4.2 KiB
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:
---
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— insrc/pages/contact.astro - Secret key (server):
0x4AAAAAADhhdSp6p_510Kj_40PSKs4lXNY— infunctions/api/contact.js - If you want to move the secret out of source, add
TURNSTILE_SECRETas an environment variable in the Cloudflare Pages dashboard — the function reads it automatically viacontext.env.TURNSTILE_SECRET.
Contact Form Flow
- User completes Turnstile challenge in the browser
- Form POSTs to
/api/contact(Pages Function) - Function verifies token with Cloudflare, then forwards to Web3Forms
- Web3Forms sends email to
info@shifthydrogen.nl - 10-minute cooldown on the submit button after a successful send (stored in
localStorage)
Design Tokens
Defined inline in component <style> blocks — no separate token file. Key values:
- Background:
#060B09(near-black green) - Surface:
#0C1510,#0F1C14 - Accent:
#0CC9A8(teal) - Text primary:
#F0FAF5 - Text muted:
rgba(240,250,245,0.35–0.45) - Border:
#162A20 - Font: Plus Jakarta Sans (Google Fonts) — 300/400/500/600/700/800
Deployment
Cloudflare Pages builds automatically on every push to main.
- Build command:
pnpm build - Output directory:
dist - Check build status: Cloudflare Pages dashboard → Deployments tab