planmymeal/app/caydens-corner/page.tsx

109 lines
5.5 KiB
TypeScript
Raw Normal View History

2026-10-31 20:44:29 -05:00
import { ArrowRight, BookHeart } from "lucide-react";
import type { Metadata } from "next";
import Link from "next/link";
import { ViewTransition } from "react";
import { ApplianceIcon } from "@/app/components/Icons";
import { SiteHeader } from "@/app/components/SiteHeader";
import { APPLIANCES } from "@/app/lib/plan";
import { RECIPES } from "@/app/lib/recipes";
import type { Recipe } from "@/app/types";
export const metadata: Metadata = {
title: "Cayden's Corner",
description: "Homemade family recipes: tried, tested and loved.",
};
const FAMILY = RECIPES.filter((r) => r.styles.includes("caydens_corner"));
const SECTIONS: { title: string; recipes: Recipe[] }[] = [
{ title: "Appetizers & Side Dishes", recipes: FAMILY.filter((r) => r.kind === "side") },
{ title: "Main Dishes", recipes: FAMILY.filter((r) => r.kind === "main" || r.kind === "breakfast") },
{ title: "Desserts & Bakes", recipes: FAMILY.filter((r) => r.kind === "dessert") },
].map((s) => ({ ...s, recipes: [...s.recipes].sort((a, b) => a.title.localeCompare(b.title)) }));
export default function CaydensCornerPage() {
return (
<div className="min-h-dvh">
<SiteHeader active="caydens-corner" />
<main className="mx-auto max-w-7xl px-4 py-10 sm:px-6">
<section className="paper-grain rounded-2xl border border-brand-border bg-brand-950 px-6 py-10 sm:px-10">
<p className="inline-flex items-center gap-2 font-mono text-xs font-semibold tracking-widest text-brand-300 uppercase">
<BookHeart className="size-4" strokeWidth={2} aria-hidden />
Cayden&apos;s Corner · Heirloom Cookbook
</p>
<h1 className="mt-2 font-serif text-3xl font-semibold tracking-tight text-balance sm:text-5xl">
Family Recipes
</h1>
<p className="mt-3 max-w-2xl text-base leading-relaxed text-ink-muted sm:text-lg">
{FAMILY.length} homemade family favorites—passed down, tested at the dinner table, and loved. Comfort classics,
holiday staples, and plenty of scratch-baked desserts.
</p>
<div className="mt-6 flex flex-wrap items-center gap-4 border-t border-brand-border/40 pt-5 text-sm text-ink-muted">
<p>
Written originally for a table of four with leftovers; the planner scales every ingredient automatically to your household.
</p>
<Link
href="/plan"
className="trim-cap ml-auto inline-flex min-h-10 items-center gap-1.5 rounded-lg border border-line-strong bg-surface px-4 py-2 text-sm font-semibold text-ink transition-colors hover:bg-raised"
>
Plan a family-recipe week
<ArrowRight className="size-4" aria-hidden />
</Link>
</div>
</section>
{SECTIONS.map((section) => (
<section key={section.title} className="mt-12" aria-labelledby={`section-${section.title}`}>
<div className="flex items-baseline justify-between border-b border-line pb-2.5">
<h2 id={`section-${section.title}`} className="font-serif text-2xl font-semibold tracking-tight">
{section.title}
</h2>
<span className="font-mono text-xs text-ink-faint">{section.recipes.length} recipes</span>
</div>
<ul className="mt-5 grid gap-3.5 sm:grid-cols-2 lg:grid-cols-3">
{section.recipes.map((r) => {
const applianceNames =
r.requiredAppliances.map((a) => APPLIANCES.find((x) => x.id === a)?.label).join(", ") || "No cooking";
return (
<li key={r.id}>
<Link
href={`/recipes/${r.id}`}
className="group flex h-full flex-col rounded-xl border border-line bg-surface p-4 transition-colors hover:border-line-strong hover:bg-raised/60"
>
<ViewTransition name={`recipe-title-${r.id}`}>
<span className="font-serif text-lg leading-snug font-semibold text-ink group-hover:text-brand-300">
{r.title}
</span>
</ViewTransition>
<span className="mt-1.5 line-clamp-2 text-sm leading-relaxed text-ink-muted">{r.description}</span>
<span className="mt-auto flex items-center justify-between border-t border-line pt-3 mt-4 text-xs text-ink-faint">
<span className="font-mono tabular-nums">
{r.prepTime >= 120 ? `${Math.round(r.prepTime / 60)} hr` : `${r.prepTime} min`} · serves {r.servings}
</span>
<span className="inline-flex items-center gap-1.5" title={applianceNames}>
{r.requiredAppliances.length > 0 ? (
<>
{r.requiredAppliances.map((a) => (
<ApplianceIcon key={a} id={a} className="size-3.5 text-ink-muted" />
))}
<span className="sr-only">Requires {applianceNames}</span>
</>
) : (
<span>No cooking</span>
)}
</span>
</span>
</Link>
</li>
);
})}
</ul>
</section>
))}
</main>
</div>
);
}