Personal editorial portfolio for John Herrera, combining kitchen craft and digital product work in one route-based experience.
- Next.js 16.2.1 (App Router, React Compiler)
- React 19
- TypeScript
- Tailwind CSS 4
- Lenis (smooth-scroll behavior)
npm install
npm run dev
npm run lint
npm run build
npm startnpm run dev and npm run build currently run Next with --webpack. next.config.ts still defines a Turbopack root for compatibility with future build/dev changes.
npm install
npm run devOpen http://localhost:3000.
/Home hero and editorial entry point/worksHospitality and digital work/aboutProfile, trajectory, and working position/contactContact CTA and social links
All route pages live under src/app/(site)/ and export dynamic = 'force-static'.
src/
├── app/ # Root layout, route group, metadata, OG/Twitter image
├── design/
│ ├── primitives/ # SectionPrimitive, MonoToken, Eyebrow, Hero, AmbientGlow, CulinaryTerm
│ ├── tokens/ # primitives/semantic/components tokens
│ └── ui/ # composed DS blocks (SectionChrome)
├── features/
│ ├── about/
│ ├── contact/
│ ├── development/
│ ├── gastronomy/
│ ├── home/
│ └── works/
├── components/
│ ├── shared/ # TopNav, ErrorBoundary, scroll helpers, status bar
│ └── *.tsx # app-level effects: Lenis, cursor, tracking, terminal
├── lib/ # constants, hooks, utils, image assets
├── assets/ # source asset home
├── config/ # project configuration home
├── content/ # reserved content home
└── types/ # global TypeScript types
Active source of truth is under src/design/:
src/design/tokens/*for visual decisionssrc/design/primitives/*for base building blockssrc/design/ui/*for composed design-system piecessrc/lib/utils/cx.tsfor class merging
Configured globally in next.config.ts:
Content-Security-PolicyPermissions-PolicyCross-Origin-Opener-PolicyCross-Origin-Resource-PolicyStrict-Transport-SecurityX-Frame-OptionsX-Content-Type-OptionsReferrer-Policy
- Root metadata is defined in
src/app/layout.tsx. - Per-route metadata comes from
PAGE_SEOinsrc/lib/constants.ts. - The OG image is generated dynamically in
src/app/opengraph-image.tsx. src/app/twitter-image.tsxreuses the OG image output.robots.tsandsitemap.tsare generated from the site constants.
Optional env vars:
NEXT_PUBLIC_GTM_ID=GTM-XXXXXXX
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXXNEXT_PUBLIC_GTM_ID: enables Google Tag ManagerNEXT_PUBLIC_GA_ID: enables direct GA4 installation- If GA4 is already sent via GTM, leave
NEXT_PUBLIC_GA_IDempty to avoid duplicates
Tracked custom events:
cta_contact_clickmailto_clickproject_clicknav_click
GitHub Actions workflow: .github/workflows/ci.yml
Runs on every push and pull request:
npm cinpm run lintnpm run build
- Configure env vars (
NEXT_PUBLIC_GTM_ID, optionalNEXT_PUBLIC_GA_ID). - Run
npm run lintandnpm run build. - Verify events in GTM/GA debug view.
- Deploy.
See CONTEXT.md for full AI-oriented project context. Use AGENTS.md as the operational ruleset for coding agents.
See docs/phase4-audit.md for cleanup decisions applied in Phase 4.