# SHIFT Hydrogen — Site Reference ## Stack - **Astro 4** (static output) + **Tailwind CSS 3** - **Cloudflare Pages** — auto-deploys on push to `main` - **Cloudflare Pages Functions** — serverless endpoint at `/api/contact` - **Web3Forms** — handles email delivery, no backend needed - **Cloudflare Turnstile** — bot protection on the contact form ## Commands ``` pnpm dev # local dev server (Pages Functions don't run here) pnpm build # production build → dist/ pnpm preview # preview built output (no Pages Functions) ``` To test the contact form locally you need `wrangler pages dev`. ## Project Structure ``` src/ content/ ← all editable copy lives here pages/ ← home.md, about.md, apply.md, contact.md clusters/ ← one .md per team cluster team/ ← one .md per team member config.ts ← content collection schemas layouts/ Layout.astro ← shared HTML shell, navbar, footer, fonts components/ Navbar.astro Footer.astro TeamCard.astro ClusterCard.astro pages/ ← route files (read content, render HTML) index.astro about.astro apply.astro contact.astro team.astro functions/ api/ contact.js ← Pages Function: verifies Turnstile, forwards to Web3Forms public/ images/ logo.png hero-bg.jpg / about-bg.jpg / apply-bg.jpg team/ ← firstname-lastname.jpg for each member ``` ## Editing Page Copy ### Home (`src/content/pages/home.md`) All sections are YAML frontmatter — hero headline, mission body, vision body, CTA section. Edit the values directly. No markdown body used on this page. ### About & Apply (`src/content/pages/about.md`, `apply.md`) Standard frontmatter (`title`, `description`) + markdown body. The body content is currently hardcoded in the `.astro` files — to change it, edit `src/pages/about.astro` and `src/pages/apply.astro` directly. ### Contact (`src/content/pages/contact.md`) Only the intro blurb is here. The form, social links, and success/error messages live in `src/pages/contact.astro`. ### Cluster descriptions (`src/content/clusters/`) Frontmatter: `title`, `order`, `tagline`. Body: free markdown, rendered on the Apply page. ## Team Management Add/remove a member by creating or deleting their file in `src/content/team/`. **Filename:** `firstname-lastname.md` **Frontmatter:** ```yaml --- name: Full Name role: Their Role cluster: Business & Economics # must match a cluster title exactly photo: firstname-lastname.jpg # must exist in public/images/team/ order: 1 # sort order within their cluster --- ``` Drop their photo into `public/images/team/` at the same time. ## Integrations & Keys ### Web3Forms - Access key: `539526ba-d115-4324-8401-62b2753cfe4b` - Set in `functions/api/contact.js` — never needs to be in client HTML - Dashboard: https://web3forms.com — 250 submissions/month on free tier ### Cloudflare Turnstile - Site key (public): `0x4AAAAAADhhdYPafjRTZbrV` — in `src/pages/contact.astro` - Secret key (server): `0x4AAAAAADhhdSp6p_510Kj_40PSKs4lXNY` — in `functions/api/contact.js` - If you want to move the secret out of source, add `TURNSTILE_SECRET` as an environment variable in the Cloudflare Pages dashboard — the function reads it automatically via `context.env.TURNSTILE_SECRET`. ### Contact Form Flow 1. User completes Turnstile challenge in the browser 2. Form POSTs to `/api/contact` (Pages Function) 3. Function verifies token with Cloudflare, then forwards to Web3Forms 4. Web3Forms sends email to `info@shifthydrogen.nl` 5. 10-minute cooldown on the submit button after a successful send (stored in `localStorage`) ## Design Tokens Defined inline in component `