From f06cc488415622b933958395d73a780168bcf0ce Mon Sep 17 00:00:00 2001 From: Matt W Date: Mon, 5 Jan 2026 22:13:32 -0500 Subject: [PATCH] Fix mobile drag and drop --- scripts/mdtask.php | 132 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 125 insertions(+), 7 deletions(-) diff --git a/scripts/mdtask.php b/scripts/mdtask.php index dc552e4..aac5a73 100644 --- a/scripts/mdtask.php +++ b/scripts/mdtask.php @@ -208,6 +208,9 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { transition: all 0.2s; user-select: none; position: relative; + display: flex; + align-items: center; + gap: 12px; } .task-item.selected { @@ -235,6 +238,53 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { background: #E8E8E8; } + .drag-handle { + width: 24px; + height: 24px; + cursor: grab; + padding: 4px; + touch-action: none; + user-select: none; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 3px; + } + + .drag-handle::before, + .drag-handle::after { + content: ''; + width: 18px; + height: 2px; + background: #999; + border-radius: 1px; + } + + .drag-handle span { + width: 18px; + height: 2px; + background: #999; + border-radius: 1px; + display: block; + } + + .drag-handle:active::before, + .drag-handle:active::after, + .drag-handle:active span { + background: #4A90E2; + } + + .drag-handle:active { + cursor: grabbing; + } + + .task-content { + flex: 1; + min-width: 0; + } + .task-name { font-weight: 500; font-size: 16px; @@ -442,18 +492,29 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { v-for="(task, index) in tasks" :key="task.id" :class="['task-item', task.status, { selected: task.selected, dragging: draggedTask === task }]" - :draggable="!task.isSeparator" - @click="!task.isSeparator && toggleTaskSelection(task)" - @dblclick="!task.isSeparator && editSingleTask(task)" - @dragstart="!task.isSeparator && onDragStart(task, $event)" @dragover="onDragOver(task, $event)" @drop="onDrop(task, $event)" - @dragend="onDragEnd" >
@@ -523,6 +584,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { currentFileName: 'Inbox', fileMtime: null, draggedTask: null, + touchDraggedTask: null, + touchStartY: 0, showFileModal: false, fileModalTitle: '', fileModalMode: '', @@ -753,6 +816,61 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_GET['api'])) { this.draggedTask = null; }, + // Touch drag for mobile + onTouchStart(task, event) { + this.touchDraggedTask = task; + this.touchStartY = event.touches[0].clientY; + // Prevent default to stop scrolling while dragging from handle + event.preventDefault(); + }, + + onTouchMove(task, event) { + if (!this.touchDraggedTask) return; + + event.preventDefault(); + const touchY = event.touches[0].clientY; + + // Find which task element we're over + const elements = document.elementsFromPoint(event.touches[0].clientX, touchY); + + for (const el of elements) { + if (el.classList && el.classList.contains('task-item')) { + // Find the task index + const taskItems = Array.from(document.querySelectorAll('.task-item')); + const targetIndex = taskItems.indexOf(el); + + if (targetIndex !== -1) { + const targetTask = this.tasks[targetIndex]; + + if (targetTask && targetTask !== this.touchDraggedTask && !targetTask.isSeparator) { + const draggedIndex = this.tasks.indexOf(this.touchDraggedTask); + + if (draggedIndex !== -1 && draggedIndex !== targetIndex) { + // Remove from old position + this.tasks.splice(draggedIndex, 1); + + // Insert at new position + const newIndex = draggedIndex < targetIndex ? targetIndex : targetIndex; + this.tasks.splice(newIndex, 0, this.touchDraggedTask); + } + } + } + break; + } + } + }, + + onTouchEnd(event) { + if (this.touchDraggedTask) { + this.saveFile(); + this.touchDraggedTask = null; + } + }, + + onTouchCancel(event) { + this.touchDraggedTask = null; + }, + // Actions addTask() { this.editorTitle = 'New Task';