'use client'; import { ArrowRight, Globe2, Rocket, Satellite, Search, X } from 'lucide-react'; import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { useEffect, useRef, useState } from 'react'; import { clientApi } from '@/lib/client-api'; import { cn } from '@/lib/cn'; import { routes } from '@/lib/site'; import type { SearchResult } from '@/lib/types'; import { useSearch } from './search-context'; const EXAMPLES = ['ISS', 'Starlink', '25544', '1998-067A', 'SpaceX', 'Canada', 'GPS', 'weather satellites', 'GEO']; function Icon({ type }: { type: SearchResult['entity_type'] }) { const cls = 'size-4 shrink-0 text-ink-3'; if (type === 'satellite') return ; if (type === 'launch' || type === 'launch_site') return ; return ; } /** Command-palette style global search (⌘K or /). Same-origin API; keyboard navigable; mobile full-screen sheet. */ export function SearchDialog() { const { open, setOpen } = useSearch(); const router = useRouter(); const [q, setQ] = useState(''); const [results, setResults] = useState([]); const [shortcuts, setShortcuts] = useState<{ label: string; href: string }[]>([]); const [active, setActive] = useState(0); const [loading, setLoading] = useState(false); const inputRef = useRef(null); useEffect(() => { if (open) { setTimeout(() => inputRef.current?.focus(), 20); document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; setQ(''); setResults([]); setShortcuts([]); } return () => { document.body.style.overflow = ''; }; }, [open]); useEffect(() => { if (!open) return; const term = q.trim(); if (term.length < 1) { setResults([]); setShortcuts([]); return; } const ctrl = new AbortController(); const t = setTimeout(async () => { setLoading(true); try { const res = await clientApi.search(term, 12, ctrl.signal); setResults(res.data.results); setShortcuts(res.data.shortcuts); setActive(0); } catch { /* aborted or unavailable */ } finally { setLoading(false); } }, 140); return () => { clearTimeout(t); ctrl.abort(); }; }, [q, open]); if (!open) return null; const items = [...shortcuts.map((s) => ({ href: s.href, title: s.label, subtitle: 'Filter', entity_type: 'filter' as const })), ...results]; const onKey = (e: React.KeyboardEvent) => { if (e.key === 'ArrowDown') { e.preventDefault(); setActive((a) => Math.min(a + 1, items.length - 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setActive((a) => Math.max(a - 1, 0)); } else if (e.key === 'Enter') { e.preventDefault(); const it = items[active]; if (it) { router.push(it.href); setOpen(false); } else if (q.trim()) { router.push(routes.search(q.trim())); setOpen(false); } } else if (e.key === 'Escape') { setOpen(false); } }; return (
setOpen(false)}>
e.stopPropagation()}>
setQ(e.target.value)} onKeyDown={onKey} placeholder="Search satellites, NORAD, COSPAR, operators, countries…" className="min-w-0 flex-1 bg-transparent text-[16px] text-ink placeholder:text-ink-3 focus:outline-none" autoComplete="off" spellCheck={false} aria-label="Search" />
{q.trim() === '' ? (

Try

{EXAMPLES.map((ex) => ( ))}

Press ↵ for full results · esc to close

) : items.length === 0 && !loading ? (
No results for “{q}”. setOpen(false)} className="link">Open full search
) : (
    {items.map((it, i) => (
  • setOpen(false)} onMouseEnter={() => setActive(i)} className={cn('flex min-h-[48px] items-center gap-3 px-4 py-2.5', i === active ? 'bg-plane-3' : 'hover:bg-plane-2')} > {it.entity_type === 'filter' ? : } {it.title} {it.subtitle && {it.subtitle}} {it.entity_type.replace('_', ' ')}
  • ))} {q.trim() && (
  • setOpen(false)} className="flex min-h-[44px] items-center gap-3 px-4 py-2 text-sm text-accent hover:bg-plane-2"> All results for “{q.trim()}”
  • )}
)}
); }