From 9c5c6c12c98efa81113a5f805868913b46a65baf Mon Sep 17 00:00:00 2001 From: Local Dev Date: Fri, 31 Jul 2026 21:53:01 +0200 Subject: [PATCH] Theseus: drag-to-reorder search engines (replaces up/down arrows) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each engine row in Settings has a drag handle (⠿) and is draggable; dropping onto another row reorders and persists via setEngineOrder, driving the toolbar dropdown order. Visual drag/over states included. --- settings.html | 39 ++++++++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/settings.html b/settings.html index f4a86b1..1a60e4e 100644 --- a/settings.html +++ b/settings.html @@ -43,9 +43,11 @@ .eng .eic .ei{width:16px;height:16px;border-radius:3px} .eng .eic .es{font-size:14px} .eng .enm{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .eng .cx{cursor:pointer;color:var(--dim);border:none;background:transparent;font-size:13px} .eng .cx:hover{color:#f6768a} - .eng .mv{display:flex;flex-direction:column;flex:none;gap:1px} - .eng .mv button{border:none;background:transparent;color:var(--dim);cursor:pointer;font-size:8px;line-height:1;padding:1px 2px;border-radius:3px} - .eng .mv button:hover{background:var(--line);color:var(--ink)} + .eng{cursor:default} + .eng .grip{flex:none;color:var(--dim);cursor:grab;font-size:14px;line-height:1;padding:0 2px;user-select:none} + .eng .grip:active{cursor:grabbing} + .eng.dragging{opacity:.45} + .eng.over{border-color:var(--acid);box-shadow:0 -2px 0 var(--acid) inset} .sw.sm{width:38px;height:22px} .sw.sm .knob{width:15px;height:15px} .sw.sm input:checked + .track .knob{transform:translateX(16px)} .ceng .cn{font-weight:600} .ceng .cu{color:var(--dim);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1} .ceng .cx{cursor:pointer;color:#8b98a9;border:none;background:transparent;font-size:13px} .ceng .cx:hover{color:#f6768a} @@ -233,26 +235,33 @@ const enabled = d.engines.filter((e) => e.enabled); sel.innerHTML = enabled.map((e) => ``).join(""); sel.value = d.current; - // unified checklist: drag handle / up-down to reorder; built-in get an + // unified checklist: drag a row by its handle to reorder; built-in get an // enable toggle, custom get a remove ✕. const list = document.getElementById("engineList"); - list.innerHTML = d.engines.map((e) => `
` + - `` + + list.innerHTML = d.engines.map((e) => `
` + + `` + `${engIcon(e)}${esc(e.name)}` + (e.builtin ? `` : ``) + `
`).join(""); list.querySelectorAll('input[type="checkbox"]').forEach((cb) => cb.onchange = () => C.setEngineEnabled(cb.dataset.id, cb.checked).then(renderEngines)); list.querySelectorAll(".cx").forEach((b) => b.onclick = () => C.removeEngine(b.dataset.id).then(renderEngines)); - const move = (id, dir) => { - const ids = [...list.querySelectorAll(".eng")].map((el) => el.dataset.id); - const i = ids.indexOf(id), j = dir === "up" ? i - 1 : i + 1; - if (j < 0 || j >= ids.length) return; - [ids[i], ids[j]] = [ids[j], ids[i]]; - C.setEngineOrder(ids).then(renderEngines); - }; - list.querySelectorAll(".up").forEach((b) => b.onclick = () => move(b.closest(".eng").dataset.id, "up")); - list.querySelectorAll(".dn").forEach((b) => b.onclick = () => move(b.closest(".eng").dataset.id, "down")); + // drag-and-drop reorder + let dragId = null; + list.querySelectorAll(".eng").forEach((row) => { + row.addEventListener("dragstart", (e) => { dragId = row.dataset.id; e.dataTransfer.effectAllowed = "move"; row.classList.add("dragging"); }); + row.addEventListener("dragend", () => { row.classList.remove("dragging"); list.querySelectorAll(".eng").forEach((r) => r.classList.remove("over")); }); + row.addEventListener("dragover", (e) => { e.preventDefault(); e.dataTransfer.dropEffect = "move"; if (row.dataset.id !== dragId) row.classList.add("over"); }); + row.addEventListener("dragleave", () => row.classList.remove("over")); + row.addEventListener("drop", (e) => { + e.preventDefault(); row.classList.remove("over"); + if (!dragId || dragId === row.dataset.id) return; + const ids = [...list.querySelectorAll(".eng")].map((el) => el.dataset.id); + const from = ids.indexOf(dragId), to = ids.indexOf(row.dataset.id); + ids.splice(from, 1); ids.splice(to, 0, dragId); + C.setEngineOrder(ids).then(renderEngines); + }); + }); } sel.onchange = () => C.set("searchEngine", sel.value); // appearance (theme)