From bb0f68a8bf1b057fb000404262b212839007002d Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Wed, 10 Jun 2026 00:43:04 -0700 Subject: [PATCH] Profiles Phase 2 (drag): make the hybrid-source reorder actually draggable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hybrid download-source list set item.draggable=true and the help text said "drag to reorder", but no drag handlers were wired — only the arrow buttons worked (and _syncHybridOrderFromDOM was dead code). Wired real dragstart/dragover/drop on each item, reordering _hybridVisualOrder (the same model moveHybridSource uses) then rebuilding + autosaving. Added grab/grabbing cursors + a dragging state. The arrow buttons still work unchanged. --- webui/static/settings.js | 31 +++++++++++++++++++++++++++++++ webui/static/style.css | 6 ++++++ 2 files changed, 37 insertions(+) diff --git a/webui/static/settings.js b/webui/static/settings.js index 533d66b8..7c82f392 100644 --- a/webui/static/settings.js +++ b/webui/static/settings.js @@ -699,6 +699,21 @@ function buildHybridSourceList() { `; + // Real drag-to-reorder (the help text promised it; previously only the + // arrow buttons worked — item.draggable was set with no handlers). + item.addEventListener('dragstart', (e) => { + e.dataTransfer.effectAllowed = 'move'; + e.dataTransfer.setData('text/plain', srcId); + item.classList.add('dragging'); + }); + item.addEventListener('dragend', () => item.classList.remove('dragging')); + item.addEventListener('dragover', (e) => { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; }); + item.addEventListener('drop', (e) => { + e.preventDefault(); + const draggedId = e.dataTransfer.getData('text/plain'); + if (draggedId && draggedId !== srcId) _reorderHybridSource(draggedId, srcId); + }); + container.appendChild(item); }); @@ -723,6 +738,22 @@ function moveHybridSource(srcId, direction) { debouncedAutoSaveSettings(); } +function _reorderHybridSource(draggedId, targetId) { + // Move draggedId to just before targetId in the visual order, then rebuild + // the enabled subset + persist — same model moveHybridSource uses. + if (!_hybridVisualOrder) return; + const from = _hybridVisualOrder.indexOf(draggedId); + if (from < 0) return; + _hybridVisualOrder.splice(from, 1); + const to = _hybridVisualOrder.indexOf(targetId); + if (to < 0) { _hybridVisualOrder.splice(from, 0, draggedId); return; } // target gone — undo + _hybridVisualOrder.splice(to, 0, draggedId); + _hybridSourceOrder = _hybridVisualOrder.filter(id => _hybridSourceEnabled[id] !== false); + buildHybridSourceList(); + updateDownloadSourceUI(); + debouncedAutoSaveSettings(); +} + function toggleHybridSource(srcId, enabled) { _hybridSourceEnabled[srcId] = enabled; // Rebuild enabled order from visual order so priority matches position diff --git a/webui/static/style.css b/webui/static/style.css index bdf6f023..03987c26 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -55534,6 +55534,12 @@ tr.tag-diff-same { border-radius: 10px; transition: all 0.2s; user-select: none; + cursor: grab; +} +.hybrid-source-item.dragging { + opacity: 0.5; + cursor: grabbing; + border-color: rgb(var(--accent-light-rgb)); } .hybrid-source-item:hover { border-color: rgba(255, 255, 255, 0.12);