feat: add touch support for drag-and-drop reordering of routine items
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m13s
All checks were successful
Chore App Build, Test, and Push Docker Images / build-and-push (push) Successful in 3m13s
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
v-for="(item, idx) in items"
|
||||
:key="item.id || `new-${idx}`"
|
||||
class="item-row"
|
||||
:data-idx="idx"
|
||||
:class="{ 'drag-over': dragOverIdx === idx, dragging: draggingIdx === idx }"
|
||||
draggable="true"
|
||||
@dragstart="(e) => onDragStart(e, idx)"
|
||||
@@ -33,7 +34,7 @@
|
||||
@drop.prevent="onDrop(idx)"
|
||||
@dragend="onDragEnd"
|
||||
>
|
||||
<span class="drag-handle" title="Drag to reorder">⠿</span>
|
||||
<span class="drag-handle" title="Drag to reorder" @touchstart="(e) => onTouchStart(e, idx)">⠿</span>
|
||||
<div class="item-left">
|
||||
<img
|
||||
v-if="item.image_url"
|
||||
@@ -363,6 +364,48 @@ function onDragEnd() {
|
||||
dragOverIdx.value = null
|
||||
}
|
||||
|
||||
function onTouchStart(e: TouchEvent, idx: number) {
|
||||
draggingIdx.value = idx
|
||||
cancelEditItem()
|
||||
|
||||
const handleTouchMove = (moveEvt: TouchEvent) => {
|
||||
moveEvt.preventDefault()
|
||||
const touch = moveEvt.touches[0]
|
||||
const el = document.elementFromPoint(touch.clientX, touch.clientY) as Element | null
|
||||
if (!el) return
|
||||
const row = el.closest('[data-idx]') as HTMLElement | null
|
||||
if (!row) return
|
||||
const rowIdx = parseInt(row.dataset.idx ?? '-1')
|
||||
if (rowIdx !== -1 && rowIdx !== draggingIdx.value) {
|
||||
dragOverIdx.value = rowIdx
|
||||
}
|
||||
}
|
||||
|
||||
const handleTouchEnd = (endEvt: TouchEvent) => {
|
||||
const touch = endEvt.changedTouches[0]
|
||||
const el = document.elementFromPoint(touch.clientX, touch.clientY) as Element | null
|
||||
const fromIdx = draggingIdx.value
|
||||
if (el && fromIdx !== null) {
|
||||
const row = el.closest('[data-idx]') as HTMLElement | null
|
||||
if (row) {
|
||||
const toIdx = parseInt(row.dataset.idx ?? '-1')
|
||||
if (toIdx !== -1 && toIdx !== fromIdx) {
|
||||
const moved = items.value.splice(fromIdx, 1)[0]
|
||||
items.value.splice(toIdx, 0, moved)
|
||||
normalizeItemOrder()
|
||||
}
|
||||
}
|
||||
}
|
||||
draggingIdx.value = null
|
||||
dragOverIdx.value = null
|
||||
document.removeEventListener('touchmove', handleTouchMove)
|
||||
document.removeEventListener('touchend', handleTouchEnd)
|
||||
}
|
||||
|
||||
document.addEventListener('touchmove', handleTouchMove, { passive: false })
|
||||
document.addEventListener('touchend', handleTouchEnd)
|
||||
}
|
||||
|
||||
async function uploadImage(file: File): Promise<string> {
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
@@ -541,6 +584,13 @@ function handleCancel() {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
.drag-handle {
|
||||
padding: 0.5rem 0.6rem;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.item-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in New Issue
Block a user