From b95f5c1aeb3d20c426b5c86a8df1b8c9cb2fe691 Mon Sep 17 00:00:00 2001 From: Jake Runyan Date: Fri, 13 Feb 2026 11:16:44 -0800 Subject: [PATCH] update recipe rendering engine to use JSX components for recipe card and frontmatter for title bar --- .claude/CLAUDE.md | 9 +- .claude/rules/architecture.md | 6 +- .claude/rules/recipe-format.md | 47 ++++- .claude/settings.local.json | 4 +- app/recipes/[category]/[slug]/page.tsx | 50 +++++- components/RecipeCard.tsx | 161 +++++++++++------- components/RecipeGridCard.tsx | 74 ++++++++ components/RecipePageClient.tsx | 13 +- components/RecipeTabs.tsx | 156 ----------------- components/RecipesClient.tsx | 4 +- lib/parseRecipe.ts | 45 ----- package-lock.json | 91 +++++++++- package.json | 1 + public/recipes/baking/apple-pie/apple-pie.mdx | 6 +- public/recipes/cajun/gumbo/gumbo.mdx | 6 +- .../broccoli-beef-in-oyster-sauce.mdx | 6 +- .../egg-flower-soup/egg-flower-soup.mdx | 6 +- .../tangy-runyan-eggroll.mdx | 6 +- .../peach-simple-syrup/peach-simple-syrup.mdx | 6 +- .../example-recipe-1/example-recipe-1.mdx | 6 +- .../example-recipe-2/example-recipe-2.mdx | 6 +- .../indian/brown-lentils/brown-lentils.mdx | 12 +- .../indian/chana-masala/chana-masala.mdx | 6 +- .../chicken-tikka-masala.mdx | 6 +- .../indian/palak-paneer/palak-paneer.mdx | 6 +- .../chicken-parmesan/chicken-parmesan.mdx | 6 +- .../fusilli-with-vodka-basil-parmesan.mdx | 6 +- .../italian/pizza-dough/pizza-dough.mdx | 6 +- .../italian/pizza-sauce/pizza-sauce.mdx | 6 +- .../ajitsuke-tamago-ramen-egg.mdx | 6 +- .../golden-curry-beef-stew.mdx | 6 +- .../golden-curry-chicken.mdx | 6 +- .../beef-bourguignon/beef-bourguignon.mdx | 6 +- .../garlic-herb-butter-roast-turkey.mdx | 6 +- .../grilled-lemon-pepper-salmon.mdx | 6 +- .../jamaican-jerk-chicken.mdx | 6 +- .../ribs-instant-pot/ribs-instant-pot.mdx | 6 +- .../meat/turkey-gravy/turkey-gravy.mdx | 6 +- public/recipes/mexican/birria/birria.mdx | 6 +- public/recipes/mexican/elote/elote.mdx | 6 +- public/recipes/mexican/horchata/horchata.mdx | 6 +- .../mexican/mexican-rice/mexican-rice.mdx | 6 +- .../mexican/pinto-beans/pinto-beans.mdx | 14 +- .../caesar-salad-dressing.mdx | 6 +- .../cauliflower-mash/cauliflower-mash.mdx | 6 +- .../pickled-red-onions/pickled-red-onions.mdx | 6 +- .../sous-vide-mashed-potatoes.mdx | 6 +- .../chicken-noodle-soup.mdx | 6 +- public/recipes/vietnamese/pho/pho.mdx | 6 +- 49 files changed, 497 insertions(+), 394 deletions(-) create mode 100644 components/RecipeGridCard.tsx delete mode 100644 components/RecipeTabs.tsx delete mode 100644 lib/parseRecipe.ts diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 89d0e5c..bfadf30 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -8,7 +8,7 @@ A personal recipe website. Content-first, no-nonsense. The name of the third hom - **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 +- **next-mdx-remote/rsc + remark-gfm** for compiling MDX content server-side - **Static site generation (SSG)** — all pages are prerendered at build time - **No database** — recipes are MDX files on disk @@ -30,13 +30,12 @@ components/ 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) + RecipeGridCard.tsx # Recipe grid card for listing page + RecipeCard.tsx # MDX component — splits h2 children into tab sections + RecipePageClient.tsx # Recipe detail page wrapper (server component) 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) diff --git a/.claude/rules/architecture.md b/.claude/rules/architecture.md index 14d6c95..c89b878 100644 --- a/.claude/rules/architecture.md +++ b/.claude/rules/architecture.md @@ -5,12 +5,12 @@ - **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]/` +- **RecipeCard** (MDX component) receives compiled children, splits by h2 into tab sections; custom `img` component in page.tsx 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) +- Images in recipe MDX are wrapped in `

` by MDX compilation — 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 +- Build warning about `` vs `` in recipe pages is intentional — markdown images can't use Next.js Image component - Never add redundant ARIA roles on semantic elements (`
`, `