feat: composant DropZone drag & drop HEIC/JPG/PNG/ZIP

This commit is contained in:
2026-06-08 17:43:40 +02:00
parent 901199c45d
commit 4c1cf73435
+73
View File
@@ -0,0 +1,73 @@
'use client'
import { useCallback, useRef, useState } from 'react'
interface DropZoneProps {
onFiles: (files: File[]) => void
disabled?: boolean
}
const ACCEPTED_TYPES = ['.heic', '.heif', '.jpg', '.jpeg', '.png', '.zip']
const ACCEPT_ATTR = ACCEPTED_TYPES.join(',')
export function DropZone({ onFiles, disabled = false }: DropZoneProps) {
const [isDragging, setIsDragging] = useState(false)
const inputRef = useRef<HTMLInputElement>(null)
const handleFiles = useCallback(
(fileList: FileList | null) => {
if (!fileList) return
const files = Array.from(fileList).filter((f) => {
const ext = '.' + f.name.split('.').pop()?.toLowerCase()
return ACCEPTED_TYPES.includes(ext)
})
if (files.length > 0) onFiles(files)
},
[onFiles],
)
const onDragOver = (e: React.DragEvent) => {
e.preventDefault()
if (!disabled) setIsDragging(true)
}
const onDragLeave = () => setIsDragging(false)
const onDrop = (e: React.DragEvent) => {
e.preventDefault()
setIsDragging(false)
if (!disabled) handleFiles(e.dataTransfer.files)
}
return (
<div
onDragOver={onDragOver}
onDragLeave={onDragLeave}
onDrop={onDrop}
onClick={() => !disabled && inputRef.current?.click()}
className={`border-2 border-dashed rounded-xl p-8 text-center cursor-pointer transition-colors ${
isDragging
? 'border-indigo-400 bg-indigo-950/30'
: disabled
? 'border-slate-700 bg-slate-800/20 cursor-not-allowed'
: 'border-slate-600 bg-slate-800/10 hover:border-indigo-500 hover:bg-indigo-950/20'
}`}
>
<div className="text-3xl mb-2">🖼</div>
<p className="text-sm font-semibold text-slate-300">
Déposez vos images ici ou cliquez pour parcourir
</p>
<p className="text-xs text-slate-500 mt-1">
HEIC, JPG, PNG, ZIP le nom du fichier = référence produit
</p>
<input
ref={inputRef}
type="file"
multiple
accept={ACCEPT_ATTR}
className="hidden"
onChange={(e) => handleFiles(e.target.files)}
disabled={disabled}
/>
</div>
)
}