"use client" import { useQuery } from "@tanstack/react-query" import { FileText, Loader2, Search, Sparkles } from "lucide-react" import { type KeyboardEvent, useEffect, useMemo, useRef, useState } from "react" import { searchMemories, type SearchResult } from "@/lib/search" import { hideSpotlight, openSpotlightResult, SPOTLIGHT_SHOWN_EVENT, type SpotlightMemory, } from "@/lib/spotlight" export default function SpotlightPage() { const inputRef = useRef(null) const [query, setQuery] = useState("") const [activeIndex, setActiveIndex] = useState(0) const trimmedQuery = query.trim() const searchQuery = useQuery({ queryKey: ["spotlight-search", trimmedQuery], queryFn: () => searchMemories(trimmedQuery), enabled: trimmedQuery.length > 0, staleTime: 30 * 1000, }) const results = useMemo( () => searchQuery.data?.results.slice(0, 6) ?? [], [searchQuery.data?.results], ) useEffect(() => { let unlisten: (() => void) | undefined const focusInput = () => { setTimeout(() => inputRef.current?.focus(), 0) } focusInput() import("@tauri-apps/api/event") .then(({ listen }) => listen(SPOTLIGHT_SHOWN_EVENT, focusInput)) .then((handler) => { unlisten = handler }) .catch(() => { unlisten = undefined }) return () => { unlisten?.() } }, []) function onKeyDown(event: KeyboardEvent) { if (event.key === "Escape") { event.preventDefault() void hideSpotlight() return } if (event.key === "ArrowDown") { event.preventDefault() setActiveIndex((index) => Math.min(index + 1, results.length - 1)) return } if (event.key === "ArrowUp") { event.preventDefault() setActiveIndex((index) => Math.max(index - 1, 0)) return } if (event.key === "Enter" && results[activeIndex]) { event.preventDefault() void openResult(results[activeIndex]) } } async function openResult(result: SearchResult) { await openSpotlightResult(searchResultToSpotlightMemory(result)) setQuery("") } return (
{ setQuery(event.target.value) setActiveIndex(0) }} onKeyDown={onKeyDown} placeholder="Ask or search your memories..." className="min-w-0 flex-1 bg-transparent text-base text-white outline-none placeholder:text-[#6F7885]" />
Spotlight
{!trimmedQuery ? (

Search by meaning, title, or question.

Press Enter to open a result in the main window.

) : null} {searchQuery.isFetching ? (
Searching...
) : null} {searchQuery.isError ? (
Search failed. Check your token and API URL.
) : null} {trimmedQuery && !searchQuery.isFetching && results.length === 0 ? (
No results found.
) : null}
    {results.map((result, index) => { const title = result.title ?? result.documentId const preview = result.summary ?? result.content ?? result.chunks.find((chunk) => chunk.isRelevant)?.content const active = index === activeIndex return (
  • ) })}
) } function searchResultToSpotlightMemory(result: SearchResult): SpotlightMemory { return { id: result.documentId, title: result.title, summary: result.summary, content: result.content ?? result.chunks.find((chunk) => chunk.isRelevant)?.content ?? null, type: result.type, createdAt: normalizeDate(result.createdAt), } } function normalizeDate(value: string | Date) { return value instanceof Date ? value.toISOString() : value }