Marketing website and lead intake for CrewVolt, a W-2 contract staffing company focused on energy infrastructure projects (substations, wind, solar, BESS, transmission).
- Worker URL:
https://crewvolt-web.codyboring.workers.dev - GitHub:
https://github.com/getboring/crewvolt-web - Runtime: Cloudflare Workers
- See
CLAUDE.mdfor full design system, component inventory, SSR rules, PWA setup, and operational notes.
- React Router v7 (framework mode)
- Cloudflare Workers + Wrangler
- Tailwind CSS v4 + custom CrewVolt tokens
- shadcn/ui primitives (full FormField pattern wired)
- React Hook Form + Zod (with Vitest unit tests)
- D1 (form submissions + open_roles board) + R2 (resumes)
- Resend for form notifications (when secret is set)
- Vitest for unit tests
- PWA manifest + iOS/Android meta + safe-area insets
pnpm install
pnpm devLocal app runs on http://localhost:5173.
pnpm dev— local dev server with Cloudflare runtimepnpm typecheck— wrangler types + react-router typegen + tscpnpm build— production buildpnpm test/pnpm test:watch— vitestpnpm run deploy— build + deploy to Cloudflare Workerspnpm cf-typegen— regenerateworker-configuration.d.ts
- Worker name:
crewvolt-web - D1 database:
crewvolt-db(983b5f01-d94a-45e8-870f-8c76a7c57f08) - R2 bucket:
crewvolt-uploads - Migrations:
workers/migrations/
Apply migrations:
pnpm exec wrangler d1 migrations apply crewvolt-db --remotepnpm exec wrangler secret put RESEND_API_KEYwrangler.jsonc vars:
NOTIFICATION_EMAILRESEND_FROM_EMAILPUBLIC_SITE_URLCF_WEB_ANALYTICS_TOKEN(optional)
All 3 intake forms (/staff-my-project, /join-our-network, /contact):
- Zod-validate (full shadcn FormField pattern with auto-wired aria attrs)
- Honeypot anti-spam (
websitesr-only field) — silent success on bot fill - Save to D1
form_submissions - Resume → R2 (5 MB cap) for the join form
- Resend notification when
RESEND_API_KEYis set - On success: render
<FormSuccess>card (replaces form) + toast - On validation rejection: per-field inline + summary toast
Capture the form ref synchronously before form.handleSubmit — RHF's async resolver clears event.currentTarget. See CLAUDE.md for the working pattern.
- D1-backed
<CurrentlyFilling>— readsopen_rolestable; each row has a server-formatted relative timestamp. <IndustryPulse>— rotating citation-backed industry stats (LBL/BLS/DOE).- Footer "Last revised" — UTC-formatted server-side date stamp.
- Scroll progress bar at top of viewport (
scroll(root)timeline) - Card reveal-on-scroll — fade-up tied to
view()timeline - Number count-up on metrics
- Ken-Burns on hero images (slow scale + drift)
- View Transitions API between routes (RR7
<Link viewTransition>) - All gated on
prefers-reduced-motion. SeeCLAUDE.mdMotion utilities section.
10 self-hosted photos under public/img/:
- 2 page heroes:
hero-offshore-wind.jpg,about-grid.jpg - 2 page hero bleeds:
services-hero.jpg,why-crewvolt-hero.jpg - 6 industry tiles:
industry-{substations,wind,solar,bess,transmission,grid-mod}.jpg
All Unsplash, free-commercial, sized at viewport-appropriate widths (~80–280 KB each).
workers/app.ts applies CSP, HSTS, X-Frame-Options, Referrer-Policy, Permissions-Policy on non-asset responses.
public/manifest.webmanifestwith app shortcuts- 180/192/512 + maskable PNG icons (regen instructions in
CLAUDE.md) - Full meta set in
<Layout><head>: theme-color light/dark, status-bar-style, viewport-fit=cover - Mobile CSS: tap-highlight, touch-action, overscroll-behavior, safe-area utilities
- Sticky mobile CTA + Sonner respect
env(safe-area-inset-bottom)