init
This commit is contained in:
commit
c19b910c36
80 changed files with 16134 additions and 0 deletions
108
app/caydens-corner/page.tsx
Normal file
108
app/caydens-corner/page.tsx
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
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'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>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue