theo-agent-dashboard

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

AttachmentPreview.tsx (1823B)


      1 interface AttachmentPreviewProps {
      2   file: { name: string; type: string; size: number };
      3   onRemove: () => void;
      4   thumbnailUrl?: string;
      5   progress?: number;
      6   error?: string;
      7 }
      8 
      9 function formatFileSize(bytes: number): string {
     10   if (bytes < 1024) return `${bytes} B`;
     11   if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(0)} KB`;
     12   return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
     13 }
     14 
     15 function isImageFile(mimeType: string): boolean {
     16   return mimeType.startsWith("image/");
     17 }
     18 
     19 export function AttachmentPreview({
     20   file,
     21   onRemove,
     22   thumbnailUrl,
     23   progress,
     24   error,
     25 }: AttachmentPreviewProps) {
     26   return (
     27     <div className="flex items-center gap-2 rounded-lg bg-gray-800 px-3 py-2 text-sm">
     28       {isImageFile(file.type) && thumbnailUrl ? (
     29         <img
     30           src={thumbnailUrl}
     31           alt={file.name}
     32           className="h-10 w-10 rounded object-cover"
     33         />
     34       ) : (
     35         <span className="text-gray-400">📄</span>
     36       )}
     37 
     38       <div className="flex-1 min-w-0">
     39         <p className="truncate text-gray-200">{file.name}</p>
     40         <p className="text-xs text-gray-500">{formatFileSize(file.size)}</p>
     41         {progress !== undefined && (
     42           <div className="mt-1 h-1 w-full rounded bg-gray-700">
     43             <div
     44               className="h-1 rounded bg-blue-500 transition-all"
     45               style={{ width: `${Math.min(progress, 100)}%` }}
     46             />
     47           </div>
     48         )}
     49         {error && <p className="text-xs text-red-400">{error}</p>}
     50       </div>
     51 
     52       <span className="text-xs text-gray-400">{progress}%</span>
     53 
     54       <button
     55         type="button"
     56         onClick={onRemove}
     57         className="ml-1 rounded p-1 text-gray-500 hover:bg-gray-700 hover:text-gray-300"
     58         aria-label="Remove attachment"
     59       >
     60         ✕
     61       </button>
     62     </div>
     63   );
     64 }