'use client'; import { useState, useEffect, useRef } from 'react'; import Link from 'next/link'; import { Search, X, Loader2, FileText } from 'lucide-react'; export default function SearchBox() { const [open, setOpen] = useState(false); const [q, setQ] = useState(''); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const inputRef = useRef(null); const debounceRef = useRef(null); // открытие хоткеем / useEffect(() => { const onKey = (e) => { if (e.key === '/' && !['INPUT','TEXTAREA'].includes(document.activeElement?.tagName)) { e.preventDefault(); setOpen(true); } if (e.key === 'Escape') setOpen(false); }; window.addEventListener('keydown', onKey); return () => window.removeEventListener('keydown', onKey); }, []); useEffect(() => { if (open) { setTimeout(() => inputRef.current?.focus(), 50); document.body.style.overflow = 'hidden'; } else { document.body.style.overflow = ''; setQ(''); setResults([]); } }, [open]); // дебаунсовый поиск useEffect(() => { if (!open) return; if (debounceRef.current) clearTimeout(debounceRef.current); if (q.trim().length < 2) { setResults([]); setLoading(false); return; } setLoading(true); debounceRef.current = setTimeout(async () => { try { const r = await fetch(`/api/search?q=${encodeURIComponent(q.trim())}`); const data = await r.json(); setResults(Array.isArray(data) ? data : []); } catch { setResults([]); } setLoading(false); }, 250); }, [q, open]); return ( <> {open && (
setOpen(false)} >
e.stopPropagation()} >
setQ(e.target.value)} placeholder="Найти статью…" className="flex-1 bg-transparent outline-none text-base sm:text-lg ink placeholder:text-stone-400" /> {loading && }
{q.trim().length < 2 && (
Введи минимум 2 символа. Подсказка: / открывает поиск.
)} {q.trim().length >= 2 && !loading && results.length === 0 && (
Ничего не найдено
)} {results.length > 0 && (
    {results.map(a => (
  • setOpen(false)} className="flex items-start gap-3 px-5 py-3 hover:surface-2 transition-colors" >
    {a.title}
    {a.excerpt &&
    {a.excerpt}
    } {a.tags?.length > 0 && (
    {a.tags.slice(0, 3).map(t => #{t})}
    )}
  • ))}
)}
)} ); }