diff --git a/main.js b/main.js index 4fabaae..9cb44d3 100644 --- a/main.js +++ b/main.js @@ -51,7 +51,15 @@ function allEngines() { ({ id, name: e.name, sym: e.sym, favicon: faviconUrl(e.fav), builtin: true, enabled: isEnabled(id) })); for (const c of settings.customEngines || []) list.push({ id: c.id, name: c.name, sym: c.sym || "🔍", favicon: customFavicon(c.url), builtin: false, enabled: true }); - return list; + // Apply the user's custom order; ids not in engineOrder keep their natural order (stable sort). + const order = settings.engineOrder || []; + return list.slice().sort((a, b) => { + const ia = order.indexOf(a.id), ib = order.indexOf(b.id); + if (ia === -1 && ib === -1) return 0; + if (ia === -1) return 1; + if (ib === -1) return -1; + return ia - ib; + }); } function enabledEnginesList() { return allEngines().filter((e) => e.enabled); } function engineUrl(id, q) { @@ -124,6 +132,7 @@ const SETTINGS_DEFAULTS = { locationMode: "hide", locationRegion: "europe", locationLat: "40.7128", locationLon: "-74.0060", // spoof by region, or manual coords searchEngine: "duckduckgo",// default search engine (built-in id or a custom id) enabledEngines: DEFAULT_ENABLED.slice(), // which built-in engines show in the dropdown + engineOrder: [], // user-defined display order of engine ids (empty = natural) customEngines: [], // user-added: [{ id, name, url-with-%s }] theme: "dark", // dark | light | system — drives prefers-color-scheme in all views }; @@ -801,6 +810,10 @@ ipcMain.handle("set-engine-enabled", (_e, id, on) => { } return { engines: allEngines(), current: settings.searchEngine }; }); +ipcMain.handle("set-engine-order", (_e, ids) => { + if (Array.isArray(ids)) { settings.engineOrder = ids.filter((x) => typeof x === "string"); saveSettings(); emitEngines(); } + return { engines: allEngines(), current: settings.searchEngine }; +}); // The custom dropdown overlay (real favicons). ipcMain.handle("toggle-engine-picker", (_e, rect) => { if (epVisible) return showEnginePicker(false); diff --git a/settings-preload.js b/settings-preload.js index 89ab17a..162a7e6 100644 --- a/settings-preload.js +++ b/settings-preload.js @@ -6,4 +6,5 @@ contextBridge.exposeInMainWorld("cfg", { addEngine: (eng) => ipcRenderer.invoke("add-engine", eng), removeEngine: (id) => ipcRenderer.invoke("remove-engine", id), setEngineEnabled: (id, on) => ipcRenderer.invoke("set-engine-enabled", id, on), + setEngineOrder: (ids) => ipcRenderer.invoke("set-engine-order", ids), }); diff --git a/settings.html b/settings.html index c48c997..f4a86b1 100644 --- a/settings.html +++ b/settings.html @@ -43,6 +43,9 @@ .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)} .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} @@ -145,7 +148,12 @@
Timezone
What sites read via JavaScript (Intl / Date).
- + + +
@@ -164,7 +172,11 @@ - + + +
@@ -181,8 +193,13 @@ + +
These reduce tracking and hide your IP, but a custom browser can still be fingerprinted. For maximum anonymity, use the Tor Browser.
@@ -216,14 +233,26 @@ const enabled = d.engines.filter((e) => e.enabled); sel.innerHTML = enabled.map((e) => ``).join(""); sel.value = d.current; - // unified checklist: built-in engines get an enable toggle; custom get a remove ✕ + // unified checklist: drag handle / up-down to reorder; built-in get an + // enable toggle, custom get a remove ✕. const list = document.getElementById("engineList"); - list.innerHTML = d.engines.map((e) => `
${engIcon(e)}${esc(e.name)}` + + 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")); } sel.onchange = () => C.set("searchEngine", sel.value); // appearance (theme) @@ -275,6 +304,13 @@ locMode.value = s.locationMode || "show"; applyLoc(); locMode.addEventListener("change", () => { C.set("locationMode", locMode.value); applyLoc(); }); + // picking a city fills the exact lat/lon fields + const CITY = { "London":[51.5074,-0.1278],"Berlin":[52.52,13.405],"Paris":[48.8566,2.3522],"Moscow":[55.7558,37.6173],"New York":[40.7128,-74.006],"Los Angeles":[34.0522,-118.2437],"São Paulo":[-23.5505,-46.6333],"Tokyo":[35.6762,139.6503],"Shanghai":[31.2304,121.4737],"Mumbai":[19.076,72.8777],"Dubai":[25.2048,55.2708],"Sydney":[-33.8688,151.2093],"Nairobi":[-1.2921,36.8219],"Singapore":[1.3521,103.8198] }; + document.getElementById("locationCity").addEventListener("change", (e) => { + const c = CITY[e.target.value.trim()]; if (!c) return; + const la = document.getElementById("locationLat"), lo = document.getElementById("locationLon"); + la.value = c[0]; lo.value = c[1]; C.set("locationLat", String(c[0])); C.set("locationLon", String(c[1])); + }); });