import { Button, ButtonGroup } from '@heroui/button' import { Pagination } from '@heroui/pagination' import { Spinner } from '@heroui/spinner' import { type Selection, type SortDescriptor, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@heroui/table' import path from 'path-browserify' import { useCallback, useEffect, useState } from 'react' import { BiRename } from 'react-icons/bi' import { FiCopy, FiDownload, FiMove, FiTrash2 } from 'react-icons/fi' import { PhotoSlider } from 'react-photo-view' import FileIcon from '@/components/file_icon' import type { FileInfo } from '@/controllers/file_manager' import { supportedPreviewExts } from './file_preview_modal' import ImageNameButton, { PreviewImage, imageExts } from './image_name_button' export interface FileTableProps { files: FileInfo[] currentPath: string loading: boolean sortDescriptor: SortDescriptor onSortChange: (descriptor: SortDescriptor) => void selectedFiles: Selection onSelectionChange: (selected: Selection) => void onDirectoryClick: (dirPath: string) => void onEdit: (filePath: string) => void onPreview: (filePath: string) => void onRenameRequest: (name: string) => void onMoveRequest: (name: string) => void onCopyPath: (fileName: string) => void onDelete: (filePath: string) => void onDownload: (filePath: string) => void } const PAGE_SIZE = 20 export default function FileTable({ files, currentPath, loading, sortDescriptor, onSortChange, selectedFiles, onSelectionChange, onDirectoryClick, onEdit, onPreview, onRenameRequest, onMoveRequest, onCopyPath, onDelete, onDownload }: FileTableProps) { const [page, setPage] = useState(1) const pages = Math.ceil(files.length / PAGE_SIZE) || 1 const start = (page - 1) * PAGE_SIZE const end = start + PAGE_SIZE const displayFiles = files.slice(start, end) const [showImage, setShowImage] = useState(false) const [previewIndex, setPreviewIndex] = useState(0) const [previewImages, setPreviewImages] = useState([]) const addPreviewImage = useCallback((image: PreviewImage) => { setPreviewImages((prev) => { const exists = prev.some((p) => p.key === image.key) if (exists) return prev return [...prev, image] }) }, []) useEffect(() => { setPreviewImages([]) setPreviewIndex(0) setShowImage(false) }, [files]) const onPreviewImage = (name: string, images: PreviewImage[]) => { const index = images.findIndex((image) => image.key === name) if (index === -1) { return } setPreviewIndex(index) setShowImage(true) } return ( <> setShowImage(false)} index={previewIndex} onIndexChange={setPreviewIndex} /> setPage(page)} /> } > 名称 类型 大小 修改时间 操作 } > {displayFiles.map((file: FileInfo) => { const filePath = path.join(currentPath, file.name) const ext = path.extname(file.name).toLowerCase() const previewable = supportedPreviewExts.includes(ext) const images = previewImages return ( {imageExts.includes(ext) ? ( onPreviewImage(file.name, images)} onAddPreview={addPreviewImage} /> ) : ( )} {file.isDirectory ? '目录' : '文件'} {isNaN(file.size) || file.isDirectory ? '-' : `${file.size} 字节`} {new Date(file.mtime).toLocaleString()} ) })}
) }