import { useState, useEffect, useMemo } from 'react'; import { Dialog, DialogContent } from './ui/dialog'; import { Input } from './ui/input'; import { ScrollArea } from './ui/scroll-area'; import { FileNode } from './FileTree'; import { MagnifyingGlass, File, Folder } from '@phosphor-icons/react'; interface FileSearchModalProps { open: boolean; onClose: () => void; files: FileNode[]; onFileSelect: (file: FileNode) => void; } export function FileSearchModal({ open, onClose, files, onFileSelect }: FileSearchModalProps) { const [search, setSearch] = useState(''); const [selectedIndex, setSelectedIndex] = useState(0); // Flatten file tree to searchable list const flattenFiles = (nodes: FileNode[], path = ''): Array<{ file: FileNode; path: string }> => { let result: Array<{ file: FileNode; path: string }> = []; for (const node of nodes) { const currentPath = path ? `${path}/${node.name}` : node.name; if (node.type === 'file') { result.push({ file: node, path: currentPath }); } if (node.children) { result = [...result, ...flattenFiles(node.children, currentPath)]; } } return result; }; const allFiles = useMemo(() => flattenFiles(files), [files]); // Filter files based on search const filteredFiles = useMemo(() => { if (!search) return allFiles; const searchLower = search.toLowerCase(); return allFiles.filter(({ file, path }) => path.toLowerCase().includes(searchLower) || file.name.toLowerCase().includes(searchLower) ); }, [allFiles, search]); // Reset when opened/closed useEffect(() => { if (open) { setSearch(''); setSelectedIndex(0); } }, [open]); // Keyboard navigation useEffect(() => { if (!open) return; const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'ArrowDown') { e.preventDefault(); setSelectedIndex((prev) => Math.min(prev + 1, filteredFiles.length - 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setSelectedIndex((prev) => Math.max(prev - 1, 0)); } else if (e.key === 'Enter') { e.preventDefault(); if (filteredFiles[selectedIndex]) { handleSelect(filteredFiles[selectedIndex].file); } } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, [open, filteredFiles, selectedIndex]); const handleSelect = (file: FileNode) => { onFileSelect(file); onClose(); }; return (
{ setSearch(e.target.value); setSelectedIndex(0); }} placeholder="Search files... (type to filter)" className="border-0 focus-visible:ring-0 focus-visible:ring-offset-0 text-base" autoFocus />
{filteredFiles.length === 0 ? (

No files found

{search && (

Try a different search term

)}
) : (
{filteredFiles.map(({ file, path }, index) => ( ))}
)}
↑↓ Navigate Select Esc Close
{filteredFiles.length} files
); }