import { useState, useEffect, useRef, useCallback, useMemo } from "react"; import { useNavigate } from "@tanstack/react-router"; import { useQuery } from "@tanstack/react-query"; import { Search, FileText, Loader2 } from "lucide-react"; import { searchQueryOptions } from "@/client/lib/queries/search"; import { useCurrentWorkspace } from "@/client/components/workspace/use-workspace-view"; import type { SearchResult } from "@/shared/types"; import { DEFAULT_PAGE_TITLE } from "@/shared/constants"; export function SearchDialog({ open, onClose }: { open: boolean; onClose: () => void }) { if (!open) return null; return ; } function SearchDialogContent({ onClose }: { onClose: () => void }) { const navigate = useNavigate(); const workspace = useCurrentWorkspace(); const [query, setQuery] = useState(""); const [debouncedQuery, setDebouncedQuery] = useState(""); const [selectedIndex, setSelectedIndex] = useState(0); const inputRef = useRef(null); const debounceRef = useRef>(null); const searchQuery = useQuery(searchQueryOptions(workspace?.id ?? null, debouncedQuery)); const results: SearchResult[] = useMemo(() => searchQuery.data ?? [], [searchQuery.data]); const isSearching = searchQuery.isFetching; const hasError = searchQuery.isError; useEffect(() => { requestAnimationFrame(() => inputRef.current?.focus()); return () => { if (!debounceRef.current) return; clearTimeout(debounceRef.current); }; }, []); const handleInput = useCallback((value: string) => { setQuery(value); setSelectedIndex(0); if (debounceRef.current) clearTimeout(debounceRef.current); debounceRef.current = setTimeout(() => setDebouncedQuery(value), 200); }, []); const selectResult = useCallback( (result: SearchResult) => { if (!workspace) return; onClose(); navigate({ to: "/$workspaceSlug/$pageId", params: { workspaceSlug: workspace.slug, pageId: result.page_id }, }); }, [workspace, navigate, onClose], ); const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === "ArrowDown") { e.preventDefault(); setSelectedIndex((i) => Math.min(i + 1, results.length - 1)); } else if (e.key === "ArrowUp") { e.preventDefault(); setSelectedIndex((i) => Math.max(i - 1, 0)); } else if (e.key === "Enter" && results[selectedIndex]) { e.preventDefault(); selectResult(results[selectedIndex]); } else if (e.key === "Escape") { onClose(); } }, [results, selectedIndex, selectResult, onClose], ); return (
); }