feat: drag-and-drop photo reordering in category form
Thumbnails are draggable — drag one over another to swap positions. Dragged item shows opacity/scale hint while dragging. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,7 @@ function CategoryForm({ category, onClose, onSave }: CategoryFormProps) {
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [saveError, setSaveError] = useState('')
|
||||
const [dragging, setDragging] = useState(false)
|
||||
const [dragSrcIdx, setDragSrcIdx] = useState<number | null>(null)
|
||||
const fileRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
const toggleAmenity = (a: string) =>
|
||||
@@ -245,8 +246,30 @@ function CategoryForm({ category, onClose, onSave }: CategoryFormProps) {
|
||||
</div>
|
||||
<div className="flex gap-2 overflow-x-auto pb-1">
|
||||
{photos.map((p, i) => (
|
||||
<button key={i} onClick={() => setPhotoIdx(i)}
|
||||
className={cn('w-14 h-14 rounded-lg overflow-hidden border-2 shrink-0', i === photoIdx ? 'border-brand-500' : 'border-transparent')}>
|
||||
<button
|
||||
key={i}
|
||||
draggable
|
||||
onDragStart={() => setDragSrcIdx(i)}
|
||||
onDragOver={e => {
|
||||
e.preventDefault()
|
||||
if (dragSrcIdx === null || dragSrcIdx === i) return
|
||||
setPhotos(prev => {
|
||||
const next = [...prev]
|
||||
const [moved] = next.splice(dragSrcIdx, 1)
|
||||
next.splice(i, 0, moved)
|
||||
return next
|
||||
})
|
||||
setPhotoIdx(i)
|
||||
setDragSrcIdx(i)
|
||||
}}
|
||||
onDragEnd={() => setDragSrcIdx(null)}
|
||||
onClick={() => setPhotoIdx(i)}
|
||||
className={cn(
|
||||
'w-14 h-14 rounded-lg overflow-hidden border-2 shrink-0 transition-all cursor-grab active:cursor-grabbing',
|
||||
i === photoIdx ? 'border-brand-500' : 'border-transparent',
|
||||
dragSrcIdx === i && 'opacity-50 scale-95',
|
||||
)}
|
||||
>
|
||||
<img src={p} alt="" className="w-full h-full object-cover" />
|
||||
</button>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user