"use client"; import { useState, useEffect, useCallback, Suspense } from "react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; interface DocHit { slug: string; title: string; section: string; score: number; snippet: string; } type SearchMode = "hybrid" | "keyword" | "semantic"; function SearchContent() { const searchParams = useSearchParams(); const initialQ = searchParams.get("q") ?? ""; const initialMode = (searchParams.get("mode") as SearchMode) ?? "hybrid"; const [query, setQuery] = useState(initialQ); const [mode, setMode] = useState( ["hybrid", "keyword", "semantic"].includes(initialMode) ? initialMode : "hybrid", ); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const handleSearch = useCallback(async (q: string, searchMode: SearchMode) => { if (!q.trim()) { setResults([]); return; } setLoading(true); try { const res = await fetch( `/api/search?q=${encodeURIComponent(q)}&mode=${searchMode}`, ); const data = await res.json(); setResults(data.results || []); } catch { setResults([]); } finally { setLoading(false); } }, []); useEffect(() => { if (initialQ) { handleSearch(initialQ, mode); } }, [initialQ, handleSearch, mode]); function handleChange(e: React.ChangeEvent) { const val = e.target.value; setQuery(val); handleSearch(val, mode); } function handleModeChange(newMode: SearchMode) { setMode(newMode); if (query.trim()) { handleSearch(query, newMode); } } return (

Search

{/* Mode Selector */}
Mode: {( [ { id: "hybrid", label: "Hybrid (FTS + Semantic)" }, { id: "keyword", label: "Keyword (FTS)" }, { id: "semantic", label: "Semantic (Embeddings)" }, ] as const ).map((m) => ( ))}
{loading &&

Searching...

} {!loading && results.length === 0 && query && (

No results found for "{query}".

)} {!loading && results.length > 0 && (
    {results.map((r) => (
  • {r.title}
    {r.section} · {r.slug} · Score: {r.score.toFixed(3)}
    {r.snippet && (

    )}

  • ))}
)}
); } export default function SearchPage() { return (

Search

Loading search...

} >
); }