/* Results — aligned to actual GET /search response shape. * No filters, no facets, no invented backend data. * Sidebar collapses to a
disclosure on narrow screens. */ const ModePill = ({ mode }) => ( {mode} ); const ScoreCell = ({ label, value, rank, dimmed }) => (
{label} {dimmed ? "—" : ( <> {value} {rank != null && {` · #${rank}`}} )}
); const ResultRow = ({ r, idx, showScores, onOpenCase }) => { const charLen = r.char_end - r.char_start; const display = window.shortCaseName(r.case_name); const open = (e) => { if (!onOpenCase) return; if (e) e.preventDefault(); onOpenCase(r.case_id); }; return (
  • { // Don't hijack clicks on links/buttons inside the row. if (e.target.closest("a, button")) return; open(); }} >
    {String(idx + 1).padStart(2, "0")}
    {/* Case heading */}

    {onOpenCase ? ( {display} ) : ( {display} )}

    {/* Sub-line: docket + chunk locator (already wraps) */}
    No. {r.docket_number} · case {r.case_id} · opinion {r.opinion_id} · chunk {r.chunk_index} · chars {r.char_start.toLocaleString()}–{r.char_end.toLocaleString()}
    {/* Snippet / preview */}

    {/* Traceability strip — wraps on narrow screens */} {showScores && (
    chunk_id {r.chunk_id}
    )}
  • ); }; /* The reusable info content — used both in desktop sidebar and mobile disclosure. */ const InfoContent = ({ mode, query, count }) => ( <>
    This query
    {`GET /search
      query = ${JSON.stringify(query)}
      mode  = ${mode}
      limit = 10
    
    → ${count} result${count === 1 ? "" : "s"}`}
          
    Retrieval
    Keyword
    SQLite FTS5, bm25 ranking
    Semantic
    FAISS, cosine similarity
    Hybrid
    Reciprocal rank fusion (k=60)
    Match signal
    ); const Results = ({ initialQuery, initialMode, onSearch, onOpenCase, showScores = true }) => { const [query, setQuery] = React.useState(initialQuery); const [mode, setMode] = React.useState(initialMode); const [data, setData] = React.useState(null); const [loading, setLoading] = React.useState(true); const [error, setError] = React.useState(null); React.useEffect(() => { setQuery(initialQuery); setMode(initialMode); }, [initialQuery, initialMode]); React.useEffect(() => { let cancelled = false; setLoading(true); setError(null); window.searchApi.search({ query: initialQuery, mode: initialMode, limit: 10 }) .then((res) => { if (!cancelled) { setData(res); setLoading(false); } }) .catch((err) => { if (!cancelled) { setError(err); setLoading(false); } }); return () => { cancelled = true; }; }, [initialQuery, initialMode]); const submit = (q, m) => { const finalQ = (q ?? query).trim(); if (!finalQ) return; onSearch(finalQ, m ?? mode); }; const count = data?.count ?? 0; return (
    { setMode(m); submit(query, m); }} onSubmit={() => submit()} busy={loading} />
    {/* Mobile-only disclosure of the same info that's in the sidebar on desktop */}
    Query · retrieval · legend
    {loading ? "searching…" : error ? "error" : `${count} result${count === 1 ? "" : "s"}`}

    Results for "{initialQuery}"

    limit=10
    {loading && (
    retrieving
    )} {error && !loading && (
    {error.status ? `Error ${error.status}` : "Error"}
    {error.message}
    )} {!loading && !error && data && data.results.length > 0 && (
      {data.results.map((r, i) => )}
    )} {!loading && !error && data && data.results.length === 0 && (

    No results.

    Try a different query or switch retrieval mode.

    )}
    ); }; window.Results = Results;