cooking/.claude/CLAUDE.md
Olomana (multica agent) b7c526a784 PWS-13: Make recipe markdown fully control the tabs
Every top-level :::name block is now a tab, shown in file order, so
authors can add custom tabs and reorder them in the markdown. Titles
come from the name or a :::name[Title] label.

The recipe card is an ordinary :::card tab. Its body lists what it
prints (::ingredients, or a block written just for the card), replacing
::card, the fallback to full sections, and its fixed tab position.

All recipes are migrated, with pages and card images unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: multica-agent <github@multica.ai>
2026-11-07 00:34:10 -08:00

4.0 KiB

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
  • Markdown (.md) for recipe content with YAML frontmatter; every tab is a markdown directive (:::ingredients, :::card)
  • unified + remark-gfm + remark-directive to parse content server-side; mdast-util-to-hast + hast-util-to-jsx-runtime to render React
  • satori + sharp to generate printable recipe card PNGs at build time
  • Static site generation (SSG) — all pages are prerendered at build time
  • No database — recipes are markdown 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, renders the markdown's tabs via RecipePageLayout)
      assets/[...file]/
        route.ts              # Serves recipe images from recipes/ (prerendered at build)
      card/[image]/
        route.ts              # Recipe card PNGs (card.png, or front.png + back.png)

components/
  Header.tsx / Footer.tsx     # Site chrome
  RecipesClient.tsx           # Recipe listing with filter state
  RecipeLayout.tsx            # Recipe listing layout: filter button, Sidebar + results
  Sidebar.tsx                 # Responsive sidebar shell (mobile drawer, desktop sticky column)
  RecipesSidebar.tsx          # Search + category/tag facet lists with result counts
  FacetGroup.tsx              # Collapsible sidebar facet section
  ActiveFilters.tsx           # Removable chips for active filters (above results)
  RecipeGridCard.tsx          # Recipe grid card for listing page
  RecipeTabs.tsx              # Tabbed recipe sections (client)
  RecipeMarkdown.tsx          # Renders a parsed markdown tree to React (server)
  markdown-styles.ts          # Shared body typography classes (recipe tabs, About page)
  RecipeCardPanel.tsx         # Recipe Card tab: card image previews (server)
  RecipeCardImage.tsx         # Card preview that enlarges to full screen on click (client)
  RecipePageLayout.tsx        # Recipe detail page layout (server component)

lib/
  recipes.ts                  # Recipe file loader with in-memory cache; reads from recipes/
  recipe-content.ts           # Parses a recipe body into intro / tabs / outro; validates directives
  recipe-content.test.ts      # Format tests; also parses every real recipe (npm test)
  recipe-card.tsx             # Card layout (measured with satori) and PNG rendering
  recipe-urls.ts              # Client-safe helper that maps ./assets/ paths to served URLs

recipes/                      # ALL recipe content lives here (markdown + images together)
  [category]/
    recipe-slug/
      recipe-slug.md
      assets/
        hero.jpg
        ...

public/
  assets/                     # Site-level images (homepage SVGs)
  authors.json                # Author metadata

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
  • The markdown is the recipe: tabs, their titles and order, and what the card prints are all written in the .md file. The renderer only turns what's written into the page; never add hardcoded tab names, ordering, or fallbacks
  • No taxonomy file: categories and tags are derived directly from frontmatter across all recipes — no external registry to keep in sync
  • Content is top level: markdown and images are colocated in recipes/; images are served by a statically prerendered route handler, so there's no copy step. public/ is only for site branding and data