"use client"; import { useRouter } from "next/navigation"; import { useEffect, useMemo, useState, useRef } from "react"; import { ArrowUpIcon, ArrowDownIcon, CornerDownLeftIcon, FileTextIcon } from "lucide-react"; import Anchor from "./anchor"; import { advanceSearch, cn } from "@/lib/utils"; import { ScrollArea } from "@/components/ui/scroll-area"; import { page_routes } from "@/lib/routes-config"; import { DialogContent, DialogHeader, DialogFooter, DialogClose, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; type ContextInfo = { icon: string; description: string; title?: string; }; type SearchResult = { title: string; href: string; noLink?: boolean; items?: undefined; score?: number; context?: ContextInfo; }; const paddingMap = { 1: "pl-2", 2: "pl-4", 3: "pl-10", } as const; interface SearchModalProps { isOpen: boolean; setIsOpen: (open: boolean) => void; } export function SearchModal({ isOpen, setIsOpen }: SearchModalProps) { const router = useRouter(); const [searchedInput, setSearchedInput] = useState(""); const [selectedIndex, setSelectedIndex] = useState(0); const itemRefs = useRef<(HTMLDivElement | null)[]>([]); useEffect(() => { if (!isOpen) { setSearchedInput(""); } }, [isOpen]); const filteredResults = useMemo(() => { const trimmedInput = searchedInput.trim(); if (trimmedInput.length < 3) { return page_routes .filter((route) => !route.href.endsWith('/')) .slice(0, 6) .map((route: { title: string; href: string; noLink?: boolean; context?: ContextInfo }) => ({ title: route.title, href: route.href, noLink: route.noLink, context: route.context, })); } return advanceSearch(trimmedInput) as unknown as SearchResult[]; }, [searchedInput]); useEffect(() => { setSelectedIndex(0); }, [filteredResults]); useEffect(() => { const handleNavigation = (event: KeyboardEvent) => { if (!isOpen || filteredResults.length === 0) return; if (event.key === "ArrowDown") { event.preventDefault(); setSelectedIndex((prev) => (prev + 1) % filteredResults.length); } else if (event.key === "ArrowUp") { event.preventDefault(); setSelectedIndex((prev) => (prev - 1 + filteredResults.length) % filteredResults.length); } else if (event.key === "Enter") { event.preventDefault(); const selectedItem = filteredResults[selectedIndex]; if (selectedItem) { router.push(`/docs${selectedItem.href}`); setIsOpen(false); } } }; window.addEventListener("keydown", handleNavigation); return () => window.removeEventListener("keydown", handleNavigation); }, [isOpen, filteredResults, selectedIndex, router, setIsOpen]); useEffect(() => { if (itemRefs.current[selectedIndex]) { itemRefs.current[selectedIndex]?.scrollIntoView({ behavior: "smooth", block: "nearest", }); } }, [selectedIndex]); return ( Search Documentation Search through the documentation setSearchedInput(e.target.value)} placeholder="Type something to search..." autoFocus className="h-14 px-6 bg-transparent border-b text-[14px] outline-none w-full" aria-label="Search documentation" /> {filteredResults.length == 0 && searchedInput && (

No results found for{" "} {`"${searchedInput}"`}

)}
{filteredResults.map((item, index) => { const level = (item.href.split("/").slice(1).length - 1) as keyof typeof paddingMap; const paddingClass = paddingMap[level] || 'pl-2'; const isActive = index === selectedIndex; return ( { itemRefs.current[index] = el as HTMLDivElement | null; }} className={cn( "dark:hover:bg-accent/15 hover:bg-accent/10 w-full px-3 rounded-sm text-sm flex items-center gap-2.5", isActive && "bg-primary/20 dark:bg-primary/30", paddingClass )} href={`/docs${item.href}`} tabIndex={-1} >
1 && "border-l pl-4" )} >
{item.title}
{isActive && (
Return
)}
); })}

to navigate

to select

esc

to close

); }