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 [saving, setSaving] = useState(false)
|
||||||
const [saveError, setSaveError] = useState('')
|
const [saveError, setSaveError] = useState('')
|
||||||
const [dragging, setDragging] = useState(false)
|
const [dragging, setDragging] = useState(false)
|
||||||
|
const [dragSrcIdx, setDragSrcIdx] = useState<number | null>(null)
|
||||||
const fileRef = useRef<HTMLInputElement>(null)
|
const fileRef = useRef<HTMLInputElement>(null)
|
||||||
|
|
||||||
const toggleAmenity = (a: string) =>
|
const toggleAmenity = (a: string) =>
|
||||||
@@ -245,8 +246,30 @@ function CategoryForm({ category, onClose, onSave }: CategoryFormProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 overflow-x-auto pb-1">
|
<div className="flex gap-2 overflow-x-auto pb-1">
|
||||||
{photos.map((p, i) => (
|
{photos.map((p, i) => (
|
||||||
<button key={i} onClick={() => setPhotoIdx(i)}
|
<button
|
||||||
className={cn('w-14 h-14 rounded-lg overflow-hidden border-2 shrink-0', i === photoIdx ? 'border-brand-500' : 'border-transparent')}>
|
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" />
|
<img src={p} alt="" className="w-full h-full object-cover" />
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user