import { ArrowLeft, BookHeart } from "lucide-react"; import type { Metadata } from "next"; import Link from "next/link"; import { notFound } from "next/navigation"; import { Suspense, ViewTransition } from "react"; import { AddToPlanControl } from "@/app/components/AddToPlanControl"; import { RecipeMeta } from "@/app/components/RecipeDetail"; import { RecipeServings } from "@/app/components/RecipeServings"; import { SiteHeader } from "@/app/components/SiteHeader"; import { PANTRY_STAPLE_IDS } from "@/app/lib/catalog"; import { buildGroceryList } from "@/app/lib/grocery"; import { CUISINES } from "@/app/lib/plan"; import { RECIPES, RECIPES_BY_ID } from "@/app/lib/recipes"; import { formatUsd } from "@/app/lib/units"; export function generateStaticParams() { return RECIPES.map((r) => ({ id: r.id })); } export async function generateMetadata({ params, }: { params: Promise<{ id: string }>; }): Promise { const recipe = RECIPES_BY_ID.get((await params).id); return recipe ? { title: recipe.title, description: recipe.description, } : {}; } /** * URL-independent App Shell renders instantly; everything reading `params` * lives inside so Next 16 Partial Prefetching never blocks navigation. */ export default function RecipePage({ params, }: { params: Promise<{ id: string }>; }) { return (
}>
); } async function RecipeContent({ params }: { params: Promise<{ id: string }> }) { const recipe = RECIPES_BY_ID.get((await params).id); if (!recipe) notFound(); const cost = buildGroceryList([recipe.id], { householdSize: recipe.servings, onHandItems: PANTRY_STAPLE_IDS, }); const cuisineLabel = CUISINES.find((c) => c.id === recipe.cuisine)?.label; const isFamily = recipe.styles.includes("caydens_corner"); const related = RECIPES.filter( (r) => r.id !== recipe.id && r.kind === recipe.kind && (isFamily ? r.styles.includes("caydens_corner") : r.cuisine === recipe.cuisine && !r.styles.includes("caydens_corner")), ).slice(0, 4); return ( <> {isFamily ? "Cayden's Corner" : "All recipes"} {isFamily && (

Heirloom Family Recipe

)}

{recipe.title}

{recipe.description}

{/* Cost ledger + Add to Plan action bar */}
Cost eaten / serving
{formatUsd(cost.usedTotal / recipe.servings)}
Full packages new
{formatUsd(cost.checkoutTotal)}
{related.length > 0 && (

More {isFamily ? "from Cayden's Corner" : cuisineLabel}

    {related.map((r) => (
  • {r.title} {r.description}
  • ))}
)} ); } function RecipeSkeleton() { return (
); }