diff --git a/chrome.html b/chrome.html index a8e05ca..fdf8371 100644 --- a/chrome.html +++ b/chrome.html @@ -66,11 +66,10 @@ .searchbox { display: flex; align-items: center; width: 300px; background: var(--surface); border: 1px solid var(--line); border-radius: 999px; padding: 0 12px 0 3px; } .searchbox:focus-within { border-color: #4b7bec; } - .engine-sel { appearance: none; -webkit-appearance: none; width: 34px; height: 30px; border: none; cursor: pointer; - color: transparent; border-radius: 999px 0 0 999px; - background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238b98a9' stroke-width='1.6'%3E%3Ccircle cx='7' cy='7' r='4.2'/%3E%3Cpath d='M10.2 10.2 L14 14'/%3E%3C/svg%3E") no-repeat center / 15px; } - .engine-sel:hover { background-color: var(--hover); } - .engine-sel option { color: var(--ink); background: var(--surface); } + .engine-btn { width: 34px; height: 30px; border: none; cursor: pointer; border-radius: 999px 0 0 999px; padding: 0; + background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%238b98a9' stroke-width='1.6'%3E%3Ccircle cx='7' cy='7' r='4.2'/%3E%3Cpath d='M10.2 10.2 L14 14'/%3E%3C/svg%3E") no-repeat left 8px center / 14px; } + .engine-btn::after { content: "β–Ύ"; position: relative; left: 12px; font-size: 9px; color: var(--dim); } + .engine-btn:hover { background-color: var(--hover); } #search { flex: 1; padding: 7px 4px; } .tor { padding: 7px 10px; border-radius: 8px; border: 1px solid var(--line); background: #2b2f3a; color: var(--ink); cursor: pointer; white-space: nowrap; font-size: 12.5px; } .tor.connecting { background: #7a5c14; } .tor.on { background: #6b3fa0; } @@ -117,7 +116,7 @@ @@ -153,24 +152,18 @@ $("logo").onclick = () => T.openSettings(); $("secbadge").onclick = () => { const r = $("secbadge").getBoundingClientRect(); T.toggleSiteInfo({ x: Math.round(r.left), y: Math.round(r.bottom + 4) }); }; - // ---- search-engine picker (with an "Add / edit…" entry that opens Settings) ---- - let engineCurrent = "duckduckgo"; - function fillEngines(d) { - engineCurrent = d.current; - const sel = $("engine"); - sel.innerHTML = d.engines.map((e) => ``; - sel.value = d.current; - const cur = d.engines.find((e) => e.id === d.current); - $("search").placeholder = cur ? "Search with " + (cur.sym ? cur.sym + " " : "") + cur.name : "Search"; + // ---- search-engine picker: the magnifier button opens a custom overlay + // dropdown (real favicons); here we only track the current engine's name. ---- + function setEnginePlaceholder(d) { + const cur = (d.engines || []).find((e) => e.id === d.current); + $("search").placeholder = cur ? "Search with " + cur.name : "Search"; } - $("engine").onchange = () => { - const v = $("engine").value; - if (v === "__manage") { $("engine").value = engineCurrent; T.openSettings(); return; } - engineCurrent = v; T.setSearchEngine(v); + $("engineBtn").onclick = () => { + const r = $("engineBtn").getBoundingClientRect(); + T.toggleEnginePicker({ x: Math.round(r.left), y: Math.round(r.bottom + 4) }); }; - T.getSearchEngines().then(fillEngines); - T.onEngines && T.onEngines(fillEngines); + T.getSearchEngines().then(setEnginePlaceholder); + T.onEngines && T.onEngines(setEnginePlaceholder); // ---- favorites bar (new-tab page only) ---- let current = { url: "", title: "" }, bookmarks = []; diff --git a/engine-picker-preload.js b/engine-picker-preload.js new file mode 100644 index 0000000..e449988 --- /dev/null +++ b/engine-picker-preload.js @@ -0,0 +1,9 @@ +const { contextBridge, ipcRenderer } = require("electron"); +contextBridge.exposeInMainWorld("picker", { + onEngines: (cb) => ipcRenderer.on("engines", (_e, d) => cb(d)), + pick: (id) => ipcRenderer.invoke("pick-engine", id), + addDetected: () => ipcRenderer.invoke("add-detected-engine"), + openSettings: () => ipcRenderer.invoke("picker-open-settings"), + close: () => ipcRenderer.invoke("close-engine-picker"), + resize: (h) => ipcRenderer.invoke("ep-resize", h), +}); diff --git a/engine-picker.html b/engine-picker.html new file mode 100644 index 0000000..9434bcc --- /dev/null +++ b/engine-picker.html @@ -0,0 +1,55 @@ + + + + + + + diff --git a/main.js b/main.js index 46c34b7..6021e8e 100644 --- a/main.js +++ b/main.js @@ -23,20 +23,37 @@ const RESOLVER = app.isPackaged : path.join(__dirname, "..", "Argus", "src", "lib", "resolver-web.js"); // Built-in search engines. Users can also add their own (settings.customEngines, // each { id, name, url } where the url contains "%s" for the query). +// Catalog of built-in engines (users pick which to enable + can add their own). +// fav = the domain to load a real favicon from; sym = emoji fallback. const SEARCH_ENGINES = { - duckduckgo: { name: "DuckDuckGo", sym: "πŸ¦†", url: (q) => "https://duckduckgo.com/?q=" + encodeURIComponent(q) }, - google: { name: "Google", sym: "πŸ”΅", url: (q) => "https://www.google.com/search?q=" + encodeURIComponent(q) }, - brave: { name: "Brave", sym: "🦁", url: (q) => "https://search.brave.com/search?q=" + encodeURIComponent(q) }, - bing: { name: "Bing", sym: "πŸ”Ž", url: (q) => "https://www.bing.com/search?q=" + encodeURIComponent(q) }, - startpage: { name: "Startpage", sym: "πŸ›‘οΈ", url: (q) => "https://www.startpage.com/sp/search?query=" + encodeURIComponent(q) }, - yandex: { name: "Yandex", sym: "πŸ”΄", url: (q) => "https://yandex.com/search/?text=" + encodeURIComponent(q) }, + duckduckgo: { name: "DuckDuckGo", sym: "πŸ¦†", fav: "duckduckgo.com", url: (q) => "https://duckduckgo.com/?q=" + encodeURIComponent(q) }, + google: { name: "Google", sym: "πŸ”΅", fav: "www.google.com", url: (q) => "https://www.google.com/search?q=" + encodeURIComponent(q) }, + brave: { name: "Brave", sym: "🦁", fav: "search.brave.com", url: (q) => "https://search.brave.com/search?q=" + encodeURIComponent(q) }, + bing: { name: "Bing", sym: "πŸ”Ž", fav: "www.bing.com", url: (q) => "https://www.bing.com/search?q=" + encodeURIComponent(q) }, + startpage: { name: "Startpage", sym: "πŸ›‘οΈ", fav: "www.startpage.com", url: (q) => "https://www.startpage.com/sp/search?query=" + encodeURIComponent(q) }, + yandex: { name: "Yandex", sym: "πŸ”΄", fav: "yandex.com", url: (q) => "https://yandex.com/search/?text=" + encodeURIComponent(q) }, + ecosia: { name: "Ecosia", sym: "🌱", fav: "www.ecosia.org", url: (q) => "https://www.ecosia.org/search?q=" + encodeURIComponent(q) }, + mojeek: { name: "Mojeek", sym: "🧭", fav: "www.mojeek.com", url: (q) => "https://www.mojeek.com/search?q=" + encodeURIComponent(q) }, + searxng: { name: "SearXNG", sym: "🧩", fav: "searx.be", url: (q) => "https://searx.be/search?q=" + encodeURIComponent(q) }, + wikipedia: { name: "Wikipedia", sym: "πŸ“–", fav: "en.wikipedia.org", url: (q) => "https://en.wikipedia.org/wiki/Special:Search?search=" + encodeURIComponent(q) }, + perplexity: { name: "Perplexity", sym: "🧠", fav: "www.perplexity.ai", url: (q) => "https://www.perplexity.ai/search?q=" + encodeURIComponent(q) }, }; -// Built-in + user-added, as flat metadata for the pickers (sym = a display symbol). +// Engines enabled by default (shown in the toolbar dropdown). The rest are in the +// catalog and can be turned on from Settings. Custom + detected engines are always on. +const DEFAULT_ENABLED = ["duckduckgo", "google", "brave", "bing", "startpage"]; +const faviconUrl = (domain) => (domain ? `https://${domain}/favicon.ico` : null); +function customFavicon(url) { try { return faviconUrl(new URL(String(url).replace("%s", "x")).hostname); } catch { return null; } } +function isEnabled(id) { return (settings.enabledEngines || DEFAULT_ENABLED).includes(id); } +// Built-in + user-added, as flat metadata for the pickers. Built-in obey +// enabledEngines; custom engines are always enabled. function allEngines() { - const list = Object.entries(SEARCH_ENGINES).map(([id, e]) => ({ id, name: e.name, sym: e.sym, builtin: true })); - for (const c of settings.customEngines || []) list.push({ id: c.id, name: c.name, sym: c.sym || "πŸ”", builtin: false }); + const list = Object.entries(SEARCH_ENGINES).map(([id, e]) => + ({ 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; } +function enabledEnginesList() { return allEngines().filter((e) => e.enabled); } function engineUrl(id, q) { if (SEARCH_ENGINES[id]) return SEARCH_ENGINES[id].url(q); const c = (settings.customEngines || []).find((e) => e.id === id); @@ -47,28 +64,37 @@ const SEARCH = (q) => engineUrl(settings.searchEngine, q); const GATEWAY = "https://navigate.st"; // ---- BNS name detection (multi-TLD) -------------------------------------- -// The engine (resolver-web.js) resolves any