Spaces:
Sleeping
Sleeping
File size: 4,324 Bytes
16d4b20 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
import React from 'react';
import { FileItem, UploadStatus } from '../types';
import { FileText, Loader2, Check, AlertCircle, ExternalLink, X } from 'lucide-react';
interface UploadListProps {
files: FileItem[];
onRemove: (id: string) => void;
onPathChange: (id: string, newPath: string) => void;
}
export const UploadList: React.FC<UploadListProps> = ({ files, onRemove, onPathChange }) => {
if (files.length === 0) return null;
return (
<div className="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
<div className="px-6 py-4 border-b border-gray-100 bg-gray-50 flex justify-between items-center">
<h3 className="font-semibold text-gray-800">Upload Queue ({files.length})</h3>
<span className="text-xs text-gray-500">You can rename the destination path below</span>
</div>
<div className="divide-y divide-gray-100">
{files.map((item) => (
<div key={item.id} className="p-4 hover:bg-gray-50 transition-colors flex items-center gap-4 group">
<div className="p-2 bg-blue-50 text-blue-600 rounded-lg">
<FileText className="w-5 h-5" />
</div>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="font-medium text-gray-900 truncate max-w-[200px]" title={item.file.name}>
{item.file.name}
</span>
<span className="text-xs text-gray-400">
({(item.file.size / 1024).toFixed(1)} KB)
</span>
</div>
{item.status === UploadStatus.IDLE && (
<div className="flex items-center gap-2">
<span className="text-xs text-gray-500">To:</span>
<input
type="text"
value={item.path}
onChange={(e) => onPathChange(item.id, e.target.value)}
className="text-xs py-1 px-2 border border-gray-200 rounded bg-white focus:border-yellow-400 outline-none w-full max-w-xs"
placeholder="path/to/file.ext"
/>
</div>
)}
{item.status === UploadStatus.UPLOADING && (
<span className="text-xs text-blue-600 flex items-center gap-1">
Processing...
</span>
)}
{item.status === UploadStatus.SUCCESS && (
<a
href={item.url}
target="_blank"
rel="noopener noreferrer"
className="text-xs text-green-600 hover:text-green-700 hover:underline flex items-center gap-1"
>
View on Hub <ExternalLink className="w-3 h-3" />
</a>
)}
{item.status === UploadStatus.ERROR && (
<span className="text-xs text-red-600 truncate" title={item.error}>
{item.error}
</span>
)}
</div>
<div className="flex items-center gap-2">
{item.status === UploadStatus.UPLOADING && (
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
)}
{item.status === UploadStatus.SUCCESS && (
<div className="p-1 bg-green-100 rounded-full">
<Check className="w-4 h-4 text-green-600" />
</div>
)}
{item.status === UploadStatus.ERROR && (
<div className="p-1 bg-red-100 rounded-full group-hover:hidden">
<AlertCircle className="w-4 h-4 text-red-600" />
</div>
)}
{item.status !== UploadStatus.UPLOADING && item.status !== UploadStatus.SUCCESS && (
<button
onClick={() => onRemove(item.id)}
className="p-1.5 text-gray-400 hover:text-red-500 hover:bg-red-50 rounded-lg transition-colors"
>
<X className="w-4 h-4" />
</button>
)}
</div>
</div>
))}
</div>
</div>
);
}; |