"use client"; import { RiHeart3Line as BookHeart, RiSearchLine as Search, RiEqualizerLine as SlidersHorizontal } from "@remixicon/react"; import Link from "next/link"; import { ViewTransition, useMemo, useState, type ReactNode } from "react"; import { APPLIANCES, CUISINES, MEAL_KIND_LABELS, STYLES, toggle } from "@/app/lib/plan"; import type { Appliance, CookingStyle, Cuisine, MealKind } from "@/app/types"; import { Chip } from "./Chip"; import { ApplianceIcon, StyleIcon } from "./Icons"; export interface RecipeSummary { id: string; title: string; description: string; cuisine: Cuisine; kind: MealKind; styles: CookingStyle[]; appliances: Appliance[]; prepTime: number; ingredientText: string; } type KindFilter = "all" | MealKind; type SortOrder = "az" | "quickest"; export function RecipeBrowser({ recipes }: { recipes: RecipeSummary[] }) { const [query, setQuery] = useState(""); const [kind, setKind] = useState("all"); const [cuisines, setCuisines] = useState([]); const [styles, setStyles] = useState([]); const [kitchen, setKitchen] = useState([]); const [sort, setSort] = useState("az"); const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false); const visible = useMemo(() => { const needle = query.trim().toLowerCase(); return recipes .filter((r) => kind === "all" || r.kind === kind) .filter((r) => cuisines.length === 0 || cuisines.includes(r.cuisine)) .filter((r) => styles.length === 0 || r.styles.some((s) => styles.includes(s))) .filter((r) => kitchen.length === 0 || r.appliances.every((a) => kitchen.includes(a))) .filter((r) => !needle || r.title.toLowerCase().includes(needle) || r.ingredientText.includes(needle)) .sort((a, b) => (sort === "quickest" ? a.prepTime - b.prepTime : 0) || a.title.localeCompare(b.title)); }, [recipes, query, kind, cuisines, styles, kitchen, sort]); const activeChipCount = (kind !== "all" ? 1 : 0) + cuisines.length + styles.length + kitchen.length; const filtersActive = Boolean(query) || activeChipCount > 0; const clearAll = () => { setQuery(""); setKind("all"); setCuisines([]); setStyles([]); setKitchen([]); }; return (
{/* --- Search + Collapsible Mobile Filters / Sticky Desktop Sidebar --- */} {/* --- Results -------------------------------------------------------- */}

Showing {visible.length} of{" "} {recipes.length} recipes {filtersActive && ( )}

{visible.length === 0 ? (

No recipes match these filters. Try relaxing an appliance or cuisine filter.

) : (
    {visible.map((r) => { const applianceNames = r.appliances.map((a) => APPLIANCES.find((x) => x.id === a)?.label).join(", ") || "No cooking"; return (
  • {r.styles.includes("caydens_corner") && ( )} {CUISINES.find((c) => c.id === r.cuisine)?.label} · {MEAL_KIND_LABELS[r.kind]} {r.title} {r.description} {r.prepTime} min {r.appliances.length > 0 ? ( <> {r.appliances.map((a) => ( ))} Requires {applianceNames} ) : ( No cooking )}
  • ); })}
)}
); } function FilterGroup({ label, hint, children }: { label: string; hint?: string; children: ReactNode }) { return (
{label} {hint && · {hint}}
{children}
); }