Spaces:
Running
Running
| import { useCallback } from 'react'; | |
| import { useDropzone } from 'react-dropzone'; | |
| import { Upload, Image as ImageIcon } from 'lucide-react'; | |
| import { cn } from '../lib/utils'; | |
| interface ImageUploadProps { | |
| onUpload: (file: File) => void; | |
| preview: string | null; | |
| label: string; | |
| description: string; | |
| } | |
| export function ImageUpload({ onUpload, preview, label, description }: ImageUploadProps) { | |
| const onDrop = useCallback( | |
| (acceptedFiles: File[]) => { | |
| if (acceptedFiles.length > 0) { | |
| onUpload(acceptedFiles[0]); | |
| } | |
| }, | |
| [onUpload] | |
| ); | |
| const { getRootProps, getInputProps, isDragActive } = useDropzone({ | |
| onDrop, | |
| accept: { | |
| 'image/*': ['.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp'], | |
| }, | |
| maxFiles: 1, | |
| }); | |
| return ( | |
| <div className="h-full flex flex-col gap-1"> | |
| <label className="flex-shrink-0 text-xs font-medium text-white flex items-center gap-2"> | |
| <ImageIcon className="w-3 h-3 text-text-secondary" /> | |
| {label} | |
| </label> | |
| <div | |
| {...getRootProps()} | |
| className={cn( | |
| 'flex-1 relative border-2 border-dashed rounded-lg transition-all duration-200 cursor-pointer', | |
| 'hover:border-nvidia-green hover:bg-nvidia-green/5', | |
| isDragActive | |
| ? 'border-nvidia-green bg-nvidia-green/10' | |
| : 'border-dark-border bg-dark-input', | |
| preview ? 'p-1' : 'p-4' | |
| )} | |
| > | |
| <input {...getInputProps()} /> | |
| {preview ? ( | |
| <div className="relative w-full h-full overflow-hidden rounded"> | |
| <img | |
| src={preview} | |
| alt="Uploaded preview" | |
| className="w-full h-full object-contain bg-black" | |
| /> | |
| <div className="absolute inset-0 bg-black/50 opacity-0 hover:opacity-100 transition-opacity flex items-center justify-center"> | |
| <p className="text-white text-sm">Click or drop to replace</p> | |
| </div> | |
| </div> | |
| ) : ( | |
| <div className="h-full flex flex-col items-center justify-center gap-3"> | |
| <div className="p-3 rounded-full bg-dark-card"> | |
| <Upload className="w-6 h-6 text-text-muted" /> | |
| </div> | |
| <div className="text-center"> | |
| <p className="text-white font-medium text-sm"> | |
| {isDragActive ? 'Drop image here' : 'Drop or click to upload'} | |
| </p> | |
| <p className="text-text-muted text-xs mt-1">{description}</p> | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| </div> | |
| ); | |
| } | |