- Adopt BoardUI (Pro init): theme tokens, Inter, .dark mode, Button, SegmentedControl, Meter, Skeleton and ThemeToggle; remap the app's color aliases onto BoardUI tokens and swap lucide for Remix icons - Retint BoardUI's neutral ramp to cool slate with a salmon accent; drop the dotted background; raise muted text contrast - Simplify the landing page and remove the overlap explorer - Planner: explicit "I have this" toggle on grocery lines, pantry panel above the menu with the staples list spelled out, sticky aisle header fix, and a "Download PDF" plan export (jsPDF, lazy-loaded) - Recipes: replace the family cabbage soup with Cade's Cabbage Soup (adds Bone-In Ham Steak to the catalog); remove Ham, Bean & Cabbage Soup - Remove unused BoardUI components, dependencies and exports Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
4.2 KiB
TypeScript
114 lines
4.2 KiB
TypeScript
import { RiHeart3Line as BookHeart, RiBookOpenLine as BookOpen, RiCalendarLine as CalendarRange, RiRestaurantLine as UtensilsCrossed } from "@remixicon/react";
|
|
import Link from "next/link";
|
|
import type { ReactNode } from "react";
|
|
import { buttonStyles } from "@/components/base/buttons/button";
|
|
import { ThemeToggle } from "@/components/application/theme/theme-toggle";
|
|
import { cx } from "@/utils/cx";
|
|
|
|
type ActiveNav = "home" | "recipes" | "caydens-corner" | "plan";
|
|
|
|
export function Logo({ small = false, subtitle }: { small?: boolean; subtitle?: ReactNode }) {
|
|
return (
|
|
<div className="flex shrink-0 items-center gap-2.5">
|
|
<Link
|
|
href="/"
|
|
aria-label="Plan my Meals home"
|
|
className={`grid shrink-0 place-items-center rounded-lg border border-brand-border bg-brand-950 text-brand-300 transition-colors hover:bg-selected ${
|
|
small ? "size-7" : "size-9"
|
|
}`}
|
|
>
|
|
<UtensilsCrossed className={small ? "size-3.5" : "size-4"} strokeWidth={2} aria-hidden />
|
|
</Link>
|
|
<div className="min-w-0">
|
|
<Link
|
|
href="/"
|
|
className={`block font-serif leading-tight font-semibold tracking-tight whitespace-nowrap hover:text-brand-300 ${
|
|
small ? "text-sm text-ink-muted" : "text-lg text-ink"
|
|
}`}
|
|
>
|
|
Plan my Meals
|
|
</Link>
|
|
<div className="flex items-center gap-1.5 text-xs leading-tight text-ink-faint whitespace-nowrap">
|
|
<span>
|
|
by{" "}
|
|
<a
|
|
href="https://caydens.dev"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="font-medium text-ink-muted transition-colors hover:text-brand-300 hover:underline"
|
|
>
|
|
Cayden Codes
|
|
</a>
|
|
</span>
|
|
{subtitle && (
|
|
<>
|
|
<span aria-hidden>·</span>
|
|
{subtitle}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface SiteHeaderProps {
|
|
active?: ActiveNav;
|
|
subtitle?: ReactNode;
|
|
rightSlot?: ReactNode;
|
|
}
|
|
|
|
export function SiteHeader({ active = "home", subtitle, rightSlot }: SiteHeaderProps) {
|
|
const linkClass = (isCurrent: boolean) =>
|
|
cx(
|
|
"inline-flex h-9 items-center gap-1.5 rounded-2lg px-2.5 text-body-medium transition-colors duration-150 sm:px-3",
|
|
isCurrent
|
|
? "bg-background-secondary-default text-text-primary"
|
|
: "text-text-secondary hover:bg-background-secondary-hover hover:text-text-primary",
|
|
);
|
|
|
|
return (
|
|
<header className="sticky top-0 z-30 border-b border-separator-border bg-background-primary-default/90 backdrop-blur-md">
|
|
<div className="mx-auto flex max-w-7xl items-center gap-2 px-4 py-2.5 sm:gap-4 sm:px-6">
|
|
<Logo subtitle={subtitle} />
|
|
|
|
<nav aria-label="Primary" className="ml-auto flex items-center gap-1 whitespace-nowrap">
|
|
<Link
|
|
href="/recipes"
|
|
aria-current={active === "recipes" ? "page" : undefined}
|
|
className={linkClass(active === "recipes")}
|
|
title="Recipe library"
|
|
>
|
|
<BookOpen className="size-4 shrink-0" strokeWidth={1.75} aria-hidden />
|
|
<span className="sr-only md:not-sr-only">Recipes</span>
|
|
</Link>
|
|
|
|
<Link
|
|
href="/caydens-corner"
|
|
aria-current={active === "caydens-corner" ? "page" : undefined}
|
|
className={linkClass(active === "caydens-corner")}
|
|
title="Cayden's Corner"
|
|
>
|
|
<BookHeart className="size-4 shrink-0" strokeWidth={1.75} aria-hidden />
|
|
<span className="sr-only md:not-sr-only">Cayden's Corner</span>
|
|
</Link>
|
|
|
|
{active !== "plan" && (
|
|
<Link
|
|
href="/plan"
|
|
className={cx(buttonStyles.base, buttonStyles.size.medium, buttonStyles.variant.primary, "ml-1 gap-1.5 px-3")}
|
|
>
|
|
<CalendarRange className={buttonStyles.icon.medium} aria-hidden />
|
|
<span className="sm:hidden">Planner</span>
|
|
<span className="hidden sm:inline">Open planner</span>
|
|
</Link>
|
|
)}
|
|
</nav>
|
|
|
|
{rightSlot}
|
|
|
|
<ThemeToggle appearance="segmented" size="small" />
|
|
</div>
|
|
</header>
|
|
);
|
|
}
|