Spaces:
Sleeping
Sleeping
| import { FileImage, X, ScanLine, FileStack, Trash2 } from 'lucide-react' | |
| interface Props { | |
| files: File[] | |
| onRemove: (name: string) => void | |
| onClearAll: () => void | |
| onAnalyze: () => void | |
| } | |
| function formatBytes(bytes: number): string { | |
| if (bytes < 1024) return `${bytes} B` | |
| if (bytes < 1024 ** 2) return `${(bytes / 1024).toFixed(1)} KB` | |
| return `${(bytes / 1024 ** 2).toFixed(1)} MB` | |
| } | |
| export default function FileList({ files, onRemove, onClearAll, onAnalyze }: Props) { | |
| const totalSize = files.reduce((sum, f) => sum + f.size, 0) | |
| return ( | |
| <div className="animate-fade-up space-y-4"> | |
| {/* Header row */} | |
| <div className="flex items-center justify-between"> | |
| <div className="flex items-center gap-2 text-sm text-slate-500"> | |
| <FileStack className="h-4 w-4 text-slate-400" /> | |
| <span> | |
| <span className="font-semibold text-slate-700">{files.length}</span>{' '} | |
| tệp đã chọn | |
| </span> | |
| <span className="text-slate-300">·</span> | |
| <span>{formatBytes(totalSize)}</span> | |
| </div> | |
| <button | |
| type="button" | |
| onClick={onClearAll} | |
| className="flex items-center gap-1.5 rounded-md border border-slate-200 bg-white px-3 py-1.5 | |
| text-xs font-medium text-slate-500 transition-all duration-150 | |
| hover:border-red-200 hover:bg-red-50 hover:text-red-500 active:scale-95" | |
| > | |
| <Trash2 className="h-3.5 w-3.5" /> | |
| Xóa tất cả | |
| </button> | |
| </div> | |
| {/* File rows */} | |
| <ul className="max-h-52 space-y-1.5 overflow-y-auto pr-1"> | |
| {files.map((file, idx) => ( | |
| <li | |
| key={file.name} | |
| className="group flex items-center gap-3 rounded-lg border border-slate-100 | |
| bg-white px-3 py-2 transition-colors hover:border-slate-200" | |
| > | |
| <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-slate-100"> | |
| <FileImage className="h-3.5 w-3.5 text-slate-400" /> | |
| </div> | |
| <div className="min-w-0 flex-1"> | |
| <p className="text-sm font-medium text-slate-700">Slice {idx + 1}</p> | |
| <p className="text-xs text-slate-400">{formatBytes(file.size)}</p> | |
| </div> | |
| <button | |
| type="button" | |
| aria-label={`Xóa ${file.name}`} | |
| onClick={() => onRemove(file.name)} | |
| className="ml-auto flex h-6 w-6 shrink-0 items-center justify-center rounded-md | |
| text-slate-300 opacity-0 transition-all group-hover:opacity-100 | |
| hover:bg-red-50 hover:text-red-400" | |
| > | |
| <X className="h-3.5 w-3.5" /> | |
| </button> | |
| </li> | |
| ))} | |
| </ul> | |
| {/* CTA */} | |
| <button | |
| type="button" | |
| onClick={onAnalyze} | |
| className="flex w-full items-center justify-center gap-2 rounded-lg | |
| bg-teal-600 px-6 py-3 | |
| text-sm font-semibold text-white shadow-sm shadow-teal-100 | |
| transition-all duration-150 hover:bg-teal-700 active:scale-[0.98]" | |
| > | |
| <ScanLine className="h-4 w-4" /> | |
| Bắt đầu phân tích | |
| </button> | |
| </div> | |
| ) | |
| } | |