Image Gallery Uploader
An image-focused uploader with thumbnail previews in a grid layout.
Preview
Code
1import {2 UplofileRoot,3 UplofileDropzone,4 UplofileTrigger,5 UplofilePreview,6 type UploadFileItem,7} from "@/components/ui/uplofile";8import {9 IoAddOutline,10 IoImageOutline,11 IoReloadOutline,12 IoCheckmarkCircleOutline,13 IoAlertCircleOutline,14} from "react-icons/io5";15import { mockUpload } from "@/lib/utils.ts";1617export default function ImageGalleryDemo() {18 return (19 <UplofileRoot upload={mockUpload} accept="image/*" multiple>20 <UplofilePreview21 render={({ items }) => (22 <div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5 gap-4">23 {items.map((item) => (24 <ImageItem key={item.uid} item={item} />25 ))}2627 <UplofileDropzone className="group aspect-square rounded-xl flex flex-col items-center justify-center border-2 border-dashed border-muted-foreground/25 hover:border-primary/50 hover:bg-primary/5 cursor-pointer transition-all duration-200 data-[dragging=true]:border-primary data-[dragging=true]:bg-primary/10 data-[dragging=true]:scale-95">28 <UplofileTrigger>29 <div className="flex flex-col items-center gap-2 text-muted-foreground group-hover:text-primary transition-colors">30 <div className="p-3 rounded-full bg-muted group-hover:bg-primary/10 transition-colors">31 <IoAddOutline className="h-6 w-6" />32 </div>33 <span className="text-[10px] font-bold uppercase tracking-wider">34 Add Image35 </span>36 </div>37 </UplofileTrigger>38 </UplofileDropzone>39 </div>40 )}41 />42 </UplofileRoot>43 );44}4546function ImageItem({ item }: { item: UploadFileItem }) {47 return (48 <div className="group relative aspect-square rounded-xl overflow-hidden bg-white border shadow-sm animate-in fade-in zoom-in-95 duration-200">49 {item.previewUrl ? (50 <img51 src={item.previewUrl}52 alt={item.name}53 className="w-full h-full object-cover transition-transform duration-300 group-hover:scale-110"54 />55 ) : (56 <div className="w-full h-full flex items-center justify-center bg-muted/50">57 <IoImageOutline className="h-6 w-6 text-muted-foreground/40" />58 </div>59 )}6061 {item.status === "uploading" && (62 <div className="absolute inset-0 bg-black/60 backdrop-blur-[2px] flex flex-col items-center justify-center p-2">63 <IoReloadOutline className="h-6 w-6 text-white animate-spin mb-2" />64 <div className="w-full bg-white/20 rounded-full h-1 max-w-[40px]">65 <div66 className="bg-white h-full rounded-full transition-all duration-300"67 style={{ width: `${item.progress}%` }}68 />69 </div>70 </div>71 )}7273 {item.status === "done" && (74 <div className="absolute top-2 right-2 bg-emerald-500 text-white p-1 rounded-full shadow-lg scale-0 group-hover:scale-100 transition-transform duration-200">75 <IoCheckmarkCircleOutline className="h-3 w-3" />76 </div>77 )}7879 {item.status === "error" && (80 <div className="absolute inset-0 bg-destructive/60 backdrop-blur-[1px] flex flex-col items-center justify-center p-2 text-white animate-in zoom-in-95">81 <IoAlertCircleOutline className="h-6 w-6 mb-1" />82 <span className="text-[10px] font-bold uppercase tracking-wider">83 Failed84 </span>85 </div>86 )}8788 <div className="absolute inset-0 bg-black/20 opacity-0 group-hover:opacity-100 transition-opacity pointer-events-none" />89 </div>90 );91}
Key Points
- → Uses
accept="image/*"to filter file types - → Grid layout with thumbnail previews via
item.previewUrl - → Add button appears alongside existing images
- → Progress overlay during upload