"use client"; import { useState, useEffect, useRef } from "react"; import Link from "next/link"; import { useRouter } from "next/navigation"; interface Hit { slug: string; title: string; section: string; snippet?: string; score: number; } export default function CommandMenu() { const [open, setOpen] = useState(false); const [query, setQuery] = useState(""); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); const router = useRouter(); const inputRef = useRef(null); // Global shortcut ⌘K or / useEffect(() => { function handleKeyDown(e: KeyboardEvent) { if ((e.metaKey || e.ctrlKey) && e.key === "k") { e.preventDefault(); setOpen((prev) => !prev); } else if (e.key === "/" && !["INPUT", "TEXTAREA"].includes((e.target as HTMLElement)?.tagName)) { e.preventDefault(); setOpen(true); } else if (e.key === "Escape" && open) { setOpen(false); } } window.addEventListener("keydown", handleKeyDown); return () => window.removeEventListener("keydown", handleKeyDown); }, [open]); useEffect(() => { if (open) { setTimeout(() => inputRef.current?.focus(), 50); setQuery(""); setResults([]); setSelectedIndex(0); } }, [open]); // Debounced search useEffect(() => { if (!query.trim()) { setResults([]); return; } const timer = setTimeout(async () => { setLoading(true); try { const res = await fetch(`/api/search?q=${encodeURIComponent(query)}&limit=8`); const data = await res.json(); setResults(data.results || []); setSelectedIndex(0); } catch { setResults([]); } finally { setLoading(false); } }, 150); return () => clearTimeout(timer); }, [query]); function handleNavigate(slug: string) { setOpen(false); router.push(`/${slug}`); } function handleKeyNavigation(e: React.KeyboardEvent) { if (e.key === "ArrowDown") { e.preventDefault(); setSelectedIndex((prev) => (results.length > 0 ? (prev + 1) % results.length : 0)); } else if (e.key === "ArrowUp") { e.preventDefault(); setSelectedIndex((prev) => (results.length > 0 ? (prev - 1 + results.length) % results.length : 0)); } else if (e.key === "Enter" && results[selectedIndex]) { e.preventDefault(); handleNavigate(results[selectedIndex].slug); } } if (!open) { return ( ); } return (
{/* Backdrop */}
setOpen(false)} /> {/* Modal */}
{/* Search input bar */}
setQuery(e.target.value)} onKeyDown={handleKeyNavigation} placeholder="Type to search (titles, keywords, concepts)..." className="w-full bg-transparent text-[var(--text-primary)] placeholder-[var(--text-dim)] text-sm focus:outline-none" /> {loading && (
)}
{/* Results / Suggestions */}
{query.trim() === "" ? (

Search full-text, semantic embeddings, and CTF writeups.

Navigation: ↑ ↓ Select: ↵
) : results.length === 0 && !loading ? (
No documents matching "{query}"
) : (
    {results.map((hit, index) => { const isSelected = index === selectedIndex; return (
  • handleNavigate(hit.slug)} onMouseEnter={() => setSelectedIndex(index)} className={`flex items-start justify-between gap-3 px-3 py-2.5 rounded-lg cursor-pointer transition-all ${ isSelected ? "bg-[#5e6ad2]/15 border border-[#5e6ad2]/40 text-[var(--text-primary)]" : "hover:bg-[var(--bg-elevated)] text-[var(--text-secondary)] border border-transparent" }`} >
    {hit.section} {hit.title}
    {hit.snippet && (

    )}

    {hit.slug}
  • ); })}
)}
{/* Footer */}
Tip: Press Hybrid search is enabled setOpen(false)} className="hover:text-[#5e6ad2] dark:hover:text-[#7170ff] transition-colors" > Open full search page →
); }