"use client"; import Link from "next/link"; import { usePathname, useRouter } from "next/navigation"; import { Disc3, Search, FolderHeart, Tag, Settings, Trash2, Users, Building2, Film, Database, ChevronDown, Layers } from "lucide-react"; import { BRAND } from "@/lib/brand"; import { useSettingsPanel } from "@/components/settings/SettingsPanelProvider"; import { useTrashPanel } from "@/components/trash/TrashPanelProvider"; import { QueueIndicator } from "@/components/queue/QueueIndicator"; import { cn } from "@/lib/utils"; import { useEffect, useRef, useState } from "react"; export function TopNav() { const pathname = usePathname(); const router = useRouter(); const { open: settingsOpen, toggle: toggleSettings } = useSettingsPanel(); const { open: trashOpen, toggle: toggleTrash } = useTrashPanel(); const [q, setQ] = useState(""); const inputRef = useRef(null); useEffect(() => { const onKey = (e: KeyboardEvent) => { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); inputRef.current?.focus(); } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, []); const submit = (e: React.FormEvent) => { e.preventDefault(); const trimmed = q.trim(); if (!trimmed) return; router.push(`/search?q=${encodeURIComponent(trimmed)}`); }; const link = (href: string, label: string, Icon: React.ComponentType<{ className?: string }>) => { const active = pathname === href || (href !== "/" && pathname.startsWith(href)); return ( {label} ); }; return (
{BRAND.name}
setQ(e.target.value)} placeholder="Search Code, Title, Notes…" className="w-full glass rounded-xl pl-10 pr-16 py-2 text-sm outline-none focus:border-[var(--color-cyan)] focus:shadow-[var(--shadow-glow-cyan)] transition-all placeholder:text-[var(--color-fg-muted)]" /> ⌘K
); } const DATABASE_ITEMS: Array<{ href: string; label: string; Icon: React.ComponentType<{ className?: string }> }> = [ { href: "/studios", label: "Studios", Icon: Building2 }, { href: "/series", label: "Series", Icon: Film }, ]; function DatabaseMenu({ pathname }: { pathname: string }) { const [open, setOpen] = useState(false); const ref = useRef(null); // Small close-delay so moving the cursor from the trigger button into // the dropdown (across the 1 px positioning offset) doesn't dismiss. const closeTimer = useRef | null>(null); const active = DATABASE_ITEMS.some((it) => pathname === it.href || pathname.startsWith(it.href + "/")); useEffect(() => { if (!open) return; const onClick = (e: MouseEvent) => { if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false); }; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") setOpen(false); }; window.addEventListener("mousedown", onClick); window.addEventListener("keydown", onKey); return () => { window.removeEventListener("mousedown", onClick); window.removeEventListener("keydown", onKey); }; }, [open]); useEffect(() => { return () => { if (closeTimer.current) clearTimeout(closeTimer.current); }; }, []); const cancelClose = () => { if (closeTimer.current) { clearTimeout(closeTimer.current); closeTimer.current = null; } }; const scheduleClose = () => { cancelClose(); closeTimer.current = setTimeout(() => setOpen(false), 120); }; return (
{ cancelClose(); setOpen(true); }} onMouseLeave={scheduleClose} > {open && (
{DATABASE_ITEMS.map(({ href, label, Icon }) => { const itemActive = pathname === href || pathname.startsWith(href + "/"); return ( setOpen(false)} role="menuitem" className={cn( "flex items-center gap-2 px-3 py-1.5 text-sm transition-colors", itemActive ? "text-[var(--color-cyan)] bg-[var(--color-glass)]" : "text-[var(--color-fg-dim)] hover:text-[var(--color-fg)] hover:bg-[var(--color-glass)]", )} > {label} ); })}
)}
); }