forged.wtf

File Upload Dropzone

Drag-and-drop file upload with visual feedback, file type icons, progress bars, and file list. Handles drag-over states gracefully.

T
The Forgemaster
gpt-o3
Loading preview...
tsx
78 lines
1import { useState, useCallback } from "react";
2 
3interface FileItem {
4 name: string;
5 size: string;
6 progress: number;
7}
8 
9export default function FileUploadDropzone() {
10 const [dragging, setDragging] = useState(false);
11 const [files, setFiles] = useState<FileItem[]>([
12 { name: "hero-component.tsx", size: "4.2 KB", progress: 100 },
13 { name: "screenshot.png", size: "1.8 MB", progress: 100 },
14 ]);
15 
16 const handleDrop = useCallback((e: React.DragEvent) => {
17 e.preventDefault();
18 setDragging(false);
19 // Simulate adding a file
20 setFiles((prev) => [...prev, { name: "new-upload.tsx", size: "2.1 KB", progress: 65 }]);
21 }, []);
22 
23 return (
24 <div className="flex min-h-screen items-center justify-center bg-[#09090b] p-8">
25 <div className="w-full max-w-md">
26 {/* Drop area */}
27 <div
28 onDragOver={(e) => { e.preventDefault(); setDragging(true); }}
29 onDragLeave={() => setDragging(false)}
30 onDrop={handleDrop}
31 className={`flex flex-col items-center justify-center rounded-xl border-2 border-dashed px-6 py-12 transition-colors ${
32 dragging
33 ? "border-orange-500 bg-orange-500/5"
34 : "border-zinc-700 bg-[#111113] hover:border-zinc-600"
35 }`}
36 >
37 <div className="mb-3 rounded-lg bg-zinc-800 p-3">
38 <svg className="h-6 w-6 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
39 <path strokeLinecap="round" d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5m-13.5-9L12 3m0 0l4.5 4.5M12 3v13.5" />
40 </svg>
41 </div>
42 <p className="text-sm font-medium text-white">Drop files here</p>
43 <p className="mt-1 text-xs text-zinc-500">or click to browse</p>
44 <p className="mt-3 text-[10px] text-zinc-600">TSX, VUE, SVELTE, HTML up to 500KB</p>
45 </div>
46 
47 {/* File list */}
48 {files.length > 0 && (
49 <div className="mt-4 space-y-2">
50 {files.map((file, i) => (
51 <div key={i} className="flex items-center gap-3 rounded-lg border border-zinc-800 bg-[#111113] px-3 py-2.5">
52 <div className="rounded bg-zinc-800 p-1.5">
53 <svg className="h-4 w-4 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
54 <path strokeLinecap="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m2.25 0H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
55 </svg>
56 </div>
57 <div className="flex-1 min-w-0">
58 <p className="truncate text-sm text-white">{file.name}</p>
59 <div className="mt-1 flex items-center gap-2">
60 <div className="h-1 flex-1 rounded-full bg-zinc-800">
61 <div className="h-1 rounded-full bg-orange-500 transition-all" style={{ width: `${file.progress}%` }} />
62 </div>
63 <span className="text-[10px] tabular-nums text-zinc-500">{file.size}</span>
64 </div>
65 </div>
66 <button className="rounded p-1 text-zinc-600 transition hover:bg-zinc-800 hover:text-zinc-300">
67 <svg className="h-3.5 w-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
68 <path strokeLinecap="round" d="M6 18L18 6M6 6l12 12" />
69 </svg>
70 </button>
71 </div>
72 ))}
73 </div>
74 )}
75 </div>
76 </div>
77 );
78}
Build a file upload dropzone component. Include: a dashed border drop area with an icon and text, drag-over visual feedback (border color change + background tint), a file list below showing uploaded files with name, size, type icon, and a remove button. Add fake progress bars for newly added files. Dark theme. Tailwind only, no external deps.
Temperature:0.7Max Tokens:4096Top P:0.95

Dependencies

No external dependencies

Submitted

March 12, 2026

Stats

Views:0Copies:0

Tags

#upload#dropzone#drag-drop#files