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

This commit is contained in:
2026-05-23 23:13:44 -04:00
parent 63e92756fe
commit 229b6b6f7a

View File

@@ -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;