@huyooo/file-explorer-frontend-react 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/index.css +1740 -0
  2. package/dist/index.css.map +1 -0
  3. package/dist/index.d.ts +562 -0
  4. package/dist/index.js +3453 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/style.css +3 -0
  7. package/package.json +58 -0
  8. package/src/components/Breadcrumb.css +61 -0
  9. package/src/components/Breadcrumb.tsx +38 -0
  10. package/src/components/CompressDialog.css +264 -0
  11. package/src/components/CompressDialog.tsx +222 -0
  12. package/src/components/ContextMenu.css +155 -0
  13. package/src/components/ContextMenu.tsx +375 -0
  14. package/src/components/FileGrid.css +267 -0
  15. package/src/components/FileGrid.tsx +277 -0
  16. package/src/components/FileIcon.css +41 -0
  17. package/src/components/FileIcon.tsx +86 -0
  18. package/src/components/FileInfoDialog.css +252 -0
  19. package/src/components/FileInfoDialog.tsx +202 -0
  20. package/src/components/FileList.css +226 -0
  21. package/src/components/FileList.tsx +228 -0
  22. package/src/components/FileListView.css +36 -0
  23. package/src/components/FileListView.tsx +355 -0
  24. package/src/components/FileSidebar.css +94 -0
  25. package/src/components/FileSidebar.tsx +66 -0
  26. package/src/components/ProgressDialog.css +211 -0
  27. package/src/components/ProgressDialog.tsx +183 -0
  28. package/src/components/SortIndicator.css +7 -0
  29. package/src/components/SortIndicator.tsx +19 -0
  30. package/src/components/StatusBar.css +20 -0
  31. package/src/components/StatusBar.tsx +21 -0
  32. package/src/components/Toolbar.css +150 -0
  33. package/src/components/Toolbar.tsx +127 -0
  34. package/src/components/Window.css +246 -0
  35. package/src/components/Window.tsx +335 -0
  36. package/src/hooks/useApplicationIcon.ts +80 -0
  37. package/src/hooks/useDragAndDrop.ts +104 -0
  38. package/src/hooks/useMediaPlayer.ts +164 -0
  39. package/src/hooks/useSelection.ts +112 -0
  40. package/src/hooks/useWindowDrag.ts +60 -0
  41. package/src/hooks/useWindowResize.ts +126 -0
  42. package/src/index.css +3 -0
  43. package/src/index.ts +34 -0
  44. package/src/types/index.ts +274 -0
  45. package/src/utils/fileTypeIcon.ts +309 -0
  46. package/src/utils/folderTypeIcon.ts +132 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types/index.ts","../src/components/FileListView.tsx","../src/components/FileGrid.tsx","../src/components/FileIcon.tsx","../src/utils/fileTypeIcon.ts","../src/utils/folderTypeIcon.ts","../src/components/FileList.tsx","../src/components/SortIndicator.tsx","../src/components/FileSidebar.tsx","../src/components/Toolbar.tsx","../src/components/Breadcrumb.tsx","../src/components/StatusBar.tsx","../src/components/ContextMenu.tsx","../src/components/Window.tsx","../src/hooks/useWindowDrag.ts","../src/hooks/useWindowResize.ts","../src/components/CompressDialog.tsx","../src/components/ProgressDialog.tsx","../src/components/FileInfoDialog.tsx","../src/hooks/useSelection.ts","../src/hooks/useDragAndDrop.ts","../src/hooks/useMediaPlayer.ts","../src/hooks/useApplicationIcon.ts"],"sourcesContent":["/**\n * 文件类型(使用 const object 而非 enum,更好的 tree-shaking)\n */\nexport const FileType = {\n FOLDER: 'folder',\n FILE: 'file',\n IMAGE: 'image',\n VIDEO: 'video',\n MUSIC: 'music',\n DOCUMENT: 'document',\n CODE: 'code',\n TEXT: 'text',\n PDF: 'pdf',\n ARCHIVE: 'archive',\n APPLICATION: 'application',\n UNKNOWN: 'unknown'\n} as const;\n\nexport type FileType = typeof FileType[keyof typeof FileType];\n\n/**\n * 文件系统项\n */\nexport interface FileItem {\n /** 唯一标识(通常是完整路径) */\n id: string;\n name: string;\n type: FileType;\n size?: string;\n dateModified?: string;\n url?: string;\n thumbnailUrl?: string;\n children?: FileItem[];\n}\n\n/**\n * 视图模式\n */\nexport type ViewMode = 'grid' | 'list' | 'columns';\n\n/**\n * 排序配置\n */\nexport interface SortConfig {\n field: 'name' | 'dateModified' | 'size' | 'type';\n direction: 'asc' | 'desc';\n}\n\n/**\n * 侧边栏项目\n */\nexport interface SidebarItem {\n id: string;\n label: string;\n icon?: string;\n path?: string;\n children?: SidebarItem[];\n}\n\n/**\n * 面包屑项\n */\nexport interface BreadcrumbItem {\n id: string;\n name: string;\n}\n\n/**\n * 操作结果\n */\nexport interface OperationResult<T = void> {\n success: boolean;\n data?: T;\n error?: string;\n}\n\n/** 压缩格式 */\nexport type CompressFormat = 'zip' | 'tar' | 'tgz' | 'tarbz2';\n\n/** 压缩级别 */\nexport type CompressLevel = 'fast' | 'normal' | 'best';\n\n/** 压缩选项 */\nexport interface CompressOptions {\n format: CompressFormat;\n level?: CompressLevel;\n outputName: string;\n outputDir: string;\n deleteSource?: boolean;\n}\n\n/** 解压选项 */\nexport interface ExtractOptions {\n targetDir: string;\n deleteArchive?: boolean;\n}\n\n/** 压缩进度 */\nexport interface CompressProgress {\n currentFile: string;\n processedCount: number;\n totalCount: number;\n percent: number;\n}\n\n/** 压缩结果 */\nexport interface CompressResult {\n success: boolean;\n outputPath?: string;\n error?: string;\n}\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息(UI 使用) */\nexport interface ProgressInfo {\n type: 'compress' | 'extract';\n status: ProgressStatus;\n percent: number;\n currentFile?: string;\n processedCount?: number;\n totalCount?: number;\n error?: string;\n outputPath?: string;\n}\n\n/**\n * 文件操作适配器接口\n */\nexport interface FileExplorerAdapter {\n /** 读取目录 */\n readDirectory(dirPath: string): Promise<FileItem[]>;\n /** 读取系统路径目录 */\n readSystemPath(pathId: string): Promise<FileItem[]>;\n /** 获取系统路径 */\n getSystemPath(pathId: string): Promise<string | null>;\n /** 读取文件内容 */\n readFileContent(filePath: string): Promise<string>;\n /** 写入文件内容 */\n writeFileContent(filePath: string, content: string): Promise<OperationResult>;\n /** 创建文件夹 */\n createFolder(parentDir: string, folderName: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 创建文件 */\n createFile(parentDir: string, fileName: string, content?: string): Promise<OperationResult<{ finalPath: string }>>;\n /** 删除文件 */\n deleteFiles(paths: string[]): Promise<OperationResult>;\n /** 重命名文件 */\n renameFile(oldPath: string, newPath: string): Promise<OperationResult>;\n /** 复制文件 */\n copyFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ copiedPaths: string[] }>>;\n /** 移动文件 */\n moveFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{ movedPaths: string[] }>>;\n /** 使用系统默认应用打开 */\n openPath(filePath: string): Promise<OperationResult>;\n /** 复制文件到剪贴板 */\n copyFilesToClipboard(filePaths: string[]): Promise<OperationResult>;\n /** 获取剪贴板文件 */\n getClipboardFiles(): Promise<OperationResult<{ files: string[] }>>;\n /** 粘贴文件 */\n pasteFiles(targetDir: string, sourcePaths: string[]): Promise<OperationResult<{ pastedPaths: string[] }>>;\n /** 流式搜索文件 */\n searchFilesStream(searchPath: string, pattern: string, searchId: string): Promise<OperationResult>;\n /** 监听搜索结果 */\n onSearchResults(callback: (data: { searchId: string; items: FileItem[]; done: boolean }) => void): () => void;\n /** 压缩文件 */\n compressFiles(sources: string[], options: CompressOptions): Promise<CompressResult>;\n /** 解压文件 */\n extractArchive(archivePath: string, options: ExtractOptions): Promise<CompressResult>;\n /** 判断是否为压缩文件 */\n isArchiveFile(filePath: string): Promise<boolean>;\n /** 监听压缩进度 */\n onCompressProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听解压进度 */\n onExtractProgress(callback: (data: CompressProgress) => void): () => void;\n /** 监听目录变化 */\n watchDirectory(dirPath: string, watchId: string): Promise<OperationResult>;\n /** 停止监听目录 */\n unwatchDirectory(watchId: string): Promise<OperationResult>;\n /** 监听文件变化事件 */\n onWatchEvent(callback: (data: { watchId: string; event: WatchEvent }) => void): () => void;\n /** 显示文件/文件夹的系统属性窗口 */\n showFileInfo(filePath: string): Promise<OperationResult>;\n /** 在终端中打开目录 */\n openInTerminal(dirPath: string): Promise<OperationResult>;\n /** 通过 Cursor 打开 */\n openInEditor(targetPath: string): Promise<OperationResult>;\n /** 在新窗口中打开文件夹(使用系统文件管理器) */\n openInNewWindow(folderPath: string): Promise<OperationResult>;\n /** 请求窗口聚焦(用于右键打开菜单前激活窗口) */\n requestWindowFocus(): void;\n \n // ===== 媒体服务 =====\n \n /** 检测媒体文件是否需要转码 */\n mediaNeedsTranscode?(filePath: string): Promise<OperationResult<TranscodeInfo>>;\n /** 获取可播放的媒体 URL(自动转码) */\n mediaGetPlayableUrl?(filePath: string): Promise<{ success: boolean; url?: string; error?: string }>;\n /** 获取媒体元数据 */\n mediaGetMetadata?(filePath: string): Promise<OperationResult<MediaMetadata>>;\n /** 监听转码进度 */\n onMediaTranscodeProgress?(callback: (data: { filePath: string; progress: MediaTranscodeProgress }) => void): () => void;\n /** 清理指定文件的转码缓存 */\n mediaCleanupFile?(filePath: string): Promise<OperationResult>;\n \n // ===== 媒体预览窗口 =====\n \n /** 打开媒体预览窗口(原生窗口) */\n openMediaPreviewWindow?(filePath: string, mediaType: 'image' | 'video' | 'audio'): Promise<OperationResult>;\n /** 关闭媒体预览窗口 */\n closeMediaPreviewWindow?(filePath: string): Promise<OperationResult>;\n}\n\n/** 文件变化事件类型 */\nexport type WatchEventType = 'add' | 'change' | 'remove' | 'rename';\n\n/** 文件变化事件 */\nexport interface WatchEvent {\n type: WatchEventType;\n path: string;\n filename: string;\n}\n\n// ===== 媒体服务类型 =====\n\n/** 媒体转码方式 */\nexport type TranscodeMethod = 'direct' | 'remux' | 'transcode';\n\n/** 媒体转码状态 */\nexport type TranscodeStatus = 'idle' | 'checking' | 'transcoding' | 'ready' | 'error';\n\n/** 媒体转码信息 */\nexport interface TranscodeInfo {\n type: 'video' | 'audio';\n needsTranscode: boolean;\n method: TranscodeMethod;\n estimatedTime?: number;\n targetFormat?: string;\n}\n\n/** 媒体转码进度 */\nexport interface MediaTranscodeProgress {\n percent: number;\n time?: number;\n duration?: number;\n speed?: string;\n}\n\n/** 媒体元数据 */\nexport interface MediaMetadata {\n filePath: string;\n type: 'video' | 'audio';\n duration: number;\n title?: string;\n artist?: string;\n album?: string;\n}\n\n/**\n * 右键菜单项\n */\nexport interface ContextMenuItem {\n id: string;\n label: string;\n icon?: string;\n shortcut?: string;\n disabled?: boolean;\n separator?: boolean;\n danger?: boolean; // 危险操作标记(如删除)\n checked?: boolean; // 勾选状态(显示在右侧)\n action?: () => void;\n children?: ContextMenuItem[];\n}\n\n","import { useState, useCallback, useImperativeHandle, forwardRef } from 'react';\nimport { Icon } from '@iconify/react';\nimport { FileGrid } from './FileGrid';\nimport { FileList } from './FileList';\nimport { FileType, type FileItem, type SortConfig, type FileExplorerAdapter } from '../types';\nimport './FileListView.css';\n\ninterface FileListViewProps {\n items: FileItem[];\n viewMode?: 'grid' | 'list';\n loading?: boolean;\n adapter?: FileExplorerAdapter;\n currentPath?: string;\n getAppIconUrl?: (item: FileItem) => string | undefined;\n onOpen?: (item: FileItem) => void;\n onSelectionChange?: (ids: Set<string>, items: FileItem[]) => void;\n onContextMenu?: (event: React.MouseEvent, item: FileItem) => void;\n onContextMenuEmpty?: (event: React.MouseEvent) => void;\n onRename?: (item: FileItem, newName: string) => void;\n onSortChange?: (config: SortConfig) => void;\n onMove?: (sourceIds: string[], targetId: string) => void;\n}\n\nexport interface FileListViewHandle {\n clearSelection: () => void;\n startRename: (id: string) => void;\n selectAll: () => void;\n selectedIds: Set<string>;\n selectedItems: FileItem[];\n}\n\nexport const FileListView = forwardRef<FileListViewHandle, FileListViewProps>(\n (\n {\n items,\n viewMode = 'grid',\n loading = false,\n adapter,\n currentPath,\n getAppIconUrl,\n onOpen,\n onSelectionChange,\n onContextMenu,\n onContextMenuEmpty,\n onRename,\n onSortChange,\n onMove,\n },\n ref\n ) => {\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n const [editingId, setEditingId] = useState<string | null>(null);\n const [dragOverId, setDragOverId] = useState<string | null>(null);\n const [sortConfig, setSortConfig] = useState<SortConfig>({\n field: 'name',\n direction: 'asc',\n });\n\n // 获取选中的文件项\n const selectedItems = items.filter((item) => selectedIds.has(item.id));\n\n // 选择处理\n const handleSelect = useCallback(\n (item: FileItem, e: React.MouseEvent) => {\n if (e.metaKey || e.ctrlKey) {\n // 多选\n setSelectedIds((prev) => {\n const newSet = new Set(prev);\n if (newSet.has(item.id)) {\n newSet.delete(item.id);\n } else {\n newSet.add(item.id);\n }\n const newItems = items.filter((i) => newSet.has(i.id));\n onSelectionChange?.(newSet, newItems);\n return newSet;\n });\n } else if (e.shiftKey && selectedIds.size > 0) {\n // 范围选择\n const lastId = Array.from(selectedIds).pop();\n const lastIndex = items.findIndex((i) => i.id === lastId);\n const currentIndex = items.findIndex((i) => i.id === item.id);\n const start = Math.min(lastIndex, currentIndex);\n const end = Math.max(lastIndex, currentIndex);\n const newSet = new Set<string>();\n for (let i = start; i <= end; i++) {\n newSet.add(items[i]!.id);\n }\n setSelectedIds(newSet);\n const newItems = items.filter((i) => newSet.has(i.id));\n onSelectionChange?.(newSet, newItems);\n } else {\n // 单选\n const newSet = new Set([item.id]);\n setSelectedIds(newSet);\n onSelectionChange?.(newSet, [item]);\n }\n },\n [items, selectedIds, onSelectionChange]\n );\n\n const handleEmptyClick = useCallback(\n (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n clearSelection();\n }\n },\n []\n );\n\n // 清除选择\n const clearSelection = useCallback(() => {\n setSelectedIds(new Set());\n onSelectionChange?.(new Set(), []);\n }, [onSelectionChange]);\n\n // 打开文件/文件夹\n const handleOpen = useCallback(\n (item: FileItem) => {\n onOpen?.(item);\n },\n [onOpen]\n );\n\n // 右键菜单\n const handleContextMenu = useCallback(\n (item: FileItem, e: React.MouseEvent) => {\n if (!selectedIds.has(item.id)) {\n const newSet = new Set([item.id]);\n setSelectedIds(newSet);\n onSelectionChange?.(newSet, [item]);\n }\n onContextMenu?.(e, item);\n },\n [selectedIds, onSelectionChange, onContextMenu]\n );\n\n const handleEmptyContextMenu = useCallback(\n (e: React.MouseEvent) => {\n const target = e.target as HTMLElement;\n if (\n !target.closest('.file-grid-item') &&\n !target.closest('.file-list-row')\n ) {\n clearSelection();\n onContextMenuEmpty?.(e);\n }\n },\n [clearSelection, onContextMenuEmpty]\n );\n\n // 从子组件触发的空白处右键菜单\n const handleEmptyContextMenuFromChild = useCallback(\n (e: React.MouseEvent) => {\n clearSelection();\n onContextMenuEmpty?.(e);\n },\n [clearSelection, onContextMenuEmpty]\n );\n\n // 名称点击(用于重命名)\n const handleNameClick = useCallback(\n (item: FileItem, e: React.MouseEvent) => {\n if (selectedIds.has(item.id) && selectedIds.size === 1) {\n setTimeout(() => {\n if (selectedIds.has(item.id)) {\n setEditingId(item.id);\n }\n }, 500);\n }\n },\n [selectedIds]\n );\n\n // 重命名\n const handleRename = useCallback(\n (item: FileItem, newName: string) => {\n if (newName && newName !== item.name) {\n onRename?.(item, newName);\n }\n setEditingId(null);\n },\n [onRename]\n );\n\n const handleRenameCancel = useCallback(() => {\n setEditingId(null);\n }, []);\n\n // 排序\n const handleSort = useCallback(\n (field: string) => {\n setSortConfig((prev) => {\n const newConfig: SortConfig =\n prev.field === field\n ? { ...prev, direction: prev.direction === 'asc' ? 'desc' : 'asc' }\n : { field: field as SortConfig['field'], direction: 'asc' };\n onSortChange?.(newConfig);\n return newConfig;\n });\n },\n [onSortChange]\n );\n\n // 拖拽\n const handleDragStart = useCallback(\n (e: React.DragEvent, item: FileItem) => {\n if (!selectedIds.has(item.id)) {\n const newSet = new Set([item.id]);\n setSelectedIds(newSet);\n onSelectionChange?.(newSet, [item]);\n }\n e.dataTransfer.setData(\n 'text/plain',\n JSON.stringify([...selectedIds])\n );\n },\n [selectedIds, onSelectionChange]\n );\n\n const handleDragOver = useCallback(\n (e: React.DragEvent, item: FileItem) => {\n if (item.type === FileType.FOLDER && !selectedIds.has(item.id)) {\n setDragOverId(item.id);\n }\n },\n [selectedIds]\n );\n\n const handleDragLeave = useCallback(() => {\n setDragOverId(null);\n }, []);\n\n const handleDrop = useCallback(\n (e: React.DragEvent, targetItem: FileItem) => {\n setDragOverId(null);\n\n if (targetItem.type !== FileType.FOLDER) return;\n\n const data = e.dataTransfer.getData('text/plain');\n if (!data) return;\n\n try {\n const draggedIds: string[] = JSON.parse(data);\n if (draggedIds.includes(targetItem.id)) return;\n\n onMove?.(draggedIds, targetItem.id);\n clearSelection();\n } catch (error) {\n console.error('拖拽解析失败:', error);\n }\n },\n [onMove, clearSelection]\n );\n\n // 开始重命名(供外部调用)\n const startRename = useCallback((id: string) => {\n setEditingId(id);\n }, []);\n\n // 全选\n const selectAll = useCallback(() => {\n const newSet = new Set(items.map((i) => i.id));\n setSelectedIds(newSet);\n onSelectionChange?.(newSet, items);\n }, [items, onSelectionChange]);\n\n // 暴露方法\n useImperativeHandle(\n ref,\n () => ({\n clearSelection,\n startRename,\n selectAll,\n selectedIds,\n selectedItems,\n }),\n [selectedIds, selectedItems, clearSelection, startRename, selectAll]\n );\n\n return (\n <div\n className=\"file-list-view\"\n onClick={handleEmptyClick}\n onContextMenu={(e) => {\n e.preventDefault();\n handleEmptyContextMenu(e);\n }}\n >\n {/* 加载中 */}\n {loading && (\n <div className=\"file-list-view-loading\">\n <div className=\"file-list-view-spinner\"></div>\n <p>加载中...</p>\n </div>\n )}\n\n {/* 空文件夹 */}\n {!loading && items.length === 0 && (\n <div className=\"file-list-view-empty\">\n <Icon icon=\"lucide:folder-open\" width={64} height={64} className=\"file-list-view-empty-icon\" />\n <p>文件夹为空</p>\n </div>\n )}\n\n {/* 网格视图 */}\n {!loading && items.length > 0 && viewMode === 'grid' && (\n <FileGrid\n items={items}\n selectedIds={selectedIds}\n editingId={editingId}\n dragOverId={dragOverId}\n getAppIconUrl={getAppIconUrl}\n onSelect={handleSelect}\n onOpen={handleOpen}\n onContextMenu={handleContextMenu}\n onContextMenuEmpty={handleEmptyContextMenuFromChild}\n onNameClick={handleNameClick}\n onRename={handleRename}\n onRenameCancel={handleRenameCancel}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n />\n )}\n\n {/* 列表视图 */}\n {!loading && items.length > 0 && viewMode === 'list' && (\n <FileList\n items={items}\n selectedIds={selectedIds}\n editingId={editingId}\n dragOverId={dragOverId}\n sortConfig={sortConfig}\n onSelect={handleSelect}\n onOpen={handleOpen}\n onContextMenu={handleContextMenu}\n onContextMenuEmpty={handleEmptyContextMenuFromChild}\n onNameClick={handleNameClick}\n onRename={handleRename}\n onRenameCancel={handleRenameCancel}\n onSort={handleSort}\n onDragStart={handleDragStart}\n onDragOver={handleDragOver}\n onDragLeave={handleDragLeave}\n onDrop={handleDrop}\n />\n )}\n </div>\n );\n }\n);\n\nFileListView.displayName = 'FileListView';\n","import { useRef, useMemo } from 'react';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\nimport { FileIcon } from './FileIcon';\nimport './FileGrid.css';\n\n/**\n * 分离文件名和扩展名\n * 文件夹或无扩展名文件返回 { baseName: name, ext: '' }\n */\nfunction splitFileName(name: string, isFolder: boolean): { baseName: string; ext: string } {\n if (isFolder) {\n return { baseName: name, ext: '' };\n }\n const lastDot = name.lastIndexOf('.');\n // 没有扩展名,或者是隐藏文件(如 .gitignore)\n if (lastDot <= 0) {\n return { baseName: name, ext: '' };\n }\n return {\n baseName: name.substring(0, lastDot),\n ext: name.substring(lastDot), // 包含点号\n };\n}\n\n/**\n * 文件名组件 - 保留扩展名显示,只截断文件名部分\n */\nfunction FileName({ \n name, \n isFolder, \n isSelected, \n onClick \n}: { \n name: string; \n isFolder: boolean; \n isSelected: boolean;\n onClick: (e: React.MouseEvent) => void;\n}) {\n const { baseName, ext } = useMemo(() => splitFileName(name, isFolder), [name, isFolder]);\n \n return (\n <span\n onClick={onClick}\n className={`file-grid-item-name ${isSelected ? 'file-grid-item-name--selected' : ''}`}\n title={name}\n >\n {ext ? (\n <>\n <span className=\"file-grid-item-name-base\">{baseName}</span>\n <span className=\"file-grid-item-name-ext\">{ext}</span>\n </>\n ) : (\n name\n )}\n </span>\n );\n}\n\ninterface FileGridProps {\n items: FileItem[];\n selectedIds: Set<string>;\n editingId?: string | null;\n dragOverId?: string | null;\n getAppIconUrl?: (item: FileItem) => string | undefined;\n onSelect?: (item: FileItem, e: React.MouseEvent) => void;\n onOpen?: (item: FileItem) => void;\n onContextMenu?: (item: FileItem, e: React.MouseEvent) => void;\n onContextMenuEmpty?: (e: React.MouseEvent) => void;\n onNameClick?: (item: FileItem, e: React.MouseEvent) => void;\n onRename?: (item: FileItem, newName: string) => void;\n onRenameCancel?: (item: FileItem) => void;\n onDragStart?: (e: React.DragEvent, item: FileItem) => void;\n onDragOver?: (e: React.DragEvent, item: FileItem) => void;\n onDragLeave?: (e: React.DragEvent) => void;\n onDrop?: (e: React.DragEvent, item: FileItem) => void;\n onThumbnailError?: (item: FileItem, e: React.SyntheticEvent<HTMLImageElement, Event>) => void;\n}\n\nexport function FileGrid({\n items,\n selectedIds,\n editingId,\n dragOverId,\n getAppIconUrl,\n onSelect,\n onOpen,\n onContextMenu,\n onContextMenuEmpty,\n onNameClick,\n onRename,\n onRenameCancel,\n onDragStart,\n onDragOver,\n onDragLeave,\n onDrop,\n onThumbnailError,\n}: FileGridProps) {\n const renameInputRef = useRef<HTMLInputElement>(null);\n\n /**\n * 空白处右键菜单\n */\n const handleEmptyContextMenu = (e: React.MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target.closest('.file-grid-item')) {\n onContextMenuEmpty?.(e);\n }\n };\n\n /**\n * 判断是否有缩略图或应用程序图标\n */\n const hasThumbnail = (item: FileItem): boolean => {\n // 应用程序图标\n if (item.type === FileType.APPLICATION && getAppIconUrl?.(item)) {\n return true;\n }\n // 图片:必须有缩略图才显示,永远不显示原始 URL\n if (item.type === FileType.IMAGE) {\n return !!item.thumbnailUrl;\n }\n // 视频:必须有缩略图才显示,如果没有缩略图说明不应该被识别为视频\n if (item.type === FileType.VIDEO) {\n return !!item.thumbnailUrl;\n }\n return false;\n };\n\n /**\n * 视频悬停播放\n */\n const handleVideoHover = (e: React.SyntheticEvent<HTMLVideoElement>, isHover: boolean) => {\n const video = e.currentTarget;\n if (isHover) {\n video.play().catch(() => {});\n } else {\n video.pause();\n video.currentTime = 0;\n }\n };\n\n /**\n * 处理重命名(blur 事件)\n */\n const handleRename = (item: FileItem, e: React.FocusEvent<HTMLInputElement>) => {\n const input = e.target;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n onRename?.(item, newName);\n } else {\n onRenameCancel?.(item);\n }\n };\n\n /**\n * Enter 键保存\n */\n const handleEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.currentTarget.blur();\n };\n\n /**\n * Escape 键取消\n */\n const handleEscapeKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const input = e.currentTarget;\n const item = items.find((i) => i.id === editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n };\n\n return (\n <div className=\"file-grid\" onContextMenu={(e) => { e.preventDefault(); handleEmptyContextMenu(e); }}>\n {items.map((item) => {\n const isSelected = selectedIds.has(item.id);\n const isEditing = editingId === item.id;\n const isDragOver = dragOverId === item.id;\n const hasThumb = hasThumbnail(item);\n const appIconUrl = item.type === FileType.APPLICATION ? getAppIconUrl?.(item) : undefined;\n\n let itemClassName = 'file-grid-item';\n if (isSelected && !isEditing) {\n itemClassName += ' file-grid-item--selected';\n } else if (isDragOver) {\n itemClassName += ' file-grid-item--drag-over';\n } else {\n itemClassName += ' file-grid-item--normal';\n }\n\n return (\n <div\n key={item.id}\n draggable={!isEditing}\n onDragStart={(e) => onDragStart?.(e, item)}\n onDragOver={(e) => { e.preventDefault(); onDragOver?.(e, item); }}\n onDragLeave={(e) => onDragLeave?.(e)}\n onDrop={(e) => { e.preventDefault(); onDrop?.(e, item); }}\n onClick={(e) => { e.stopPropagation(); onSelect?.(item, e); }}\n onDoubleClick={(e) => { e.stopPropagation(); onOpen?.(item); }}\n onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); onContextMenu?.(item, e); }}\n className={itemClassName}\n >\n <div className=\"file-grid-item-icon\">\n {/* 应用程序图标 */}\n {appIconUrl && (\n <img\n src={appIconUrl}\n alt={item.name}\n className={`file-grid-item-thumbnail file-grid-item-thumbnail--application ${\n isSelected && !isEditing ? 'file-grid-item-thumbnail--selected' : ''\n }`}\n />\n )}\n {/* 视频缩略图 - 视频类型必须有缩略图,如果没有缩略图说明不应该被识别为视频,按普通文件处理 */}\n {!appIconUrl && item.type === FileType.VIDEO && item.thumbnailUrl && hasThumb && (\n <div className=\"file-grid-item-thumbnail file-grid-item-thumbnail--video\">\n <img\n src={item.thumbnailUrl}\n alt={item.name}\n className=\"file-grid-item-thumbnail\"\n onError={(e) => onThumbnailError?.(item, e)}\n />\n <div className=\"file-grid-item-video-play\">\n <div className=\"file-grid-item-video-play-icon\" />\n </div>\n </div>\n )}\n {/* 图片缩略图 - 永远只显示缩略图,不显示原始 URL */}\n {!appIconUrl && item.type === FileType.IMAGE && item.thumbnailUrl && hasThumb && (\n <img\n src={item.thumbnailUrl}\n alt={item.name}\n className=\"file-grid-item-thumbnail\"\n onError={(e) => onThumbnailError?.(item, e)}\n />\n )}\n {/* 默认图标 */}\n {!appIconUrl && !hasThumb && (\n <FileIcon type={item.type} name={item.name} size={48} />\n )}\n </div>\n\n <div className=\"file-grid-item-name-wrapper\">\n {isEditing ? (\n <input\n ref={renameInputRef}\n type=\"text\"\n className=\"file-grid-item-rename-input\"\n defaultValue={item.name}\n onBlur={(e) => handleRename(item, e)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n handleEnterKey(e);\n } else if (e.key === 'Escape') {\n handleEscapeKey(e);\n }\n }}\n autoFocus\n />\n ) : (\n <FileName\n name={item.name}\n isFolder={item.type === FileType.FOLDER}\n isSelected={isSelected}\n onClick={(e) => { e.stopPropagation(); onNameClick?.(item, e); }}\n />\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n","import { useMemo } from 'react';\nimport { Icon } from '@iconify/react';\nimport { FileType, type FileType as FileTypeType } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\nimport { getFolderTypeIcon } from '../utils/folderTypeIcon';\nimport './FileIcon.css';\n\ninterface FileIconProps {\n type: FileTypeType;\n name?: string;\n className?: string;\n size?: number;\n}\n\nexport function FileIcon({ type, name, className = '', size = 24 }: FileIconProps) {\n const iconName = useMemo(() => {\n if (type === FileType.FOLDER) {\n // 文件夹:先查特定类型图标,否则用默认 folder\n const folderIcon = name ? getFolderTypeIcon(name) : undefined;\n return folderIcon ?? 'flat-color-icons:folder';\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (name) {\n return getFileTypeIcon(name, type);\n }\n \n // 回退逻辑(没有文件名时)\n switch (type) {\n case FileType.IMAGE:\n return 'material-icon-theme:image';\n case FileType.TEXT:\n return 'material-icon-theme:document';\n case FileType.CODE:\n return 'material-icon-theme:javascript';\n case FileType.MUSIC:\n return 'material-icon-theme:audio';\n case FileType.VIDEO:\n return 'material-icon-theme:video';\n case FileType.PDF:\n return 'material-icon-theme:pdf';\n case FileType.DOCUMENT:\n return 'material-icon-theme:word';\n case FileType.APPLICATION:\n return 'material-icon-theme:exe';\n case FileType.ARCHIVE:\n return 'material-icon-theme:zip';\n default:\n return 'material-icon-theme:document';\n }\n }, [type, name]);\n\n const iconClass = useMemo(() => {\n const base = 'file-icon';\n switch (type) {\n case FileType.FOLDER:\n return `${base} file-icon--folder`;\n case FileType.IMAGE:\n return `${base} file-icon--image`;\n case FileType.TEXT:\n return `${base} file-icon--text`;\n case FileType.CODE:\n return `${base} file-icon--code`;\n case FileType.MUSIC:\n return `${base} file-icon--music`;\n case FileType.VIDEO:\n return `${base} file-icon--video`;\n case FileType.PDF:\n case FileType.DOCUMENT:\n return `${base} file-icon--pdf`;\n case FileType.APPLICATION:\n return `${base} file-icon--application`;\n case FileType.ARCHIVE:\n return `${base} file-icon--archive`;\n default:\n return `${base} file-icon--default`;\n }\n }, [type]);\n\n return (\n <div className={className}>\n <Icon icon={iconName} width={size} height={size} className={iconClass} />\n </div>\n );\n}\n\n","import { FileType } from '../types';\n\n/**\n * 文件图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有图标名\n * 2. EXT_MAP:扩展名 → 图标名\n * 3. SPECIAL_FILES:特殊文件名 → 图标名\n * 4. 逻辑:特殊文件名匹配 → 扩展名匹配 → 兜底\n */\n\n// 从 material-icon-theme.json 提取的所有图标名(~200 个常用)\nconst KNOWN_TYPES = new Set([\n '3d', 'actionscript', 'ada', 'adobe-illustrator', 'adobe-photoshop', 'android',\n 'angular', 'applescript', 'arduino', 'asciidoc', 'assembly', 'astro', 'audio',\n 'aurelia', 'babel', 'ballerina', 'bazel', 'biome', 'blender', 'bower', 'bun',\n 'c', 'cabal', 'caddy', 'cake', 'certificate', 'changelog', 'circleci', 'claude',\n 'clojure', 'cmake', 'cobol', 'coffee', 'command', 'conduct', 'contributing',\n 'controller', 'copilot', 'cpp', 'crystal', 'csharp', 'css', 'css-map', 'cucumber',\n 'cuda', 'cursor', 'cypress', 'd', 'dart', 'database', 'deno', 'dependabot', 'diff',\n 'django', 'docker', 'document', 'drawio', 'drizzle', 'editorconfig', 'ejs',\n 'elixir', 'elm', 'email', 'ember', 'epub', 'erlang', 'esbuild', 'eslint',\n 'excalidraw', 'exe', 'favicon', 'figma', 'firebase', 'flash', 'flow', 'font',\n 'forth', 'fortran', 'freemarker', 'fsharp', 'gamemaker', 'gatsby', 'gcp', 'gemfile',\n 'gemini', 'git', 'gitlab', 'gleam', 'go', 'go-mod', 'godot', 'gradle', 'graphql',\n 'groovy', 'grunt', 'gulp', 'h', 'haml', 'handlebars', 'hardhat', 'haskell', 'haxe',\n 'hcl', 'helm', 'hjson', 'hosts', 'hpp', 'html', 'http', 'husky', 'i18n', 'image',\n 'imba', 'ionic', 'jar', 'java', 'javaclass', 'javascript', 'javascript-map',\n 'jenkins', 'jest', 'jinja', 'jsconfig', 'json', 'julia', 'jupyter', 'just',\n 'karma', 'key', 'kotlin', 'kubernetes', 'laravel', 'lean', 'lefthook', 'lerna',\n 'less', 'lib', 'license', 'lighthouse', 'liquid', 'lisp', 'livescript', 'lock',\n 'log', 'lua', 'luau', 'makefile', 'markdown', 'markdownlint', 'matlab', 'maven',\n 'mdx', 'mercurial', 'mermaid', 'meson', 'minecraft', 'mjml', 'mocha', 'mojo',\n 'nest', 'netlify', 'next', 'nginx', 'nim', 'nix', 'nodejs', 'nodemon', 'npm',\n 'nuget', 'nunjucks', 'nuxt', 'nx', 'objective-c', 'objective-cpp', 'ocaml', 'odin',\n 'openapi', 'opentofu', 'pascal', 'pdf', 'perl', 'php', 'phpstan', 'phpunit',\n 'pipeline', 'playwright', 'pnpm', 'postcss', 'powerpoint', 'powershell', 'prettier',\n 'prisma', 'processing', 'prolog', 'proto', 'pug', 'puppet', 'purescript', 'python',\n 'pytorch', 'quasar', 'r', 'racket', 'razor', 'react', 'react-ts', 'readme', 'reason',\n 'remark', 'remix', 'renovate', 'replit', 'rescript', 'riot', 'roadmap', 'robot',\n 'robots', 'rollup', 'routing', 'rspec', 'rubocop', 'ruby', 'ruff', 'rust', 'salt',\n 'san', 'sas', 'sass', 'sbt', 'scala', 'scheme', 'search', 'sentry', 'sequelize',\n 'serverless', 'settings', 'shader', 'shellcheck', 'sketch', 'slim', 'slint',\n 'smarty', 'snakemake', 'snapcraft', 'snyk', 'solidity', 'spwn', 'stackblitz',\n 'stan', 'stencil', 'storybook', 'stryker', 'stylelint', 'stylus', 'sublime',\n 'subtitles', 'supabase', 'svelte', 'svg', 'svgo', 'swagger', 'swc', 'swift',\n 'tailwindcss', 'taskfile', 'tauri', 'tcl', 'teal', 'templ', 'template', 'terraform',\n 'test-js', 'test-jsx', 'test-ts', 'tex', 'todo', 'toml', 'travis', 'tree', 'tsconfig',\n 'tsdoc', 'turborepo', 'twig', 'typescript', 'typescript-def', 'unity', 'unocss',\n 'vagrant', 'vanilla-extract', 'vercel', 'verilog', 'video', 'vim', 'vite', 'vitest',\n 'vlang', 'vscode', 'vue', 'vue-config', 'wakatime', 'wallaby', 'webassembly',\n 'webhint', 'webpack', 'windicss', 'word', 'wrangler', 'wxt', 'xaml', 'xmake',\n 'xml', 'yaml', 'yarn', 'zig', 'zip',\n]);\n\n// 扩展名 → 图标名\nconst EXT_MAP: Record<string, string> = {\n // JavaScript/TypeScript\n 'js': 'javascript', 'mjs': 'javascript', 'cjs': 'javascript',\n 'jsx': 'react',\n 'ts': 'typescript', 'mts': 'typescript', 'cts': 'typescript',\n 'tsx': 'react-ts',\n // 前端框架\n 'vue': 'vue',\n 'svelte': 'svelte',\n 'astro': 'astro',\n // 后端语言\n 'py': 'python', 'pyw': 'python', 'pyi': 'python', 'pyc': 'python',\n 'java': 'java', 'class': 'javaclass', 'jar': 'jar',\n 'c': 'c', 'h': 'h',\n 'cpp': 'cpp', 'cc': 'cpp', 'cxx': 'cpp', 'hpp': 'hpp', 'hh': 'hpp', 'hxx': 'hpp',\n 'cs': 'csharp', 'csx': 'csharp',\n 'go': 'go',\n 'rs': 'rust',\n 'php': 'php', 'phtml': 'php',\n 'rb': 'ruby', 'rake': 'ruby',\n 'swift': 'swift',\n 'kt': 'kotlin', 'kts': 'kotlin',\n 'scala': 'scala',\n 'dart': 'dart',\n 'lua': 'lua', 'luau': 'luau',\n 'r': 'r', 'rdata': 'r', 'rds': 'r',\n 'pl': 'perl', 'pm': 'perl',\n 'sh': 'command', 'bash': 'command', 'zsh': 'command', 'fish': 'command',\n 'ps1': 'powershell', 'psm1': 'powershell', 'psd1': 'powershell',\n 'bat': 'command', 'cmd': 'command',\n // 样式\n 'css': 'css',\n 'scss': 'sass', 'sass': 'sass',\n 'less': 'less',\n 'styl': 'stylus',\n // 标记/配置\n 'html': 'html', 'htm': 'html', 'xhtml': 'html',\n 'xml': 'xml', 'xsl': 'xml', 'xslt': 'xml',\n 'json': 'json', 'jsonc': 'json', 'json5': 'json',\n 'yaml': 'yaml', 'yml': 'yaml',\n 'toml': 'toml',\n 'ini': 'settings',\n 'conf': 'settings', 'config': 'settings',\n // 文档\n 'md': 'markdown', 'markdown': 'markdown', 'mdx': 'mdx',\n 'txt': 'document',\n 'pdf': 'pdf',\n 'doc': 'word', 'docx': 'word', 'dot': 'word', 'dotx': 'word', 'odt': 'word',\n 'xls': 'table', 'xlsx': 'table', 'xlsm': 'table', 'ods': 'table', 'csv': 'table',\n 'ppt': 'powerpoint', 'pptx': 'powerpoint', 'odp': 'powerpoint',\n // 图片\n 'jpg': 'image', 'jpeg': 'image', 'png': 'image', 'gif': 'image', 'webp': 'image',\n 'ico': 'image', 'bmp': 'image', 'tiff': 'image', 'tif': 'image', 'heic': 'image', 'heif': 'image',\n 'svg': 'svg',\n 'psd': 'adobe-photoshop',\n 'ai': 'adobe-illustrator',\n 'sketch': 'sketch',\n 'fig': 'figma', 'figma': 'figma',\n // 视频/音频\n 'mp4': 'video', 'mov': 'video', 'avi': 'video', 'mkv': 'video', 'webm': 'video',\n 'flv': 'video', 'wmv': 'video', 'm4v': 'video', '3gp': 'video', 'mpeg': 'video', 'mpg': 'video',\n 'mp3': 'audio', 'wav': 'audio', 'flac': 'audio', 'aac': 'audio', 'ogg': 'audio',\n 'wma': 'audio', 'm4a': 'audio', 'aiff': 'audio',\n // 压缩\n 'zip': 'zip', 'rar': 'zip', '7z': 'zip', 'tar': 'zip', 'gz': 'zip', 'bz2': 'zip',\n 'xz': 'zip', 'tgz': 'zip', 'tbz2': 'zip',\n // 数据库\n 'sql': 'database',\n 'db': 'database', 'sqlite': 'database', 'sqlite3': 'database',\n 'prisma': 'prisma',\n // 其他\n 'log': 'log',\n 'lock': 'lock',\n 'env': 'settings',\n 'graphql': 'graphql', 'gql': 'graphql',\n 'proto': 'proto',\n 'wasm': 'webassembly',\n 'zig': 'zig',\n 'nim': 'nim',\n 'nix': 'nix',\n 'hcl': 'hcl', 'tf': 'terraform',\n 'sol': 'solidity',\n 'ex': 'elixir', 'exs': 'elixir',\n 'erl': 'erlang', 'hrl': 'erlang',\n 'hs': 'haskell', 'lhs': 'haskell',\n 'ml': 'ocaml', 'mli': 'ocaml',\n 'clj': 'clojure', 'cljs': 'clojure', 'cljc': 'clojure',\n 'lisp': 'lisp', 'lsp': 'lisp', 'el': 'lisp',\n 'vim': 'vim',\n 'dockerfile': 'docker',\n};\n\n// 特殊文件名 → 图标名\nconst SPECIAL_FILES: Record<string, string> = {\n // Git\n '.gitignore': 'git', '.gitattributes': 'git', '.gitmodules': 'git', '.gitkeep': 'git',\n // 环境\n '.env': 'settings', '.env.local': 'settings', '.env.development': 'settings',\n '.env.production': 'settings', '.env.test': 'settings', '.env.example': 'settings',\n // Node/包管理\n 'package.json': 'nodejs', 'package-lock.json': 'npm',\n 'yarn.lock': 'yarn', '.yarnrc': 'yarn', '.yarnrc.yml': 'yarn',\n 'pnpm-lock.yaml': 'pnpm', '.pnpmfile.cjs': 'pnpm',\n 'bun.lockb': 'bun', 'bunfig.toml': 'bun',\n // Python\n 'requirements.txt': 'python', 'pipfile': 'python', 'pipfile.lock': 'python',\n 'pyproject.toml': 'python', 'poetry.lock': 'python', 'setup.py': 'python',\n // Rust\n 'cargo.toml': 'rust', 'cargo.lock': 'rust',\n // Go\n 'go.mod': 'go-mod', 'go.sum': 'go-mod', 'go.work': 'go-mod',\n // PHP\n 'composer.json': 'php', 'composer.lock': 'php',\n // Ruby\n 'gemfile': 'gemfile', 'gemfile.lock': 'gemfile', 'rakefile': 'ruby',\n // Docker\n 'dockerfile': 'docker', 'docker-compose.yml': 'docker', 'docker-compose.yaml': 'docker',\n '.dockerignore': 'docker',\n // 构建工具\n 'makefile': 'makefile', 'gnumakefile': 'makefile',\n 'cmakelists.txt': 'cmake',\n 'build.gradle': 'gradle', 'build.gradle.kts': 'gradle', 'settings.gradle': 'gradle',\n 'pom.xml': 'maven',\n // 配置\n 'tsconfig.json': 'tsconfig', 'jsconfig.json': 'jsconfig',\n '.prettierrc': 'prettier', '.prettierrc.json': 'prettier', '.prettierrc.js': 'prettier',\n '.prettierignore': 'prettier', 'prettier.config.js': 'prettier',\n '.eslintrc': 'eslint', '.eslintrc.json': 'eslint', '.eslintrc.js': 'eslint',\n '.eslintignore': 'eslint', 'eslint.config.js': 'eslint', 'eslint.config.mjs': 'eslint',\n '.editorconfig': 'editorconfig',\n 'vite.config.ts': 'vite', 'vite.config.js': 'vite',\n 'webpack.config.js': 'webpack', 'webpack.config.ts': 'webpack',\n 'rollup.config.js': 'rollup', 'rollup.config.ts': 'rollup',\n 'esbuild.config.js': 'esbuild',\n 'tailwind.config.js': 'tailwindcss', 'tailwind.config.ts': 'tailwindcss',\n 'postcss.config.js': 'postcss', 'postcss.config.cjs': 'postcss',\n 'babel.config.js': 'babel', '.babelrc': 'babel',\n 'jest.config.js': 'jest', 'jest.config.ts': 'jest',\n 'vitest.config.ts': 'vitest', 'vitest.config.js': 'vitest',\n 'playwright.config.ts': 'playwright', 'playwright.config.js': 'playwright',\n 'cypress.config.ts': 'cypress', 'cypress.config.js': 'cypress',\n '.swcrc': 'swc', 'swc.config.js': 'swc',\n 'turbo.json': 'turborepo',\n 'nx.json': 'nx',\n 'biome.json': 'biome',\n '.nvmrc': 'nodejs', '.node-version': 'nodejs',\n // 框架配置\n 'nuxt.config.ts': 'nuxt', 'nuxt.config.js': 'nuxt',\n 'next.config.js': 'next', 'next.config.mjs': 'next', 'next.config.ts': 'next',\n 'svelte.config.js': 'svelte',\n 'astro.config.mjs': 'astro', 'astro.config.ts': 'astro',\n 'vue.config.js': 'vue-config',\n 'angular.json': 'angular',\n 'nest-cli.json': 'nest',\n 'tauri.conf.json': 'tauri',\n // CI/CD\n '.travis.yml': 'travis',\n '.gitlab-ci.yml': 'gitlab',\n 'vercel.json': 'vercel',\n 'netlify.toml': 'netlify',\n // 其他\n 'license': 'license', 'license.md': 'license', 'license.txt': 'license',\n 'readme': 'readme', 'readme.md': 'readme', 'readme.txt': 'readme',\n 'changelog': 'changelog', 'changelog.md': 'changelog',\n '.npmrc': 'npm', '.npmignore': 'npm',\n 'robots.txt': 'robots',\n '.htaccess': 'nginx',\n 'vagrantfile': 'vagrant',\n '.stylelintrc': 'stylelint', '.stylelintrc.json': 'stylelint',\n 'nodemon.json': 'nodemon',\n '.huskyrc': 'husky',\n 'renovate.json': 'renovate',\n '.snyk': 'snyk',\n 'deno.json': 'deno', 'deno.jsonc': 'deno',\n};\n\n/**\n * 根据文件名获取 material-icon-theme 图标名称\n */\nexport function getFileTypeIcon(fileName: string, fallbackType?: FileType): string {\n const lowerName = fileName.toLowerCase();\n\n // 1. 特殊文件名匹配\n if (SPECIAL_FILES[lowerName]) {\n const type = SPECIAL_FILES[lowerName];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 2. Dockerfile 特殊处理\n if (lowerName === 'dockerfile' || lowerName.startsWith('dockerfile.')) {\n return 'material-icon-theme:docker';\n }\n\n // 3. .env 变体处理\n if (lowerName === '.env' || lowerName.startsWith('.env.')) {\n return 'material-icon-theme:settings';\n }\n\n // 4. 提取扩展名并匹配\n const lastDotIndex = fileName.lastIndexOf('.');\n const ext = lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1).toLowerCase() : '';\n\n // 处理复合扩展名\n if (ext === 'ts' || ext === 'js') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.d')) {\n return 'material-icon-theme:typescript-def';\n }\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'ts' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-js';\n }\n }\n if (ext === 'jsx' || ext === 'tsx') {\n const baseName = fileName.substring(0, lastDotIndex).toLowerCase();\n if (baseName.endsWith('.test') || baseName.endsWith('.spec')) {\n return ext === 'tsx' ? 'material-icon-theme:test-ts' : 'material-icon-theme:test-jsx';\n }\n }\n\n if (ext && EXT_MAP[ext]) {\n const type = EXT_MAP[ext];\n if (KNOWN_TYPES.has(type)) {\n return `material-icon-theme:${type}`;\n }\n }\n\n // 5. 根据 fallbackType 返回兜底图标\n if (fallbackType) {\n return getFallbackIcon(fallbackType);\n }\n\n // 6. 最终兜底\n return 'material-icon-theme:document';\n}\n\nfunction getFallbackIcon(type: FileType): string {\n switch (type) {\n case FileType.IMAGE: return 'material-icon-theme:image';\n case FileType.VIDEO: return 'material-icon-theme:video';\n case FileType.MUSIC: return 'material-icon-theme:audio';\n case FileType.CODE: return 'material-icon-theme:javascript';\n case FileType.TEXT: return 'material-icon-theme:document';\n case FileType.DOCUMENT: return 'material-icon-theme:word';\n case FileType.PDF: return 'material-icon-theme:pdf';\n case FileType.ARCHIVE: return 'material-icon-theme:zip';\n case FileType.APPLICATION: return 'material-icon-theme:exe';\n default: return 'material-icon-theme:document';\n }\n}\n\n","/**\n * 文件夹图标映射(基于 material-icon-theme.json)\n *\n * 原理:\n * 1. KNOWN_TYPES:从 material-icon-theme.json 提取的所有 folder-{type} 类型\n * 2. ALIASES:常见变体映射到标准名\n * 3. 逻辑:目录名小写 → 查别名 → 查白名单 → 命中则返回 material-icon-theme:folder-{type}\n */\n\n// 从 material-icon-theme.json 提取的所有 folder-* 类型(去掉 folder- 前缀和 -open 后缀)\nconst KNOWN_TYPES = new Set([\n 'admin', 'android', 'angular', 'animation', 'ansible', 'api', 'apollo', 'app',\n 'archive', 'astro', 'atom', 'attachment', 'audio', 'aurelia', 'aws',\n 'azure-pipelines', 'backup', 'base', 'batch', 'benchmark', 'bibliography',\n 'bicep', 'blender', 'bloc', 'bower', 'buildkite', 'cart', 'changesets', 'ci',\n 'circleci', 'class', 'claude', 'client', 'cline', 'cloud-functions', 'cloudflare',\n 'cluster', 'cobol', 'command', 'components', 'config', 'connection', 'console',\n 'constant', 'container', 'content', 'context', 'contract', 'controller', 'core',\n 'coverage', 'css', 'cue', 'cursor', 'custom', 'cypress', 'dal', 'dart', 'database',\n 'debug', 'decorators', 'delta', 'desktop', 'directive', 'dist', 'docker', 'docs',\n 'download', 'drizzle', 'dump', 'element', 'enum', 'environment', 'error', 'eslint',\n 'event', 'examples', 'expo', 'export', 'fastlane', 'favicon', 'features', 'filter',\n 'firebase', 'firestore', 'flow', 'flutter', 'font', 'forgejo', 'functions',\n 'gamemaker', 'generator', 'gh-workflows', 'git', 'gitea', 'github', 'gitlab',\n 'global', 'godot', 'gradle', 'graphql', 'guard', 'gulp', 'helm', 'helper', 'home',\n 'hook', 'husky', 'i18n', 'images', 'import', 'include', 'input', 'intellij',\n 'interceptor', 'interface', 'ios', 'java', 'javascript', 'jinja', 'job', 'json',\n 'jupyter', 'keys', 'kubernetes', 'kusto', 'layout', 'lefthook', 'less', 'lib',\n 'license', 'link', 'linux', 'liquibase', 'log', 'lottie', 'lua', 'luau', 'macos',\n 'mail', 'mappings', 'markdown', 'mercurial', 'messages', 'meta', 'metro',\n 'middleware', 'migrations', 'mjml', 'mobile', 'mock', 'mojo', 'molecule', 'moon',\n 'netlify', 'next', 'ngrx-store', 'node', 'nuxt', 'obsidian', 'organism', 'other',\n 'packages', 'pdf', 'pdm', 'php', 'phpmailer', 'pipe', 'plastic', 'plugin', 'policy',\n 'powershell', 'prisma', 'private', 'project', 'prompts', 'proto', 'public', 'python',\n 'pytorch', 'quasar', 'queue', 'react-components', 'redux-reducer', 'repository',\n 'resolver', 'resource', 'review', 'robot', 'routes', 'rules', 'rust', 'salt',\n 'sandbox', 'sass', 'scala', 'scons', 'scripts', 'secure', 'seeders', 'server',\n 'serverless', 'shader', 'shared', 'simulations', 'snapcraft', 'snippet', 'src',\n 'src-tauri', 'stack', 'stencil', 'store', 'storybook', 'stylus', 'sublime',\n 'supabase', 'svelte', 'svg', 'syntax', 'target', 'taskfile', 'tasks', 'television',\n 'temp', 'template', 'terraform', 'test', 'theme', 'toc', 'tools', 'trash', 'trigger',\n 'turborepo', 'typescript', 'ui', 'unity', 'update', 'upload', 'utils', 'vercel',\n 'verdaccio', 'video', 'views', 'vm', 'vscode', 'vue', 'vue-directives', 'vuepress',\n 'vuex-store', 'wakatime', 'webpack', 'windows', 'wordpress', 'yarn', 'zeabur',\n]);\n\n// 别名映射\nconst ALIASES: Record<string, string> = {\n // 复数/变体\n 'tests': 'test', '__tests__': 'test', '__test__': 'test', 'spec': 'test', 'specs': 'test',\n 'script': 'scripts',\n 'configs': 'config', 'configuration': 'config', 'configurations': 'config',\n 'route': 'routes', 'routing': 'routes',\n 'stories': 'storybook', 'story': 'storybook',\n 'templates': 'template',\n 'themes': 'theme',\n 'videos': 'video',\n 'imgs': 'images', 'img': 'images', 'image': 'images',\n 'fonts': 'font',\n 'styles': 'css', 'style': 'css', 'styling': 'css', 'stylesheets': 'css',\n 'view': 'views', 'pages': 'views', 'page': 'views',\n 'layouts': 'layout',\n 'models': 'database', 'model': 'database',\n 'modules': 'lib', 'module': 'lib', 'mods': 'lib',\n 'plugins': 'plugin', 'addons': 'plugin', 'extensions': 'plugin',\n 'middlewares': 'middleware',\n 'helpers': 'helper', 'utilities': 'utils', 'util': 'utils',\n 'tool': 'tools', 'tooling': 'tools',\n 'resources': 'resource', 'res': 'resource', 'assets': 'resource', 'asset': 'resource',\n 'hooks': 'hook', 'composables': 'hook',\n 'mocks': 'mock', '__mocks__': 'mock', 'fixtures': 'mock', '__fixtures__': 'mock',\n 'logs': 'log',\n 'uploads': 'upload',\n 'function': 'functions', 'func': 'functions', 'fns': 'functions',\n 'services': 'server', 'service': 'server',\n 'component': 'components', 'comp': 'components', 'comps': 'components',\n 'controllers': 'controller',\n // 常见变体\n 'source': 'src', 'sources': 'src',\n 'distribution': 'dist', 'build': 'dist', 'builds': 'dist', 'out': 'dist', 'output': 'dist',\n 'documentation': 'docs', 'doc': 'docs', 'document': 'docs', 'documents': 'docs',\n 'static': 'public', 'statics': 'public', 'publics': 'public',\n 'libs': 'lib', 'library': 'lib', 'vendor': 'lib', 'vendors': 'lib',\n 'bin': 'scripts', 'binaries': 'scripts',\n 'tmp': 'temp', 'temporary': 'temp', 'cache': 'temp', 'caches': 'temp', '.cache': 'temp', '.turbo': 'temp',\n 'types': 'typescript', '@types': 'typescript', 'typings': 'typescript', 'dts': 'typescript',\n 'locales': 'i18n', 'locale': 'i18n', 'lang': 'i18n', 'languages': 'i18n', 'translations': 'i18n',\n 'db': 'database', 'databases': 'database', 'sql': 'database', 'queries': 'database',\n 'migration': 'migrations', 'seeds': 'seeders', 'seed': 'seeders',\n // 技术栈\n '.vscode': 'vscode',\n '.github': 'github',\n '.gitlab': 'gitlab',\n '.circleci': 'circleci',\n '.husky': 'husky',\n '.docker': 'docker',\n 'node_modules': 'node',\n 'scss': 'sass',\n 'renderer': 'client', 'frontend': 'client', 'web': 'client', 'webapp': 'client', 'website': 'client',\n 'backend': 'server', 'main': 'server',\n 'preload': 'scripts',\n '.idea': 'intellij',\n '.git': 'git',\n 'k8s': 'kubernetes', 'kube': 'kubernetes',\n 'mongo': 'database', 'mongodb': 'database', 'mysql': 'database', 'postgres': 'database',\n 'api': 'api', 'apis': 'api',\n 'interfaces': 'interface',\n 'notebook': 'jupyter', 'notebooks': 'jupyter', 'ipynb': 'jupyter',\n 'notification': 'messages', 'notifications': 'messages',\n 'env': 'environment', 'envs': 'environment',\n 'redux': 'redux-reducer', 'store': 'store', 'stores': 'store',\n 'electron': 'desktop',\n 'tauri': 'src-tauri',\n};\n\n/**\n * 根据文件夹名称获取对应的 material-icon-theme 图标名\n * @returns 图标名 或 undefined(让上层兜底默认图标)\n */\nexport function getFolderTypeIcon(folderName: string): string | undefined {\n const name = (folderName || '').trim();\n if (!name) return undefined;\n\n const lower = name.replace(/[\\\\/]+$/, '').toLowerCase();\n const standardName = ALIASES[lower] ?? lower;\n\n if (KNOWN_TYPES.has(standardName)) {\n return `material-icon-theme:folder-${standardName}`;\n }\n\n return undefined;\n}\n","import { useRef } from 'react';\nimport type { FileItem, SortConfig } from '../types';\nimport { FileType } from '../types';\nimport { FileIcon } from './FileIcon';\nimport { SortIndicator } from './SortIndicator';\nimport './FileList.css';\n\ninterface FileListProps {\n items: FileItem[];\n selectedIds: Set<string>;\n sortConfig?: SortConfig;\n editingId?: string | null;\n dragOverId?: string | null;\n onSelect?: (item: FileItem, e: React.MouseEvent) => void;\n onOpen?: (item: FileItem) => void;\n onContextMenu?: (item: FileItem, e: React.MouseEvent) => void;\n onContextMenuEmpty?: (e: React.MouseEvent) => void;\n onNameClick?: (item: FileItem, e: React.MouseEvent) => void;\n onRename?: (item: FileItem, newName: string) => void;\n onRenameCancel?: (item: FileItem) => void;\n onSort?: (field: string) => void;\n onDragStart?: (e: React.DragEvent, item: FileItem) => void;\n onDragOver?: (e: React.DragEvent, item: FileItem) => void;\n onDragLeave?: (e: React.DragEvent) => void;\n onDrop?: (e: React.DragEvent, item: FileItem) => void;\n}\n\n/**\n * 获取类型标签\n */\nfunction getTypeLabel(type: FileType): string {\n const labels: Record<FileType, string> = {\n [FileType.FOLDER]: '文件夹',\n [FileType.FILE]: '文件',\n [FileType.IMAGE]: '图片',\n [FileType.VIDEO]: '视频',\n [FileType.MUSIC]: '音频',\n [FileType.DOCUMENT]: '文档',\n [FileType.CODE]: '代码',\n [FileType.TEXT]: '文本',\n [FileType.PDF]: 'PDF',\n [FileType.ARCHIVE]: '压缩包',\n [FileType.APPLICATION]: '应用程序',\n [FileType.UNKNOWN]: '未知',\n };\n return labels[type] || type;\n}\n\nexport function FileList({\n items,\n selectedIds,\n sortConfig,\n editingId,\n dragOverId,\n onSelect,\n onOpen,\n onContextMenu,\n onContextMenuEmpty,\n onNameClick,\n onRename,\n onRenameCancel,\n onSort,\n onDragStart,\n onDragOver,\n onDragLeave,\n onDrop,\n}: FileListProps) {\n const renameInputRef = useRef<HTMLInputElement>(null);\n\n /**\n * 空白处右键菜单\n */\n const handleEmptyContextMenu = (e: React.MouseEvent) => {\n const target = e.target as HTMLElement;\n if (!target.closest('tr')) {\n onContextMenuEmpty?.(e);\n }\n };\n\n /**\n * 处理重命名(blur 事件)\n */\n const handleRename = (item: FileItem, e: React.FocusEvent<HTMLInputElement>) => {\n const input = e.target;\n const newName = input.value.trim();\n if (newName && newName !== item.name) {\n onRename?.(item, newName);\n } else {\n onRenameCancel?.(item);\n }\n };\n\n /**\n * Enter 键保存\n */\n const handleEnterKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n e.currentTarget.blur();\n };\n\n /**\n * Escape 键取消\n */\n const handleEscapeKey = (e: React.KeyboardEvent<HTMLInputElement>) => {\n const input = e.currentTarget;\n const item = items.find((i) => i.id === editingId);\n if (item) {\n input.value = item.name;\n }\n input.blur();\n };\n\n return (\n <div className=\"file-list\" onContextMenu={(e) => { e.preventDefault(); handleEmptyContextMenu(e); }}>\n <table className=\"file-list-table\">\n <thead className=\"file-list-header\">\n <tr>\n <th\n className=\"file-list-header-cell file-list-header-cell--name\"\n onClick={() => onSort?.('name')}\n >\n 名称\n {sortConfig?.field === 'name' && (\n <SortIndicator direction={sortConfig.direction} />\n )}\n </th>\n <th\n className=\"file-list-header-cell\"\n onClick={() => onSort?.('dateModified')}\n >\n 修改日期\n {sortConfig?.field === 'dateModified' && (\n <SortIndicator direction={sortConfig.direction} />\n )}\n </th>\n <th\n className=\"file-list-header-cell\"\n onClick={() => onSort?.('size')}\n >\n 大小\n {sortConfig?.field === 'size' && (\n <SortIndicator direction={sortConfig.direction} />\n )}\n </th>\n <th\n className=\"file-list-header-cell\"\n onClick={() => onSort?.('type')}\n >\n 类型\n {sortConfig?.field === 'type' && (\n <SortIndicator direction={sortConfig.direction} />\n )}\n </th>\n </tr>\n </thead>\n <tbody className=\"file-list-body\">\n {items.map((item, index) => {\n const isSelected = selectedIds.has(item.id);\n const isEditing = editingId === item.id;\n const isDragOver = dragOverId === item.id;\n\n let rowClassName = 'file-list-row';\n if (isSelected) {\n rowClassName += ' file-list-row--selected';\n } else if (isDragOver) {\n rowClassName += ' file-list-row--drag-over';\n } else if (index % 2 === 0) {\n rowClassName += ' file-list-row--even';\n } else {\n rowClassName += ' file-list-row--odd';\n }\n\n return (\n <tr\n key={item.id}\n draggable={!isEditing}\n onDragStart={(e) => onDragStart?.(e, item)}\n onDragOver={(e) => { e.preventDefault(); onDragOver?.(e, item); }}\n onDragLeave={(e) => onDragLeave?.(e)}\n onDrop={(e) => { e.preventDefault(); onDrop?.(e, item); }}\n onClick={(e) => { e.stopPropagation(); onSelect?.(item, e); }}\n onDoubleClick={(e) => { e.stopPropagation(); onOpen?.(item); }}\n onContextMenu={(e) => { e.preventDefault(); e.stopPropagation(); onContextMenu?.(item, e); }}\n className={rowClassName}\n >\n <td className={`file-list-cell file-list-cell--name ${isSelected ? 'file-list-cell--selected' : ''}`}>\n <FileIcon type={item.type} name={item.name} size={16} />\n {isEditing ? (\n <input\n ref={renameInputRef}\n type=\"text\"\n className=\"file-list-rename-input\"\n defaultValue={item.name}\n onBlur={(e) => handleRename(item, e)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n handleEnterKey(e);\n } else if (e.key === 'Escape') {\n handleEscapeKey(e);\n }\n }}\n autoFocus\n />\n ) : (\n <span\n onClick={(e) => { e.stopPropagation(); onNameClick?.(item, e); }}\n className={`file-list-name ${isSelected ? 'file-list-name--selected' : ''}`}\n >\n {item.name}\n </span>\n )}\n </td>\n <td className={`file-list-cell ${isSelected ? 'file-list-cell--selected' : ''}`}>\n {item.dateModified || '--'}\n </td>\n <td className={`file-list-cell file-list-cell--size ${isSelected ? 'file-list-cell--selected' : ''}`}>\n {item.size || '--'}\n </td>\n <td className={`file-list-cell ${isSelected ? 'file-list-cell--selected' : ''}`}>\n {getTypeLabel(item.type)}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n </div>\n );\n}\n","import { Icon } from '@iconify/react';\nimport './SortIndicator.css';\n\ninterface SortIndicatorProps {\n direction: 'asc' | 'desc';\n}\n\nexport function SortIndicator({ direction }: SortIndicatorProps) {\n return (\n <span className=\"sort-indicator\">\n <Icon \n icon={direction === 'asc' ? 'lucide:chevron-up' : 'lucide:chevron-down'} \n width={12} \n height={12} \n />\n </span>\n );\n}\n\n","import { Icon } from '@iconify/react';\nimport type { SidebarItem } from '../types';\nimport './FileSidebar.css';\n\ninterface SidebarSection {\n id: string;\n title: string;\n items: SidebarItem[];\n}\n\ninterface FileSidebarProps {\n sections: SidebarSection[];\n activeId?: string;\n onNavigate?: (item: SidebarItem) => void;\n}\n\nexport function FileSidebar({ sections, activeId, onNavigate }: FileSidebarProps) {\n const handleNavigate = (item: SidebarItem) => {\n onNavigate?.(item);\n };\n\n // 将 Lucide 图标名称转换为 Iconify 格式\n const getIconName = (iconName?: string): string => {\n if (!iconName) return 'mdi:folder';\n // 如果已经是 Iconify 格式,直接返回\n if (iconName.includes(':')) return iconName;\n // 否则转换为 lucide: 格式\n return `lucide:${iconName.toLowerCase()}`;\n };\n\n return (\n <div className=\"file-sidebar\">\n {sections.map((section) => (\n <div key={section.id} className=\"file-sidebar-section\">\n <div className=\"file-sidebar-section-title\">{section.title}</div>\n <ul className=\"file-sidebar-list\">\n {section.items.map((item) => {\n const isActive = activeId === item.id;\n return (\n <li\n key={item.id}\n onClick={() => handleNavigate(item)}\n className={`file-sidebar-item ${\n isActive ? 'file-sidebar-item--active' : ''\n }`}\n >\n <Icon\n icon={getIconName(item.icon)}\n width={18}\n height={18}\n className={\n isActive\n ? 'file-sidebar-item-icon--active'\n : 'file-sidebar-item-icon'\n }\n />\n <span>{item.label}</span>\n </li>\n );\n })}\n </ul>\n </div>\n ))}\n </div>\n );\n}\n","import { Icon } from '@iconify/react';\nimport { Breadcrumb } from './Breadcrumb';\nimport type { BreadcrumbItem } from '../types';\nimport './Toolbar.css';\n\ninterface ToolbarProps {\n canGoBack?: boolean;\n canGoForward?: boolean;\n breadcrumbs?: BreadcrumbItem[];\n viewMode?: 'grid' | 'list';\n searchQuery?: string;\n showSearch?: boolean;\n showViewToggle?: boolean;\n draggable?: boolean;\n onBack?: () => void;\n onForward?: () => void;\n onBreadcrumbNavigate?: (item: BreadcrumbItem) => void;\n onViewModeChange?: (mode: 'grid' | 'list') => void;\n onSearchQueryChange?: (query: string) => void;\n children?: React.ReactNode;\n breadcrumbSlot?: React.ReactNode;\n actionsSlot?: React.ReactNode;\n}\n\nexport function Toolbar({\n canGoBack = false,\n canGoForward = false,\n breadcrumbs = [],\n viewMode = 'grid',\n searchQuery = '',\n showSearch = false,\n showViewToggle = true,\n draggable = false,\n onBack,\n onForward,\n onBreadcrumbNavigate,\n onViewModeChange,\n onSearchQueryChange,\n children,\n breadcrumbSlot,\n actionsSlot,\n}: ToolbarProps) {\n return (\n <div\n className={`file-toolbar ${draggable ? 'file-toolbar--draggable' : ''}`}\n >\n {/* 导航按钮 */}\n <div className=\"file-toolbar-nav\">\n <button\n className=\"file-toolbar-button\"\n onClick={onBack}\n disabled={!canGoBack}\n title=\"后退\"\n >\n <Icon icon=\"lucide:chevron-left\" width={18} height={18} />\n </button>\n <button\n className=\"file-toolbar-button\"\n onClick={onForward}\n disabled={!canGoForward}\n title=\"前进\"\n >\n <Icon icon=\"lucide:chevron-right\" width={18} height={18} />\n </button>\n </div>\n\n {/* 面包屑插槽 */}\n <div className=\"file-toolbar-breadcrumb\">\n {breadcrumbSlot || (\n breadcrumbs.length > 0 && (\n <Breadcrumb\n items={breadcrumbs}\n onNavigate={onBreadcrumbNavigate}\n />\n )\n )}\n </div>\n\n {/* 自定义内容插槽 */}\n {children && <div className=\"file-toolbar-custom\">{children}</div>}\n\n {/* 操作区 */}\n <div className=\"file-toolbar-actions\">\n {/* 搜索框 */}\n {showSearch && (\n <div className=\"file-toolbar-search\">\n <Icon icon=\"lucide:search\" width={16} height={16} className=\"file-toolbar-search-icon\" />\n <input\n type=\"text\"\n value={searchQuery}\n onChange={(e) => onSearchQueryChange?.(e.target.value)}\n placeholder=\"搜索\"\n className=\"file-toolbar-search-input\"\n />\n </div>\n )}\n\n {/* 视图切换 */}\n {showViewToggle && (\n <div className=\"file-toolbar-view-toggle\">\n <button\n onClick={() => onViewModeChange?.('grid')}\n className={`file-toolbar-button ${\n viewMode === 'grid' ? 'file-toolbar-button--active' : ''\n }`}\n title=\"网格视图\"\n >\n <Icon icon=\"lucide:layout-grid\" width={18} height={18} />\n </button>\n <button\n onClick={() => onViewModeChange?.('list')}\n className={`file-toolbar-button ${\n viewMode === 'list' ? 'file-toolbar-button--active' : ''\n }`}\n title=\"列表视图\"\n >\n <Icon icon=\"lucide:list\" width={18} height={18} />\n </button>\n </div>\n )}\n\n {/* 额外操作插槽 */}\n {actionsSlot}\n </div>\n </div>\n );\n}\n","import { Icon } from '@iconify/react';\nimport type { BreadcrumbItem } from '../types';\nimport './Breadcrumb.css';\n\ninterface BreadcrumbProps {\n items: BreadcrumbItem[];\n onNavigate?: (item: BreadcrumbItem, index: number) => void;\n}\n\nexport function Breadcrumb({ items, onNavigate }: BreadcrumbProps) {\n const handleClick = (item: BreadcrumbItem, index: number) => {\n // 点击最后一项不触发导航\n if (index < items.length - 1) {\n onNavigate?.(item, index);\n }\n };\n\n return (\n <div className=\"file-breadcrumb\">\n {items.map((item, index) => (\n <span key={item.id} className=\"file-breadcrumb-item\">\n <span\n onClick={() => handleClick(item, index)}\n className={`file-breadcrumb-link ${\n index === items.length - 1 ? 'file-breadcrumb-link--current' : ''\n }`}\n >\n {item.name}\n </span>\n {index < items.length - 1 && (\n <Icon icon=\"lucide:chevron-right\" width={14} height={14} className=\"file-breadcrumb-separator\" />\n )}\n </span>\n ))}\n </div>\n );\n}\n\n","import './StatusBar.css';\n\ninterface StatusBarProps {\n itemCount?: number;\n selectedCount?: number;\n children?: React.ReactNode;\n}\n\nexport function StatusBar({ itemCount = 0, selectedCount = 0, children }: StatusBarProps) {\n return (\n <div className=\"file-status-bar\">\n {children || (\n <>\n <span>{itemCount} 个项目</span>\n {selectedCount > 0 && <span> • 已选择 {selectedCount} 个</span>}\n </>\n )}\n </div>\n );\n}\n\n","import { createPortal } from 'react-dom';\nimport { useMemo, useEffect, useRef, useCallback, useState } from 'react';\nimport { Icon } from '@iconify/react';\nimport type { ContextMenuItem } from '../types';\nimport './ContextMenu.css';\n\ninterface ContextMenuProps {\n visible: boolean;\n x: number;\n y: number;\n options: ContextMenuItem[];\n onClose?: () => void;\n onSelect?: (option: ContextMenuItem) => void;\n}\n\n/** 边距常量 */\nconst MARGIN = 8;\n/** 菜单固定宽度 */\nconst MENU_WIDTH = 220;\n/** 菜单项高度 */\nconst MENU_ITEM_HEIGHT = 32;\n/** 分隔线高度 */\nconst SEPARATOR_HEIGHT = 9;\n/** 菜单内边距 */\nconst MENU_PADDING = 8;\n/** 子菜单与父菜单的间距 */\nconst SUBMENU_GAP = 0;\n\n/**\n * 估算菜单高度(根据菜单项数量)\n */\nfunction estimateMenuHeight(items: ContextMenuItem[]): number {\n let height = MENU_PADDING;\n for (const item of items) {\n height += item.separator ? SEPARATOR_HEIGHT : MENU_ITEM_HEIGHT;\n }\n return height;\n}\n\n/**\n * 计算自适应菜单位置\n * 使用固定宽度,只需测量高度,简化计算逻辑\n */\nfunction calculateMenuPosition(\n clickX: number,\n clickY: number,\n menuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n let adjustedX = clickX;\n let adjustedY = clickY;\n\n // 水平方向调整(使用固定宽度)\n const spaceRight = viewportWidth - clickX;\n const spaceLeft = clickX;\n\n // 如果右边空间不足,尝试在左边显示\n if (spaceRight < MENU_WIDTH + MARGIN) {\n // 左边空间足够,在左边显示\n if (spaceLeft >= MENU_WIDTH + MARGIN) {\n adjustedX = clickX - MENU_WIDTH;\n } else {\n // 左右空间都不足,选择空间更大的一边,并留出边距\n if (spaceRight > spaceLeft) {\n adjustedX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n adjustedX = MARGIN;\n }\n }\n }\n\n // 垂直方向调整\n const spaceBottom = viewportHeight - clickY;\n const spaceTop = clickY;\n\n // 如果下边空间不足,尝试在上边显示\n if (spaceBottom < menuHeight + MARGIN) {\n // 上边空间足够,在上边显示\n if (spaceTop >= menuHeight + MARGIN) {\n adjustedY = clickY - menuHeight;\n } else {\n // 上下空间都不足,选择空间更大的一边,并留出边距\n if (spaceBottom > spaceTop) {\n adjustedY = viewportHeight - menuHeight - MARGIN;\n } else {\n adjustedY = MARGIN;\n }\n }\n }\n\n // 最终边界检查,确保不会超出视口\n adjustedX = Math.max(MARGIN, Math.min(adjustedX, viewportWidth - MENU_WIDTH - MARGIN));\n adjustedY = Math.max(MARGIN, Math.min(adjustedY, viewportHeight - menuHeight - MARGIN));\n\n return { x: adjustedX, y: adjustedY };\n}\n\n/**\n * 计算二级菜单位置(Windows/Mac 标准行为:优先右侧,空间不足时左侧)\n * @param parentRect 父菜单项的边界矩形\n * @param submenuHeight 子菜单高度\n * @returns 子菜单位置\n */\nfunction calculateSubmenuPosition(\n parentRect: DOMRect,\n submenuHeight: number\n): { x: number; y: number } {\n const viewportWidth = window.innerWidth;\n const viewportHeight = window.innerHeight;\n\n // 计算可用空间\n const spaceRight = viewportWidth - parentRect.right;\n const spaceLeft = parentRect.left;\n\n let submenuX: number;\n let submenuY: number;\n\n // 水平方向:优先右侧,空间不足时左侧(Windows/Mac 标准行为)\n if (spaceRight >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧有足够空间,在右侧显示(紧贴父菜单右边缘)\n submenuX = parentRect.right + SUBMENU_GAP;\n } else if (spaceLeft >= MENU_WIDTH + SUBMENU_GAP + MARGIN) {\n // 右侧空间不足,左侧有足够空间,在左侧显示(紧贴父菜单左边缘)\n submenuX = parentRect.left - MENU_WIDTH - SUBMENU_GAP;\n } else {\n // 左右空间都不足,选择空间更大的一边\n if (spaceRight > spaceLeft) {\n submenuX = viewportWidth - MENU_WIDTH - MARGIN;\n } else {\n submenuX = MARGIN;\n }\n }\n\n // 垂直方向:与父菜单项顶部对齐(Windows/Mac 标准行为)\n submenuY = parentRect.top;\n\n // 如果子菜单底部超出视口,向上调整\n if (submenuY + submenuHeight > viewportHeight - MARGIN) {\n submenuY = viewportHeight - submenuHeight - MARGIN;\n }\n\n // 如果子菜单顶部超出视口,向下调整\n if (submenuY < MARGIN) {\n submenuY = MARGIN;\n }\n\n return { x: submenuX, y: submenuY };\n}\n\nexport function ContextMenu({\n visible,\n x,\n y,\n options,\n onClose,\n onSelect,\n}: ContextMenuProps) {\n const menuRef = useRef<HTMLDivElement>(null);\n const [hoveredItemId, setHoveredItemId] = useState<string | null>(null);\n const [submenuPosition, setSubmenuPosition] = useState<{ x: number; y: number } | null>(null);\n const itemRefs = useRef<Map<string, HTMLDivElement>>(new Map());\n\n // 使用 useMemo 在渲染前计算位置(使用估算高度,避免位置调整动画)\n const position = useMemo(() => {\n const estimatedHeight = estimateMenuHeight(options);\n return calculateMenuPosition(x, y, estimatedHeight);\n }, [x, y, options]);\n\n const menuStyle = useMemo(\n () => ({\n left: `${position.x}px`,\n top: `${position.y}px`,\n }),\n [position]\n );\n\n // 获取当前悬停项的子菜单\n const hoveredItem = useMemo(() => {\n if (!hoveredItemId) return null;\n return options.find(opt => opt.id === hoveredItemId && opt.children && opt.children.length > 0);\n }, [hoveredItemId, options]);\n\n // 计算子菜单位置\n useEffect(() => {\n if (!hoveredItemId || !hoveredItem) {\n setSubmenuPosition(null);\n return;\n }\n\n const itemEl = itemRefs.current.get(hoveredItemId);\n if (!itemEl) {\n setSubmenuPosition(null);\n return;\n }\n\n const rect = itemEl.getBoundingClientRect();\n const submenuHeight = estimateMenuHeight(hoveredItem.children || []);\n const pos = calculateSubmenuPosition(rect, submenuHeight);\n setSubmenuPosition(pos);\n }, [hoveredItemId, hoveredItem]);\n\n // 点击外部或按 ESC 键时关闭\n useEffect(() => {\n if (!visible) return;\n\n const handleClickOutside = (e: MouseEvent) => {\n const target = e.target as Node;\n \n // 检查是否点击在菜单内(包括主菜单和子菜单)\n const menuContainer = document.querySelector('.context-menu-container');\n if (menuContainer && menuContainer.contains(target)) {\n return;\n }\n\n onClose?.();\n };\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose?.();\n }\n };\n\n // 使用 mousedown 来更快响应(Windows/Mac 标准行为)\n document.addEventListener('mousedown', handleClickOutside);\n document.addEventListener('keydown', handleEscape);\n\n return () => {\n document.removeEventListener('mousedown', handleClickOutside);\n document.removeEventListener('keydown', handleEscape);\n };\n }, [visible, onClose]);\n\n // 重置状态当菜单关闭时\n useEffect(() => {\n if (!visible) {\n setHoveredItemId(null);\n setSubmenuPosition(null);\n }\n }, [visible]);\n\n // Iconify 图标渲染函数\n const renderIcon = (iconName: string) => {\n if (!iconName) return null;\n return <Icon icon={iconName} width={16} height={16} className=\"context-menu-item-icon\" />;\n };\n\n const handleOptionClick = useCallback(\n (option: ContextMenuItem) => {\n if (option.disabled) return;\n\n // 如果有子菜单,不执行 action,只显示子菜单\n if (option.children && option.children.length > 0) {\n return;\n }\n\n if (option.action) {\n option.action();\n }\n onSelect?.(option);\n onClose?.();\n },\n [onClose, onSelect]\n );\n\n // 处理菜单项鼠标进入\n const handleItemMouseEnter = useCallback((option: ContextMenuItem) => {\n if (option.children && option.children.length > 0) {\n setHoveredItemId(option.id);\n } else {\n setHoveredItemId(null);\n }\n }, []);\n\n if (!visible) return null;\n\n return createPortal(\n <div className=\"context-menu-container\">\n {/* 主菜单 - 不使用 overlay,通过 document mousedown 事件来关闭菜单 */}\n <div ref={menuRef} className=\"context-menu\" style={menuStyle}>\n {options.map((option, index) => {\n if (option.separator) {\n return <div key={index} className=\"context-menu-separator\" />;\n }\n\n const hasChildren = option.children && option.children.length > 0;\n const isHovered = hoveredItemId === option.id;\n\n return (\n <div\n key={option.id || index}\n ref={(el) => {\n if (el) {\n itemRefs.current.set(option.id, el);\n } else {\n itemRefs.current.delete(option.id);\n }\n }}\n className={`context-menu-item ${\n option.disabled ? 'context-menu-item--disabled' : ''\n } ${\n option.danger ? 'context-menu-item--danger' : ''\n } ${\n hasChildren ? 'context-menu-item--has-children' : ''\n } ${\n isHovered ? 'context-menu-item--active' : ''\n }`}\n onClick={() => handleOptionClick(option)}\n onMouseEnter={() => handleItemMouseEnter(option)}\n >\n {option.icon && renderIcon(option.icon)}\n <span className=\"context-menu-item-label\">{option.label}</span>\n {option.checked && (\n <Icon icon=\"lucide:check\" width={14} height={14} className=\"context-menu-item-check\" />\n )}\n {option.shortcut && !hasChildren && (\n <span className=\"context-menu-item-shortcut\">\n {option.shortcut}\n </span>\n )}\n {hasChildren && (\n <Icon icon=\"lucide:chevron-right\" width={14} height={14} className=\"context-menu-item-arrow\" />\n )}\n </div>\n );\n })}\n </div>\n\n {/* 二级菜单(独立渲染,避免定位问题) */}\n {hoveredItem && submenuPosition && (\n <div\n className=\"context-menu context-menu-submenu\"\n style={{\n left: `${submenuPosition.x}px`,\n top: `${submenuPosition.y}px`,\n }}\n onMouseEnter={() => setHoveredItemId(hoveredItem.id)}\n onMouseLeave={() => setHoveredItemId(null)}\n >\n {hoveredItem.children!.map((child, childIndex) => {\n if (child.separator) {\n return <div key={`child-sep-${childIndex}`} className=\"context-menu-separator\" />;\n }\n\n return (\n <div\n key={child.id || childIndex}\n className={`context-menu-item ${\n child.disabled ? 'context-menu-item--disabled' : ''\n } ${\n child.danger ? 'context-menu-item--danger' : ''\n }`}\n onClick={() => handleOptionClick(child)}\n >\n {child.icon && renderIcon(child.icon)}\n <span className=\"context-menu-item-label\">{child.label}</span>\n {child.checked && (\n <Icon icon=\"lucide:check\" width={14} height={14} className=\"context-menu-item-check\" />\n )}\n {child.shortcut && (\n <span className=\"context-menu-item-shortcut\">\n {child.shortcut}\n </span>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>,\n document.body\n );\n}\n","import { createPortal } from 'react-dom';\nimport { useMemo, useRef, useEffect, useState } from 'react';\nimport { Icon } from '@iconify/react';\nimport { useWindowDrag } from '../hooks/useWindowDrag';\nimport { useWindowResize } from '../hooks/useWindowResize';\nimport './Window.css';\n\ninterface WindowProps {\n title?: string;\n showTitleBar?: boolean;\n showMinimize?: boolean;\n showMaximize?: boolean;\n draggable?: boolean;\n resizable?: boolean;\n width?: string | number;\n height?: string | number;\n minWidth?: string | number;\n minHeight?: string | number;\n maxWidth?: string | number;\n maxHeight?: string | number;\n closeOnBackdrop?: boolean;\n fitContent?: boolean;\n onClose?: () => void;\n onMinimize?: () => void;\n onMaximize?: () => void;\n children?: React.ReactNode;\n titleSlot?: React.ReactNode;\n actionsSlot?: React.ReactNode;\n}\n\nexport function Window({\n title,\n showTitleBar = true,\n showMinimize = false,\n showMaximize = false,\n draggable = true,\n resizable = true,\n closeOnBackdrop = true,\n width = 'auto',\n height = 'auto',\n minWidth = 300,\n minHeight = 200,\n maxWidth = '80vw',\n maxHeight = '80vh',\n fitContent = false,\n onClose,\n onMinimize,\n onMaximize,\n children,\n titleSlot,\n actionsSlot,\n}: WindowProps) {\n const windowContainerRef = useRef<HTMLDivElement>(null);\n const windowDrag = draggable ? useWindowDrag() : null;\n\n /**\n * 是否使用自适应内容模式\n */\n const isAutoSize = useMemo(() => {\n return (\n fitContent ||\n width === 'auto' ||\n width === 'fit-content' ||\n height === 'auto' ||\n height === 'fit-content'\n );\n }, [fitContent, width, height]);\n\n /**\n * 计算初始尺寸\n */\n const getInitialSize = () => {\n if (isAutoSize) {\n return { initialWidth: 0, initialHeight: 0 };\n }\n\n const defaultWidth = 600;\n const defaultHeight = 500;\n\n let initialWidth = defaultWidth;\n let initialHeight = defaultHeight;\n\n if (width !== 'auto' && width !== 'fit-content') {\n initialWidth =\n typeof width === 'number' ? width : parseInt(width as string);\n }\n if (height !== 'auto' && height !== 'fit-content') {\n initialHeight =\n typeof height === 'number' ? height : parseInt(height as string);\n }\n\n return { initialWidth, initialHeight };\n };\n\n /**\n * 解析尺寸限制\n */\n const parseSize = (size: string | number, defaultPx: number): number => {\n if (typeof size === 'number') return size;\n if (typeof size === 'string') {\n if (size.endsWith('px')) return parseInt(size);\n if (size.endsWith('vw'))\n return (parseInt(size) / 100) * window.innerWidth;\n if (size.endsWith('vh'))\n return (parseInt(size) / 100) * window.innerHeight;\n }\n return defaultPx;\n };\n\n const { initialWidth, initialHeight } = getInitialSize();\n const minW = parseSize(minWidth, 500);\n const minH = parseSize(minHeight, 350);\n const maxW = parseSize(maxWidth, window.innerWidth * 0.8);\n const maxH = parseSize(maxHeight, window.innerHeight * 0.8);\n\n const windowResize = resizable\n ? useWindowResize(initialWidth, initialHeight, minW, minH, maxW, maxH)\n : null;\n\n const windowStyle = useMemo(() => {\n const baseStyle: React.CSSProperties = {\n left: '50%',\n top: '50%',\n };\n\n let translateX = '-50%';\n let translateY = '-50%';\n\n if (draggable && windowDrag) {\n translateX = `calc(-50% + ${windowDrag.position.x}px)`;\n translateY = `calc(-50% + ${windowDrag.position.y}px)`;\n }\n\n baseStyle.transform = `translate(${translateX}, ${translateY})`;\n baseStyle.transformOrigin = 'center center';\n\n if (isAutoSize) {\n if (resizable && windowResize && windowResize.width > 0) {\n baseStyle.width = `${windowResize.width}px`;\n baseStyle.height = `${windowResize.height}px`;\n }\n } else {\n if (resizable && windowResize) {\n baseStyle.width = `${windowResize.width}px`;\n baseStyle.height = `${windowResize.height}px`;\n } else {\n if (width !== 'auto' && width !== 'fit-content') {\n baseStyle.width =\n typeof width === 'number' ? `${width}px` : (width as string);\n }\n if (height !== 'auto' && height !== 'fit-content') {\n baseStyle.height =\n typeof height === 'number' ? `${height}px` : (height as string);\n }\n }\n }\n\n if (minWidth) {\n baseStyle.minWidth =\n typeof minWidth === 'number' ? `${minWidth}px` : (minWidth as string);\n }\n if (minHeight) {\n baseStyle.minHeight =\n typeof minHeight === 'number'\n ? `${minHeight}px`\n : (minHeight as string);\n }\n if (maxWidth) {\n baseStyle.maxWidth =\n typeof maxWidth === 'number' ? `${maxWidth}px` : (maxWidth as string);\n }\n if (maxHeight) {\n baseStyle.maxHeight =\n typeof maxHeight === 'number'\n ? `${maxHeight}px`\n : (maxHeight as string);\n }\n\n return baseStyle;\n }, [\n draggable,\n windowDrag,\n isAutoSize,\n resizable,\n windowResize,\n width,\n height,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n ]);\n\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (closeOnBackdrop && e.target === e.currentTarget) {\n onClose?.();\n }\n };\n\n const handleDragStart = (e: React.MouseEvent) => {\n if (draggable && windowDrag) {\n windowDrag.startDrag(e);\n }\n };\n\n const handleResizeStart = (\n e: React.MouseEvent,\n direction: 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw'\n ) => {\n if (!resizable || !windowResize || !windowContainerRef.current) return;\n\n const rect = windowContainerRef.current.getBoundingClientRect();\n const currentWidth = rect.width;\n const currentHeight = rect.height;\n\n windowResize.startResize(e, direction, currentWidth, currentHeight);\n };\n\n /**\n * ESC 键关闭\n */\n useEffect(() => {\n const handleEsc = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClose?.();\n }\n };\n window.addEventListener('keydown', handleEsc);\n return () => {\n window.removeEventListener('keydown', handleEsc);\n };\n }, [onClose]);\n\n return createPortal(\n <div className=\"window-overlay\" onClick={handleBackdropClick}>\n <div\n ref={windowContainerRef}\n className=\"window-container\"\n style={windowStyle}\n onClick={(e) => e.stopPropagation()}\n >\n {/* Title Bar */}\n {showTitleBar && (\n <div\n className=\"window-title-bar draggable-area\"\n onMouseDown={handleDragStart}\n >\n <div className=\"window-controls\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n onClose?.();\n }}\n className=\"window-control-button window-control-button--close\"\n >\n <Icon icon=\"lucide:x\" width={7} height={7} className=\"window-control-icon\" />\n </button>\n {showMinimize && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onMinimize?.();\n }}\n className=\"window-control-button window-control-button--minimize\"\n >\n <Icon icon=\"lucide:minus\" width={7} height={7} className=\"window-control-icon\" />\n </button>\n )}\n {showMaximize && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onMaximize?.();\n }}\n className=\"window-control-button window-control-button--maximize\"\n >\n <Icon icon=\"lucide:maximize-2\" width={7} height={7} className=\"window-control-icon\" />\n </button>\n )}\n </div>\n\n <div className=\"window-title-info\">\n {titleSlot || <span className=\"window-title-text\">{title}</span>}\n </div>\n\n <div className=\"window-title-actions\">{actionsSlot}</div>\n </div>\n )}\n\n {/* Content */}\n <div className=\"window-content\">{children}</div>\n\n {/* Resize Handles */}\n {resizable && (\n <>\n <div\n className=\"window-resize-handle window-resize-handle--n\"\n onMouseDown={(e) => handleResizeStart(e, 'n')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--s\"\n onMouseDown={(e) => handleResizeStart(e, 's')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--e\"\n onMouseDown={(e) => handleResizeStart(e, 'e')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--w\"\n onMouseDown={(e) => handleResizeStart(e, 'w')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--ne\"\n onMouseDown={(e) => handleResizeStart(e, 'ne')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--nw\"\n onMouseDown={(e) => handleResizeStart(e, 'nw')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--se\"\n onMouseDown={(e) => handleResizeStart(e, 'se')}\n ></div>\n <div\n className=\"window-resize-handle window-resize-handle--sw\"\n onMouseDown={(e) => handleResizeStart(e, 'sw')}\n ></div>\n </>\n )}\n </div>\n </div>,\n document.body\n );\n}\n","import { useState, useCallback, useEffect } from 'react';\n\n/**\n * 窗口拖拽功能管理\n */\nexport function useWindowDrag() {\n const [position, setPosition] = useState({ x: 0, y: 0 });\n const [isDragging, setIsDragging] = useState(false);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (!isDragging) return;\n setPosition(prev => ({\n x: prev.x + e.movementX,\n y: prev.y + e.movementY\n }));\n }, [isDragging]);\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = useCallback(() => {\n setIsDragging(false);\n }, []);\n\n /**\n * 开始拖拽\n */\n const startDrag = useCallback((e: React.MouseEvent) => {\n const target = e.target as HTMLElement;\n // 检查是否点击在可拖拽区域,但排除按钮\n if (target.closest('.draggable-area') && !target.closest('button')) {\n e.preventDefault();\n setIsDragging(true);\n }\n }, []);\n\n /**\n * 监听拖拽状态变化\n */\n useEffect(() => {\n if (isDragging) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n };\n }\n }, [isDragging, handleMouseMove, handleMouseUp]);\n\n return {\n position,\n isDragging,\n startDrag\n };\n}\n\n","import { useState, useCallback, useEffect } from 'react';\n\ntype ResizeDirection = 'n' | 's' | 'e' | 'w' | 'ne' | 'nw' | 'se' | 'sw';\n\n/**\n * 窗口调整大小功能管理\n */\nexport function useWindowResize(\n initialWidth: number,\n initialHeight: number,\n minWidth: number,\n minHeight: number,\n maxWidth: number,\n maxHeight: number\n) {\n const [width, setWidth] = useState(initialWidth);\n const [height, setHeight] = useState(initialHeight);\n const [isResizing, setIsResizing] = useState(false);\n const [resizeDirection, setResizeDirection] = useState<ResizeDirection | null>(null);\n const [startX, setStartX] = useState(0);\n const [startY, setStartY] = useState(0);\n const [startWidth, setStartWidth] = useState(0);\n const [startHeight, setStartHeight] = useState(0);\n\n /**\n * 鼠标移动处理\n */\n const handleMouseMove = useCallback((e: MouseEvent) => {\n if (!isResizing || !resizeDirection) return;\n\n const deltaX = e.clientX - startX;\n const deltaY = e.clientY - startY;\n\n let newWidth = startWidth;\n let newHeight = startHeight;\n\n const direction = resizeDirection;\n\n // 处理水平方向\n if (direction.includes('e')) {\n newWidth = Math.min(Math.max(startWidth + deltaX, minWidth), maxWidth);\n } else if (direction.includes('w')) {\n newWidth = Math.min(Math.max(startWidth - deltaX, minWidth), maxWidth);\n }\n\n // 处理垂直方向\n if (direction.includes('s')) {\n newHeight = Math.min(Math.max(startHeight + deltaY, minHeight), maxHeight);\n } else if (direction.includes('n')) {\n newHeight = Math.min(Math.max(startHeight - deltaY, minHeight), maxHeight);\n }\n\n setWidth(newWidth);\n setHeight(newHeight);\n }, [isResizing, resizeDirection, startX, startY, startWidth, startHeight, minWidth, minHeight, maxWidth, maxHeight]);\n\n /**\n * 鼠标释放处理\n */\n const handleMouseUp = useCallback(() => {\n setIsResizing(false);\n setResizeDirection(null);\n }, []);\n\n /**\n * 开始调整大小\n */\n const startResize = useCallback((\n e: React.MouseEvent,\n direction: ResizeDirection,\n currentWidth: number,\n currentHeight: number\n ) => {\n e.preventDefault();\n e.stopPropagation();\n setIsResizing(true);\n setResizeDirection(direction);\n setStartX(e.clientX);\n setStartY(e.clientY);\n setStartWidth(currentWidth);\n setStartHeight(currentHeight);\n }, []);\n\n /**\n * 获取对应方向的鼠标样式\n */\n const getCursorForDirection = useCallback((direction: ResizeDirection): string => {\n const cursors: Record<ResizeDirection, string> = {\n n: 'n-resize',\n s: 's-resize',\n e: 'e-resize',\n w: 'w-resize',\n ne: 'ne-resize',\n nw: 'nw-resize',\n se: 'se-resize',\n sw: 'sw-resize'\n };\n return cursors[direction];\n }, []);\n\n /**\n * 监听调整大小状态变化\n */\n useEffect(() => {\n if (isResizing) {\n window.addEventListener('mousemove', handleMouseMove);\n window.addEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = getCursorForDirection(resizeDirection || 'se');\n document.body.style.userSelect = 'none';\n return () => {\n window.removeEventListener('mousemove', handleMouseMove);\n window.removeEventListener('mouseup', handleMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n };\n }\n }, [isResizing, resizeDirection, handleMouseMove, handleMouseUp, getCursorForDirection]);\n\n return {\n width,\n height,\n isResizing,\n startResize\n };\n}\n\n","import { useState, useMemo, useEffect } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Icon } from '@iconify/react';\nimport './CompressDialog.css';\nimport type { CompressFormat, CompressLevel, CompressOptions } from '../types';\n\ntype CompressDialogOptions = Omit<CompressOptions, 'outputDir'>;\n\ninterface CompressDialogProps {\n visible: boolean;\n /** 要压缩的文件/文件夹路径列表 */\n filePaths: string[];\n /** 输出目录 */\n outputDir: string;\n onConfirm: (options: CompressDialogOptions) => void;\n onCancel: () => void;\n}\n\n/** 格式选项配置 */\nconst FORMAT_OPTIONS: { value: CompressFormat; label: string; ext: string }[] = [\n { value: 'zip', label: 'ZIP', ext: '.zip' },\n { value: 'tgz', label: 'TAR.GZ (gzip)', ext: '.tar.gz' },\n { value: 'tarbz2', label: 'TAR.BZ2 (bzip2)', ext: '.tar.bz2' },\n { value: 'tar', label: 'TAR (无压缩)', ext: '.tar' },\n];\n\n/** 压缩级别选项 */\nconst LEVEL_OPTIONS: { value: CompressLevel; label: string; desc: string }[] = [\n { value: 'fast', label: '快速', desc: '压缩速度快,文件较大' },\n { value: 'normal', label: '标准', desc: '平衡速度和大小' },\n { value: 'best', label: '最佳', desc: '文件最小,速度较慢' },\n];\n\n/**\n * 压缩对话框组件\n */\nexport function CompressDialog({\n visible,\n filePaths,\n outputDir,\n onConfirm,\n onCancel,\n}: CompressDialogProps) {\n const [format, setFormat] = useState<CompressFormat>('zip');\n const [level, setLevel] = useState<CompressLevel>('normal');\n const [outputName, setOutputName] = useState('');\n const [deleteSource, setDeleteSource] = useState(false);\n const [password, setPassword] = useState('');\n const [showPassword, setShowPassword] = useState(false);\n\n // 根据选中文件生成默认输出名称\n const defaultOutputName = useMemo(() => {\n if (filePaths.length === 0) return 'archive';\n if (filePaths.length === 1) {\n const name = filePaths[0].split('/').pop() || 'archive';\n // 移除扩展名\n return name.replace(/\\.[^.]+$/, '');\n }\n return '压缩文件';\n }, [filePaths]);\n\n // 初始化输出名称\n useEffect(() => {\n if (visible) {\n setOutputName(defaultOutputName);\n setFormat('zip');\n setLevel('normal');\n setDeleteSource(false);\n setPassword('');\n }\n }, [visible, defaultOutputName]);\n\n // 获取当前格式的扩展名\n const currentExt = FORMAT_OPTIONS.find(f => f.value === format)?.ext || '.zip';\n\n // 完整输出路径预览\n const fullOutputPath = `${outputDir}/${outputName}${currentExt}`;\n\n const handleConfirm = () => {\n onConfirm({\n format,\n level,\n outputName: outputName + currentExt,\n deleteSource,\n });\n };\n\n // 当前后端未实现密码压缩,避免 UI 误导:直接关闭密码选项\n const supportsPassword = false;\n\n if (!visible) return null;\n\n return createPortal(\n <div className=\"compress-dialog-overlay\" onClick={onCancel}>\n <div className=\"compress-dialog\" onClick={e => e.stopPropagation()}>\n {/* 头部 */}\n <div className=\"compress-dialog-header\">\n <div className=\"compress-dialog-title\">\n <Icon icon=\"lucide:archive\" width={20} height={20} />\n <span>压缩文件</span>\n </div>\n <button className=\"compress-dialog-close\" onClick={onCancel}>\n <Icon icon=\"lucide:x\" width={18} height={18} />\n </button>\n </div>\n\n {/* 内容 */}\n <div className=\"compress-dialog-content\">\n {/* 文件信息 */}\n <div className=\"compress-dialog-info\">\n <Icon icon=\"lucide:file-archive\" width={16} height={16} />\n <span>\n {filePaths.length === 1 \n ? filePaths[0].split('/').pop() \n : `${filePaths.length} 个项目`}\n </span>\n </div>\n\n {/* 输出文件名 */}\n <div className=\"compress-dialog-field\">\n <label>文件名</label>\n <div className=\"compress-dialog-input-group\">\n <input\n type=\"text\"\n value={outputName}\n onChange={e => setOutputName(e.target.value)}\n placeholder=\"输入文件名\"\n />\n <span className=\"compress-dialog-ext\">{currentExt}</span>\n </div>\n </div>\n\n {/* 压缩格式 */}\n <div className=\"compress-dialog-field\">\n <label>压缩格式</label>\n <select value={format} onChange={e => setFormat(e.target.value as CompressFormat)}>\n {FORMAT_OPTIONS.map(opt => (\n <option key={opt.value} value={opt.value}>{opt.label}</option>\n ))}\n </select>\n </div>\n\n {/* 压缩级别 */}\n <div className=\"compress-dialog-field\">\n <label>压缩级别</label>\n <div className=\"compress-dialog-levels\">\n {LEVEL_OPTIONS.map(opt => (\n <label key={opt.value} className=\"compress-dialog-level\">\n <input\n type=\"radio\"\n name=\"level\"\n value={opt.value}\n checked={level === opt.value}\n onChange={() => setLevel(opt.value)}\n />\n <span className=\"compress-dialog-level-label\">{opt.label}</span>\n <span className=\"compress-dialog-level-desc\">{opt.desc}</span>\n </label>\n ))}\n </div>\n </div>\n\n {/* 密码保护(仅 zip/7z) */}\n {supportsPassword && (\n <div className=\"compress-dialog-field\">\n <label>密码保护(可选)</label>\n <div className=\"compress-dialog-input-group\">\n <input\n type={showPassword ? 'text' : 'password'}\n value={password}\n onChange={e => setPassword(e.target.value)}\n placeholder=\"设置密码\"\n />\n <button\n type=\"button\"\n className=\"compress-dialog-toggle-password\"\n onClick={() => setShowPassword(!showPassword)}\n >\n {showPassword ? '隐藏' : '显示'}\n </button>\n </div>\n </div>\n )}\n\n {/* 删除源文件选项 */}\n <div className=\"compress-dialog-field compress-dialog-checkbox\">\n <label>\n <input\n type=\"checkbox\"\n checked={deleteSource}\n onChange={e => setDeleteSource(e.target.checked)}\n />\n <span>压缩后删除源文件</span>\n </label>\n </div>\n\n {/* 输出路径预览 */}\n <div className=\"compress-dialog-preview\">\n <span className=\"compress-dialog-preview-label\">输出位置:</span>\n <span className=\"compress-dialog-preview-path\">{fullOutputPath}</span>\n </div>\n </div>\n\n {/* 底部按钮 */}\n <div className=\"compress-dialog-footer\">\n <button className=\"compress-dialog-btn compress-dialog-btn-cancel\" onClick={onCancel}>\n 取消\n </button>\n <button \n className=\"compress-dialog-btn compress-dialog-btn-confirm\" \n onClick={handleConfirm}\n disabled={!outputName.trim()}\n >\n 压缩\n </button>\n </div>\n </div>\n </div>,\n document.body\n );\n}\n\n","import { createPortal } from 'react-dom';\nimport { Icon } from '@iconify/react';\nimport './ProgressDialog.css';\n\n/** 进度状态 */\nexport type ProgressStatus = 'pending' | 'processing' | 'success' | 'error';\n\n/** 进度信息 */\nexport interface ProgressInfo {\n /** 操作类型 */\n type: 'compress' | 'extract';\n /** 状态 */\n status: ProgressStatus;\n /** 进度百分比 0-100 */\n percent: number;\n /** 当前处理的文件 */\n currentFile?: string;\n /** 已处理文件数 */\n processedCount?: number;\n /** 总文件数 */\n totalCount?: number;\n /** 错误信息 */\n error?: string;\n /** 输出路径 */\n outputPath?: string;\n}\n\ninterface ProgressDialogProps {\n visible: boolean;\n progress: ProgressInfo;\n onCancel?: () => void;\n onClose?: () => void;\n /** 打开输出文件夹 */\n onOpenFolder?: (path: string) => void;\n}\n\n/**\n * 进度对话框组件\n */\nexport function ProgressDialog({\n visible,\n progress,\n onCancel,\n onClose,\n onOpenFolder,\n}: ProgressDialogProps) {\n const { type, status, percent, currentFile, processedCount, totalCount, error, outputPath } = progress;\n \n const title = type === 'compress' ? '压缩文件' : '解压文件';\n const isCompleted = status === 'success' || status === 'error';\n\n // 获取状态图标\n const StatusIcon = () => {\n switch (status) {\n case 'processing':\n return <Icon icon=\"lucide:loader-2\" width={24} height={24} className=\"progress-dialog-icon-spin\" />;\n case 'success':\n return <Icon icon=\"lucide:check-circle\" width={24} height={24} className=\"progress-dialog-icon-success\" />;\n case 'error':\n return <Icon icon=\"lucide:x-circle\" width={24} height={24} className=\"progress-dialog-icon-error\" />;\n default:\n return <Icon icon=\"lucide:archive\" width={24} height={24} />;\n }\n };\n\n // 获取状态文本\n const getStatusText = () => {\n switch (status) {\n case 'pending':\n return '准备中...';\n case 'processing':\n return type === 'compress' ? '正在压缩...' : '正在解压...';\n case 'success':\n return type === 'compress' ? '压缩完成' : '解压完成';\n case 'error':\n return '操作失败';\n default:\n return '';\n }\n };\n\n const handleClose = () => {\n if (isCompleted) {\n onClose?.();\n } else {\n onCancel?.();\n }\n };\n\n if (!visible) return null;\n\n return createPortal(\n <div className=\"progress-dialog-overlay\">\n <div className=\"progress-dialog\">\n {/* 头部 */}\n <div className=\"progress-dialog-header\">\n <div className=\"progress-dialog-title\">\n <StatusIcon />\n <span>{title}</span>\n </div>\n {isCompleted && (\n <button className=\"progress-dialog-close\" onClick={handleClose}>\n <Icon icon=\"lucide:x\" width={18} height={18} />\n </button>\n )}\n </div>\n\n {/* 内容 */}\n <div className=\"progress-dialog-content\">\n {/* 状态文本 */}\n <div className=\"progress-dialog-status\">{getStatusText()}</div>\n\n {/* 进度条 */}\n {status === 'processing' && (\n <div className=\"progress-dialog-bar-container\">\n <div className=\"progress-dialog-bar\">\n <div \n className=\"progress-dialog-bar-fill\"\n style={{ width: `${percent}%` }}\n />\n </div>\n <span className=\"progress-dialog-percent\">{percent}%</span>\n </div>\n )}\n\n {/* 当前文件 */}\n {currentFile && status === 'processing' && (\n <div className=\"progress-dialog-current-file\">\n {currentFile}\n </div>\n )}\n\n {/* 文件计数 */}\n {totalCount && totalCount > 0 && status === 'processing' && (\n <div className=\"progress-dialog-count\">\n {processedCount || 0} / {totalCount} 个文件\n </div>\n )}\n\n {/* 错误信息 */}\n {error && (\n <div className=\"progress-dialog-error\">\n {error}\n </div>\n )}\n\n {/* 成功后显示输出路径 */}\n {status === 'success' && outputPath && (\n <div className=\"progress-dialog-output\">\n <span className=\"progress-dialog-output-label\">输出位置:</span>\n <span className=\"progress-dialog-output-path\">{outputPath}</span>\n </div>\n )}\n </div>\n\n {/* 底部按钮 */}\n <div className=\"progress-dialog-footer\">\n {status === 'processing' && onCancel && (\n <button className=\"progress-dialog-btn progress-dialog-btn-cancel\" onClick={onCancel}>\n 取消\n </button>\n )}\n {status === 'success' && outputPath && onOpenFolder && (\n <button \n className=\"progress-dialog-btn progress-dialog-btn-folder\" \n onClick={() => onOpenFolder(outputPath)}\n >\n <Icon icon=\"lucide:folder-open\" width={16} height={16} />\n 打开文件夹\n </button>\n )}\n {isCompleted && (\n <button className=\"progress-dialog-btn progress-dialog-btn-close\" onClick={handleClose}>\n 关闭\n </button>\n )}\n </div>\n </div>\n </div>,\n document.body\n );\n}\n\n","/**\n * FileInfoDialog - 文件信息弹窗组件\n * \n * 显示文件/文件夹的详细信息\n */\n\nimport React from 'react';\nimport { Icon } from '@iconify/react';\nimport { FileItem, FileType } from '../types';\nimport { getFileTypeIcon } from '../utils/fileTypeIcon';\nimport './FileInfoDialog.css';\n\nexport interface FileInfoDialogProps {\n /** 是否显示 */\n visible: boolean;\n /** 文件项 */\n item: FileItem | null;\n /** 关闭回调 */\n onClose: () => void;\n}\n\n/** 获取文件类型图标 */\nfunction getFileIcon(type: FileType, name?: string) {\n // 文件夹使用 material-icon-theme:folder\n if (type === FileType.FOLDER) {\n return <Icon icon=\"flat-color-icons:folder\" width={48} height={48} className=\"file-info-icon\" />;\n }\n \n // 如果有文件名,使用 material-icon-theme 图标映射(传递 type 作为兜底)\n if (name) {\n const iconName = getFileTypeIcon(name, type);\n return <Icon icon={iconName} width={48} height={48} className=\"file-info-icon\" />;\n }\n \n // 回退逻辑(没有文件名时)\n const iconMap: Partial<Record<FileType, string>> = {\n [FileType.IMAGE]: 'material-icon-theme:image',\n [FileType.VIDEO]: 'material-icon-theme:video',\n [FileType.MUSIC]: 'material-icon-theme:audio',\n [FileType.DOCUMENT]: 'material-icon-theme:word',\n [FileType.CODE]: 'material-icon-theme:javascript',\n [FileType.ARCHIVE]: 'material-icon-theme:zip',\n [FileType.PDF]: 'material-icon-theme:pdf',\n [FileType.TEXT]: 'material-icon-theme:document',\n [FileType.APPLICATION]: 'material-icon-theme:exe',\n };\n \n const iconName = iconMap[type] || 'material-icon-theme:document';\n return <Icon icon={iconName} width={48} height={48} className=\"file-info-icon\" />;\n}\n\n/** 获取文件类型名称 */\nfunction getFileTypeName(type: FileType, extension?: string): string {\n switch (type) {\n case FileType.FOLDER:\n return '文件夹';\n case FileType.IMAGE:\n return `图片${extension ? ` (${extension.toUpperCase()})` : ''}`;\n case FileType.VIDEO:\n return `视频${extension ? ` (${extension.toUpperCase()})` : ''}`;\n case FileType.MUSIC:\n return `音频${extension ? ` (${extension.toUpperCase()})` : ''}`;\n case FileType.DOCUMENT:\n return `文档${extension ? ` (${extension.toUpperCase()})` : ''}`;\n case FileType.CODE:\n return `代码文件${extension ? ` (${extension.toUpperCase()})` : ''}`;\n case FileType.ARCHIVE:\n return `压缩包${extension ? ` (${extension.toUpperCase()})` : ''}`;\n default:\n return extension ? `${extension.toUpperCase()} 文件` : '文件';\n }\n}\n\n/** 获取文件扩展名 */\nfunction getExtension(filename: string): string | undefined {\n const lastDot = filename.lastIndexOf('.');\n if (lastDot === -1 || lastDot === 0) return undefined;\n return filename.substring(lastDot + 1).toLowerCase();\n}\n\n/** 获取文件所在目录 */\nfunction getDirectory(path: string): string {\n const lastSlash = path.lastIndexOf('/');\n if (lastSlash === -1) return path;\n return path.substring(0, lastSlash) || '/';\n}\n\nexport function FileInfoDialog({ visible, item, onClose }: FileInfoDialogProps) {\n if (!visible || !item) return null;\n\n const extension = getExtension(item.name);\n const directory = getDirectory(item.id);\n\n // 点击背景关闭\n const handleBackdropClick = (e: React.MouseEvent) => {\n if (e.target === e.currentTarget) {\n onClose();\n }\n };\n\n // ESC 关闭\n React.useEffect(() => {\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n if (visible) {\n document.addEventListener('keydown', handleKeyDown);\n }\n return () => document.removeEventListener('keydown', handleKeyDown);\n }, [visible, onClose]);\n\n return (\n <div className=\"file-info-dialog-overlay\" onClick={handleBackdropClick}>\n <div className=\"file-info-dialog\">\n {/* 头部 */}\n <div className=\"file-info-dialog-header\">\n <div className=\"file-info-dialog-title\">\n {getFileIcon(item.type, item.name)}\n <span className=\"file-info-dialog-name\" title={item.name}>\n {item.name}\n </span>\n </div>\n <button className=\"file-info-dialog-close\" onClick={onClose}>\n <Icon icon=\"lucide:x\" width={18} height={18} />\n </button>\n </div>\n\n {/* 内容 */}\n <div className=\"file-info-dialog-content\">\n {/* 类型 */}\n <div className=\"file-info-row\">\n <div className=\"file-info-label\">\n <Icon icon=\"lucide:file\" width={14} height={14} />\n <span>类型</span>\n </div>\n <div className=\"file-info-value\">\n {getFileTypeName(item.type, extension)}\n </div>\n </div>\n\n {/* 大小 */}\n {item.type !== FileType.FOLDER && item.size && (\n <div className=\"file-info-row\">\n <div className=\"file-info-label\">\n <Icon icon=\"lucide:hard-drive\" width={14} height={14} />\n <span>大小</span>\n </div>\n <div className=\"file-info-value\">\n {item.size}\n </div>\n </div>\n )}\n\n {/* 位置 */}\n <div className=\"file-info-row\">\n <div className=\"file-info-label\">\n <Icon icon=\"lucide:map-pin\" width={14} height={14} />\n <span>位置</span>\n </div>\n <div className=\"file-info-value file-info-value--path\" title={directory}>\n {directory}\n </div>\n </div>\n\n {/* 完整路径 */}\n <div className=\"file-info-row\">\n <div className=\"file-info-label\">\n <Icon icon=\"lucide:map-pin\" width={14} height={14} />\n <span>完整路径</span>\n </div>\n <div className=\"file-info-value file-info-value--path\" title={item.id}>\n {item.id}\n </div>\n </div>\n\n {/* 修改时间 */}\n {item.dateModified && (\n <div className=\"file-info-row\">\n <div className=\"file-info-label\">\n <Icon icon=\"lucide:clock\" width={14} height={14} />\n <span>修改时间</span>\n </div>\n <div className=\"file-info-value\">\n {item.dateModified}\n </div>\n </div>\n )}\n </div>\n\n {/* 底部按钮 */}\n <div className=\"file-info-dialog-footer\">\n <button className=\"file-info-dialog-btn\" onClick={onClose}>\n 关闭\n </button>\n </div>\n </div>\n </div>\n );\n}\n\n","import { useState, useCallback } from 'react';\nimport type { FileItem } from '../types';\n\n/**\n * 文件选择状态管理\n */\nexport function useSelection() {\n const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());\n const [lastSelectedId, setLastSelectedId] = useState<string | null>(null);\n const [editingId, setEditingId] = useState<string | null>(null);\n\n /**\n * 清除选择\n */\n const clearSelection = useCallback(() => {\n setSelectedIds(new Set());\n setLastSelectedId(null);\n }, []);\n\n /**\n * 选择项目\n * @param id 项目 ID(null 表示清除选择)\n * @param items 当前显示的项目列表\n * @param multi 是否多选(Cmd/Ctrl)\n * @param range 是否范围选择(Shift)\n */\n const selectItem = useCallback((\n id: string | null, \n items: FileItem[],\n multi: boolean = false, \n range: boolean = false\n ) => {\n if (!id) {\n clearSelection();\n return;\n }\n\n setSelectedIds(prev => {\n setLastSelectedId(prevLast => {\n // 范围选择\n if (range && prevLast) {\n const indexA = items.findIndex(i => i.id === prevLast);\n const indexB = items.findIndex(i => i.id === id);\n \n if (indexA !== -1 && indexB !== -1) {\n const start = Math.min(indexA, indexB);\n const end = Math.max(indexA, indexB);\n const newSet = new Set(multi ? prev : []);\n for (let i = start; i <= end; i++) {\n const item = items[i];\n if (item) {\n newSet.add(item.id);\n }\n }\n setSelectedIds(newSet);\n return id;\n }\n }\n\n // 多选切换\n if (multi) {\n const newSet = new Set(prev);\n if (newSet.has(id)) {\n newSet.delete(id);\n } else {\n newSet.add(id);\n }\n setSelectedIds(newSet);\n return id;\n }\n\n // 单选\n setSelectedIds(new Set([id]));\n return id;\n });\n return prev;\n });\n }, [clearSelection]);\n\n /**\n * 全选\n */\n const selectAll = useCallback((items: FileItem[]) => {\n setSelectedIds(new Set(items.map(i => i.id)));\n }, []);\n\n /**\n * 设置编辑状态\n */\n const setEditing = useCallback((id: string | null) => {\n setEditingId(id);\n }, []);\n\n /**\n * 检查是否选中\n */\n const isSelected = useCallback((id: string): boolean => {\n return selectedIds.has(id);\n }, [selectedIds]);\n\n return {\n selectedIds,\n lastSelectedId,\n editingId,\n clearSelection,\n selectItem,\n selectAll,\n setEditing,\n isSelected\n };\n}\n\n","import { useState, useCallback } from 'react';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n/**\n * 拖拽操作管理\n */\nexport function useDragAndDrop(\n getSelectedIds: () => Set<string>,\n onSelect: (id: string, multi: boolean, range: boolean) => void,\n onMove: (targetFolderId: string, itemIds: Set<string>) => void\n) {\n const [dragOverId, setDragOverId] = useState<string | null>(null);\n const [isDragging, setIsDragging] = useState(false);\n\n /**\n * 开始拖拽\n */\n const handleDragStart = useCallback((e: React.DragEvent, itemId: string) => {\n if (!e.dataTransfer) return;\n \n const selectedIds = getSelectedIds();\n \n // 如果拖拽的项目未被选中,先选中它\n if (!selectedIds.has(itemId)) {\n onSelect(itemId, false, false);\n }\n\n // 设置拖拽数据\n const draggedIds = selectedIds.has(itemId) ? selectedIds : new Set([itemId]);\n e.dataTransfer.setData('text/plain', JSON.stringify([...draggedIds]));\n e.dataTransfer.effectAllowed = 'move';\n \n setIsDragging(true);\n }, [getSelectedIds, onSelect]);\n\n /**\n * 拖拽经过\n */\n const handleDragOver = useCallback((e: React.DragEvent, item: FileItem) => {\n if (!isDragging) return;\n \n // 只有文件夹可以作为放置目标\n if (item.type === FileType.FOLDER) {\n const selectedIds = getSelectedIds();\n // 不能拖拽到自己身上\n if (!selectedIds.has(item.id)) {\n e.preventDefault();\n setDragOverId(item.id);\n }\n }\n }, [isDragging, getSelectedIds]);\n\n /**\n * 拖拽离开\n */\n const handleDragLeave = useCallback(() => {\n setDragOverId(null);\n }, []);\n\n /**\n * 放置\n */\n const handleDrop = useCallback((e: React.DragEvent, targetItem: FileItem) => {\n setDragOverId(null);\n setIsDragging(false);\n\n if (!e.dataTransfer || targetItem.type !== FileType.FOLDER) return;\n\n const data = e.dataTransfer.getData('text/plain');\n if (!data) return;\n\n try {\n const draggedIds: string[] = JSON.parse(data);\n const itemIds = new Set(draggedIds);\n \n // 不能移动到自己\n if (itemIds.has(targetItem.id)) return;\n \n onMove(targetItem.id, itemIds);\n } catch {\n // 忽略解析错误\n }\n }, [onMove]);\n\n /**\n * 拖拽结束\n */\n const handleDragEnd = useCallback(() => {\n setDragOverId(null);\n setIsDragging(false);\n }, []);\n\n return {\n dragOverId,\n isDragging,\n handleDragStart,\n handleDragOver,\n handleDragLeave,\n handleDrop,\n handleDragEnd\n };\n}\n\n","import { useState, useCallback, useEffect, useRef } from 'react';\nimport { FileType } from '../types';\n\n/**\n * 媒体播放器功能管理\n */\nexport function useMediaPlayer(\n mediaType: FileType,\n mediaRef: React.RefObject<HTMLVideoElement | HTMLAudioElement>\n) {\n const [isPlaying, setIsPlaying] = useState(false);\n const [progress, setProgress] = useState(0);\n const [currentTime, setCurrentTime] = useState(0);\n const [duration, setDuration] = useState(0);\n const [isMuted, setIsMuted] = useState(false);\n const [volume, setVolume] = useState(1);\n const [lastVolume, setLastVolume] = useState(1);\n const [showControls, setShowControls] = useState(false);\n\n const isAudio = mediaType === FileType.MUSIC;\n\n /**\n * 更新播放进度\n */\n const updateProgress = useCallback(() => {\n const media = mediaRef.current;\n if (media) {\n const curr = media.currentTime;\n const dur = media.duration;\n setCurrentTime(curr);\n if (dur && !isNaN(dur)) {\n setDuration(dur);\n setProgress((curr / dur) * 100);\n }\n }\n }, [mediaRef]);\n\n /**\n * 切换播放/暂停\n */\n const togglePlay = useCallback(() => {\n const media = mediaRef.current;\n if (media) {\n if (isPlaying) {\n media.pause();\n setIsPlaying(false);\n } else {\n media.play();\n setIsPlaying(true);\n }\n }\n }, [isPlaying, mediaRef]);\n\n /**\n * 切换静音\n */\n const toggleMute = useCallback(() => {\n const media = mediaRef.current;\n if (media) {\n if (isMuted) {\n const volToRestore = lastVolume || 1;\n media.volume = volToRestore;\n media.muted = false;\n setVolume(volToRestore);\n setIsMuted(false);\n } else {\n setLastVolume(volume);\n media.volume = 0;\n media.muted = true;\n setVolume(0);\n setIsMuted(true);\n }\n }\n }, [isMuted, lastVolume, volume, mediaRef]);\n\n /**\n * 音量变化\n */\n const handleVolumeChange = useCallback((val: number) => {\n setVolume(val);\n const media = mediaRef.current;\n if (media) {\n media.volume = val;\n if (val === 0) {\n setIsMuted(true);\n media.muted = true;\n } else {\n setIsMuted(false);\n media.muted = false;\n }\n }\n }, [mediaRef]);\n\n /**\n * 跳转到指定时间\n */\n const seekTo = useCallback((time: number) => {\n const media = mediaRef.current;\n if (media && duration) {\n media.currentTime = time;\n setCurrentTime(time);\n setProgress((time / duration) * 100);\n }\n }, [duration, mediaRef]);\n\n /**\n * 格式化时间显示\n */\n const formatTime = useCallback((time: number) => {\n if (isNaN(time)) return '0:00';\n const minutes = Math.floor(time / 60);\n const seconds = Math.floor(time % 60);\n return `${minutes}:${seconds.toString().padStart(2, '0')}`;\n }, []);\n\n /**\n * 自动播放\n */\n const autoPlay = useCallback(() => {\n const media = mediaRef.current;\n if ((mediaType === FileType.VIDEO || isAudio) && media) {\n media.volume = volume;\n media.play().catch(() => {});\n setIsPlaying(true);\n }\n }, [mediaType, isAudio, volume, mediaRef]);\n\n /**\n * 监听媒体事件\n */\n useEffect(() => {\n const media = mediaRef.current;\n if (media) {\n media.addEventListener('timeupdate', updateProgress);\n media.addEventListener('loadedmetadata', updateProgress);\n media.addEventListener('ended', () => {\n setIsPlaying(false);\n });\n return () => {\n media.removeEventListener('timeupdate', updateProgress);\n media.removeEventListener('loadedmetadata', updateProgress);\n };\n }\n }, [mediaRef, updateProgress]);\n\n return {\n isPlaying,\n progress,\n currentTime,\n duration,\n isMuted,\n volume,\n showControls,\n isAudio,\n togglePlay,\n toggleMute,\n handleVolumeChange,\n seekTo,\n formatTime,\n autoPlay,\n updateProgress\n };\n}\n\n","import { useState, useCallback, useEffect } from 'react';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\n\n// 扩展 Window 类型\ndeclare global {\n interface Window {\n fileExplorerAPI?: {\n getApplicationIcon?: (appPath: string) => Promise<string | null>;\n };\n }\n}\n\n/**\n * 应用程序图标管理 hook\n */\nexport function useApplicationIcon(items: FileItem[]) {\n // 应用程序图标缓存(避免重复请求)\n const appIconCache = new Map<string, string>();\n\n // 使用响应式的图标 URL 映射\n const [appIconUrls, setAppIconUrls] = useState<Map<string, string>>(new Map());\n\n /**\n * 为应用程序获取图标\n */\n const loadApplicationIcon = useCallback(async (item: FileItem) => {\n if (item.type !== FileType.APPLICATION || !item.id) return;\n \n // 检查缓存\n if (appIconCache.has(item.id)) {\n const cachedUrl = appIconCache.get(item.id);\n if (cachedUrl) {\n setAppIconUrls(prev => new Map(prev).set(item.id, cachedUrl));\n }\n return;\n }\n \n // 检查响应式映射\n if (appIconUrls.has(item.id)) {\n return;\n }\n \n if (typeof window.fileExplorerAPI !== 'undefined' && window.fileExplorerAPI.getApplicationIcon) {\n try {\n const iconUrl = await window.fileExplorerAPI.getApplicationIcon(item.id);\n if (iconUrl) {\n appIconCache.set(item.id, iconUrl);\n setAppIconUrls(prev => new Map(prev).set(item.id, iconUrl));\n }\n } catch (error) {\n console.error(`Failed to load application icon for ${item.name}:`, error);\n }\n }\n }, [appIconUrls]);\n\n /**\n * 监听 items 变化,为应用程序加载图标\n */\n useEffect(() => {\n items.forEach(item => {\n if (item.type === FileType.APPLICATION && !appIconUrls.has(item.id)) {\n loadApplicationIcon(item);\n }\n });\n }, [items, appIconUrls, loadApplicationIcon]);\n\n /**\n * 获取应用程序图标的响应式 URL\n */\n const getAppIconUrl = useCallback((item: FileItem): string | undefined => {\n return appIconUrls.get(item.id);\n }, [appIconUrls]);\n\n return {\n getAppIconUrl,\n loadApplicationIcon\n };\n}\n\n"],"mappings":"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","names":["Icon","useMemo","KNOWN_TYPES","jsx","useMemo","useRef","Icon","jsx","Icon","jsx","jsxs","useRef","jsx","jsxs","Icon","Icon","jsx","jsxs","Icon","Icon","Icon","jsx","jsxs","Icon","jsx","jsxs","Icon","Fragment","jsx","jsxs","useMemo","useRef","useCallback","useState","Icon","jsx","jsxs","useRef","useState","useMemo","Icon","useCallback","createPortal","useMemo","useRef","useEffect","Icon","useState","useCallback","useEffect","useState","useCallback","useEffect","Fragment","jsx","jsxs","useRef","useMemo","initialWidth","initialHeight","useEffect","createPortal","Icon","useState","useMemo","useEffect","createPortal","Icon","jsx","jsxs","useState","useMemo","useEffect","createPortal","Icon","createPortal","Icon","jsx","jsxs","Icon","createPortal","Icon","jsx","jsxs","Icon","iconName","useState","useCallback","useState","useCallback","useState","useCallback","useState","useCallback","useEffect","useState","useCallback","useEffect","useState","useCallback","useEffect","useState","useCallback","useEffect"]}
package/dist/style.css ADDED
@@ -0,0 +1,3 @@
1
+ /* Base styles for file-explorer-frontend-react */
2
+ /* This file will be copied to dist/style.css during build */
3
+
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@huyooo/file-explorer-frontend-react",
3
+ "version": "0.4.2",
4
+ "description": "File Explorer Frontend - React components for file management",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "development": "./src/index.ts",
13
+ "import": "./dist/index.js",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "./style.css": "./dist/style.css"
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "src"
21
+ ],
22
+ "scripts": {
23
+ "prebuild": "npm run clean",
24
+ "build": "tsup",
25
+ "dev": "tsup --watch",
26
+ "typecheck": "tsc --noEmit",
27
+ "clean": "rm -rf dist",
28
+ "prepublishOnly": "npm run build && npm run typecheck"
29
+ },
30
+ "peerDependencies": {
31
+ "react": ">=18.0.0",
32
+ "react-dom": ">=18.0.0"
33
+ },
34
+ "dependencies": {
35
+ "@iconify/react": "^6.0.2",
36
+ "lucide-react": "^0.460.0"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^22.0.0",
40
+ "@types/react": "^18.0.0",
41
+ "@types/react-dom": "^18.0.0",
42
+ "react": "^18.0.0",
43
+ "react-dom": "^18.0.0",
44
+ "tsup": "^8.0.0",
45
+ "typescript": "^5.0.0"
46
+ },
47
+ "keywords": [
48
+ "file",
49
+ "explorer",
50
+ "react",
51
+ "frontend"
52
+ ],
53
+ "author": "huyooo",
54
+ "license": "MIT",
55
+ "publishConfig": {
56
+ "access": "public"
57
+ }
58
+ }