// ======================================== // FloatingFileBrowser Component // ======================================== // Floating file browser panel for Terminal Dashboard. import * as React from 'react'; import { useIntl } from 'react-intl'; import { Copy, ArrowRightToLine, Loader2, RefreshCw } from 'lucide-react'; import { cn } from '@/lib/utils'; import { FloatingPanel } from './FloatingPanel'; import { Button } from '@/components/ui/Button'; import { TreeView } from '@/components/shared/TreeView'; import { FilePreview } from '@/components/shared/FilePreview'; import { useFileExplorer, useFileContent } from '@/hooks/useFileExplorer'; import type { FileSystemNode } from '@/types/file-explorer'; export interface FloatingFileBrowserProps { isOpen: boolean; onClose: () => void; rootPath: string; onInsertPath?: (path: string) => void; initialSelectedPath?: string | null; width?: number | string; } export function FloatingFileBrowser({ isOpen, onClose, rootPath, onInsertPath, initialSelectedPath = null, width = 400, }: FloatingFileBrowserProps) { const { formatMessage } = useIntl(); const { state, rootNodes, isLoading, isFetching, error, refetch, setSelectedFile, toggleExpanded, } = useFileExplorer({ rootPath, maxDepth: 6, enabled: isOpen, }); const selectedPath = state.selectedFile; const { content, isLoading: isContentLoading, error: contentError } = useFileContent(selectedPath, { enabled: isOpen && !!selectedPath, }); const [copied, setCopied] = React.useState(false); React.useEffect(() => { if (!isOpen) return; if (initialSelectedPath) { setSelectedFile(initialSelectedPath); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [isOpen, initialSelectedPath]); const handleNodeClick = (node: FileSystemNode) => { if (node.type === 'file') { setSelectedFile(node.path); } }; const handleCopyPath = async () => { if (!selectedPath) return; try { await navigator.clipboard.writeText(selectedPath); setCopied(true); setTimeout(() => setCopied(false), 1200); } catch (err) { console.error('[FloatingFileBrowser] copy path failed:', err); } }; const handleInsert = () => { if (!selectedPath) return; onInsertPath?.(selectedPath); }; return (
{/* Toolbar */}
{selectedPath ? formatMessage({ id: 'terminalDashboard.fileBrowser.selected' }) : formatMessage({ id: 'terminalDashboard.fileBrowser.noSelection' })}
{selectedPath ?? rootPath}
{/* Body */}
{/* Tree */}
{isLoading ? (
{formatMessage({ id: 'terminalDashboard.fileBrowser.loading' })}
) : error ? (
{formatMessage({ id: 'terminalDashboard.fileBrowser.loadFailed' })}
) : ( )}
{/* Preview */}
); } export default FloatingFileBrowser;