diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md new file mode 100644 index 0000000..89d0e5c --- /dev/null +++ b/.claude/CLAUDE.md @@ -0,0 +1,58 @@ +# Cooking Site — Project Context + +## What This Is + +A personal recipe website. Content-first, no-nonsense. The name of the third homepage illustration (`recipe_sites_suck.svg`) sums up the philosophy: no popups, no life stories, just recipes. + +## Tech Stack + +- **Next.js 15** with App Router, TypeScript, Tailwind CSS +- **MDX** for recipe content with YAML frontmatter +- **ReactMarkdown + remark-gfm** for rendering recipe sections client-side +- **Static site generation (SSG)** — all pages are prerendered at build time +- **No database** — recipes are MDX files on disk + +## Project Structure + +``` +app/ # Next.js App Router pages + page.tsx # Homepage (server component) + layout.tsx # Root layout with Header/Footer + recipes/ + page.tsx # Recipe listing (server, passes data to RecipesClient) + [category]/[slug]/ + page.tsx # Recipe detail (server, passes data to RecipePageClient) + +components/ + Header.tsx / Footer.tsx # Site chrome + RecipesClient.tsx # Recipe listing with filter state + RecipeLayout.tsx # Sidebar layout (mobile drawer, desktop persistent) + RecipesSidebar.tsx # Search + category + tag filters + SelectedTags.tsx # Active tag chips + TagSelector.tsx # Tag dropdown picker + RecipeCard.tsx # Recipe grid card + RecipePageClient.tsx # Recipe detail page wrapper + RecipeTabs.tsx # Section tabs (Photos/Ingredients/Instructions/Notes/References) + +lib/ + recipes.ts # Recipe file loader with in-memory cache; reads from public/recipes/ + parseRecipe.ts # Splits MDX content into ## sections for tabs + +public/ + assets/ # Site-level images (homepage SVGs) + authors.json # Author metadata + recipes/ # ALL recipe content lives here (MDX + images together) + [category]/ + recipe-slug/ + recipe-slug.mdx + assets/ + hero.jpg + ... +``` + +## Design Principles + +- **Content first**: recipe pages are minimal — no sidebar, just the recipe +- **Server components by default**: only add `'use client'` when interactivity is needed +- **No taxonomy file**: categories and tags are derived directly from frontmatter across all recipes — no external registry to keep in sync +- **Single content location**: MDX and images are colocated in `public/recipes/` so they can be served directly without a copy step diff --git a/.claude/rules/architecture.md b/.claude/rules/architecture.md new file mode 100644 index 0000000..14d6c95 --- /dev/null +++ b/.claude/rules/architecture.md @@ -0,0 +1,16 @@ +# Component Architecture + +## State and Data Flow + +- **RecipeLayout** owns sidebar open/close state; passes `handleFilterChange` (memoised with `useCallback`) down to RecipesSidebar +- **RecipesSidebar** owns filter state (search, category, selectedTags) and reports changes via `useEffect` → `onFilterChange` +- **RecipesClient** owns filtered recipe list (memoised with `useMemo`) and passes `setFilters` as `onFilterChange` +- **RecipeTabs** renders content with ReactMarkdown; custom `img` component rewrites `./` paths to `/recipes/[folderPath]/` + +## Known Constraints + +- `folderPath` in recipe metadata uses backslashes on Windows (from `path.join`) — always `.replace(/\\/g, '/')` before using in URLs +- Images in recipe MDX are wrapped in `

` by ReactMarkdown — use `` not `

` to avoid invalid HTML nesting (`

` is invalid) +- `lib/recipes.ts` uses Node.js `fs` — server-side only; never import in client components +- Build warning about `` vs `` in RecipeTabs is intentional — markdown images can't use Next.js Image component +- Never add redundant ARIA roles on semantic elements (`
`, `