File List with Actions
A detailed file list with file info, progress indicators, and remove buttons.
Preview
No files added yet.
Code
1import { clsx } from "clsx";2import {3 UplofileRoot,4 UplofileTrigger,5 UplofilePreview,6 UplofileRemove,7 type UploadFileItem,8} from "@/components/ui/uplofile";9import {10 IoDocumentOutline,11 IoImageOutline,12 IoDocumentTextOutline,13 IoArchiveOutline,14 IoCloseOutline,15 IoAddOutline,16 IoCheckmarkCircleOutline,17 IoAlertCircleOutline,18} from "react-icons/io5";19import { mockUpload, formatBytes } from "@/lib/utils.ts";2021export default function FileListWithActionsDemo() {22 return (23 <UplofileRoot upload={mockUpload} multiple>24 <UplofileTrigger asChild>25 <button className="inline-flex items-center gap-2 px-4 py-2 bg-primary text-primary-foreground rounded-lg hover:bg-primary/90 transition-all shadow-sm font-medium text-sm active:scale-95">26 <IoAddOutline className="h-4 w-4" />27 Add Files28 </button>29 </UplofileTrigger>3031 <UplofilePreview32 render={({ items }) => (33 <div className="mt-6 divide-y divide-border border rounded-xl bg-card shadow-sm overflow-hidden">34 {items.length === 0 && (35 <div className="p-12 text-center">36 <IoDocumentOutline className="h-10 w-10 text-muted-foreground/20 mx-auto mb-4" />37 <p className="text-sm text-muted-foreground">38 No files added yet.39 </p>40 </div>41 )}42 {items.map((item) => (43 <FileItem key={item.uid} item={item} />44 ))}45 </div>46 )}47 />48 </UplofileRoot>49 );50}5152function FileItem({ item }: { item: UploadFileItem }) {53 return (54 <div className="flex items-center gap-4 p-4 hover:bg-muted/50 transition-colors animate-in fade-in slide-in-from-left-2">55 <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">56 {getFileIcon(item.name)}57 </div>58 <div className="flex-1 min-w-0">59 <div className="flex items-center justify-between gap-2 mb-1">60 <p className="text-sm font-semibold truncate text-foreground">61 {item.name}62 </p>63 <span className="text-[10px] font-bold text-muted-foreground uppercase tracking-widest">64 {item.file ? formatBytes(item.file.size) : "—"}65 </span>66 </div>6768 <div className="flex items-center gap-2">69 {item.status === "uploading" ? (70 <div className="flex items-center gap-2 w-full">71 <div className="flex-1 h-1 bg-secondary rounded-full overflow-hidden">72 <div73 className="h-full bg-primary transition-all duration-300"74 style={{ width: `${item.progress}%` }}75 />76 </div>77 <span className="text-[10px] font-medium tabular-nums">78 {item.progress}%79 </span>80 </div>81 ) : (82 <div className="flex items-center gap-1.5">83 {item.status === "done" && (84 <IoCheckmarkCircleOutline className="h-3 w-3 text-emerald-500" />85 )}86 {item.status === "error" && (87 <IoAlertCircleOutline className="h-3 w-3 text-destructive" />88 )}89 <span90 className={clsx(91 "text-[10px] font-bold uppercase tracking-tighter italic",92 item.status === "done" && "text-emerald-600",93 item.status === "error" && "text-destructive",94 item.status === "idle" && "text-muted-foreground",95 )}96 >97 {item.status}98 </span>99 </div>100 )}101 </div>102 </div>103 <UplofileRemove104 uid={item.uid}105 className="p-2 rounded-md text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-all"106 >107 <IoCloseOutline className="h-4 w-4" />108 </UplofileRemove>109 </div>110 );111}112113function getFileIcon(name: string) {114 const ext = name.split(".").pop()?.toLowerCase();115 if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext || ""))116 return <IoImageOutline className="h-5 w-5" />;117 if (ext === "pdf" || ["doc", "docx"].includes(ext || ""))118 return <IoDocumentTextOutline className="h-5 w-5" />;119 if (["zip", "rar", "7z"].includes(ext || ""))120 return <IoArchiveOutline className="h-5 w-5" />;121 return <IoDocumentOutline className="h-5 w-5" />;122}
Key Points
- → Uses
UplofileRemovecomponent withuidprop - → File type icons based on extension
- → Human-readable file sizes
- → Status shown inline (uploading %, done, error)