"use client"; import { useState, useTransition } from "react"; import Link from "next/link"; import { useRouter, usePathname } from "next/navigation"; import { PlusCircle, Sparkles, Link2, Search, X, SlidersHorizontal, ArrowUpDown } from "lucide-react"; import { useTranslations } from "next-intl"; import { Button, buttonVariants } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { AiGenerateDialog } from "./ai-generate-dialog"; import { UrlImportDialog } from "./url-import-dialog"; function TagFilterInput({ value, onChange }: { value: string; onChange: (v: string) => void }) { const [local, setLocal] = useState(value); return ( setLocal(e.target.value)} onKeyDown={(e) => { if (e.key === "Enter") onChange(local); }} onBlur={() => onChange(local)} placeholder="Filter by tag…" className="w-full h-7 px-2 text-sm rounded-md border border-input bg-background focus:outline-none focus:ring-1 focus:ring-ring" /> ); } import { cn } from "@/lib/utils"; const SORT_LABELS: Record = { updated_desc: "Recently updated", updated_asc: "Oldest updated", created_desc: "Newest first", created_asc: "Oldest first", title_asc: "Title A–Z", title_desc: "Title Z–A", }; const VISIBILITY_LABELS: Record = { "": "All", private: "Private", unlisted: "Unlisted", public: "Public", }; const DIFFICULTY_LABELS: Record = { "": "Any difficulty", easy: "Easy", medium: "Medium", hard: "Hard", }; export function RecipesHeader({ count, initialQuery = "", initialSort = "updated_desc", initialVisibility = "", initialDifficulty = "", initialTag = "", }: { count: number; initialQuery?: string; initialSort?: string; initialVisibility?: string; initialDifficulty?: string; initialTag?: string; }) { const router = useRouter(); const pathname = usePathname(); const t = useTranslations("recipes"); const [aiOpen, setAiOpen] = useState(false); const [urlOpen, setUrlOpen] = useState(false); const [query, setQuery] = useState(initialQuery); const [, startTransition] = useTransition(); function pushParams(overrides: Record) { const params = new URLSearchParams(); const current = { q: query, sort: initialSort, visibility: initialVisibility, difficulty: initialDifficulty, tag: initialTag, ...overrides, }; if (current.q?.trim()) params.set("q", current.q.trim()); if (current.sort && current.sort !== "updated_desc") params.set("sort", current.sort); if (current.visibility) params.set("visibility", current.visibility); if (current.difficulty) params.set("difficulty", current.difficulty); if (current.tag?.trim()) params.set("tag", current.tag.trim()); startTransition(() => router.push(`${pathname}?${params.toString()}`)); } function handleSearch(value: string) { setQuery(value); pushParams({ q: value }); } const activeFilterCount = [initialVisibility, initialDifficulty, initialTag].filter(Boolean).length; const sortChanged = initialSort !== "updated_desc"; return ( <>

{t("title")}

{count === 0 ? t("subtitle") : t(count !== 1 ? "resultPlural" : "resultSingular", { count })}

{t("new")}
{/* Search */}
handleSearch(e.target.value)} placeholder={t("search")} className="pl-9 pr-9" /> {query && ( )}
{/* Sort */} {SORT_LABELS[initialSort] ?? "Sort"} Sort by {Object.entries(SORT_LABELS).map(([value, label]) => ( pushParams({ sort: value })} className={cn(initialSort === value && "font-medium text-primary")} > {label} ))} {/* Filters */} 0 ? "secondary" : "outline", size: "sm" }), "gap-1.5" )} > Filter {activeFilterCount > 0 && ( {activeFilterCount} )} Visibility {Object.entries(VISIBILITY_LABELS).map(([value, label]) => ( pushParams({ visibility: value })} className={cn(initialVisibility === value && "font-medium text-primary")} > {label} ))} Difficulty {Object.entries(DIFFICULTY_LABELS).map(([value, label]) => ( pushParams({ difficulty: value })} className={cn(initialDifficulty === value && "font-medium text-primary")} > {label} ))} Tag
pushParams({ tag: v })} />
{activeFilterCount > 0 && ( <> pushParams({ visibility: "", difficulty: "", tag: "" })} className="text-muted-foreground" > Clear filters )}
); }