theseus/engine-picker.html
Local Dev 0f823ba583 Theseus: Firefox-style search picker (favicons, catalog, scan)
- Custom engine dropdown as a floating overlay view (engine-picker.html) that
  renders REAL favicons per engine — a native <select> can't show images.
- Larger catalog (DuckDuckGo/Google/Brave/Bing/Startpage/Yandex/Ecosia/Mojeek/
  SearXNG/Wikipedia/Perplexity); Settings has a favicon checklist to choose
  which appear in the dropdown (enabledEngines), plus manual add/remove.
- OpenSearch "scan": pages advertising a search engine surface an
  "Add <site>'s search" entry in the dropdown.
- Toolbar search box now just a magnifier button that opens the dropdown
  (no per-engine icon in the bar).
2026-07-30 22:55:52 +02:00

55 lines
3.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html><head><meta charset="utf-8">
<style>
:root { color-scheme: light dark; font-family: system-ui, sans-serif; }
html, body { margin: 0; background: transparent; }
.menu { background: #1c222c; border: 1px solid #ffffff26; border-radius: 10px; box-shadow: 0 12px 34px #000c; overflow: hidden; color: #e7eaf1; }
.hdr { font-size: 11px; letter-spacing: .04em; text-transform: uppercase; color: #8b98a9; padding: 10px 14px 6px; }
.item { display: flex; align-items: center; gap: 10px; padding: 8px 14px; cursor: pointer; font-size: 13px; }
.item:hover { background: #ffffff12; }
.item .ic { width: 18px; height: 18px; flex: none; display: grid; place-items: center; }
.item .ic img { width: 16px; height: 16px; border-radius: 3px; }
.item .ic .em { font-size: 14px; }
.item .nm { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item .chk { color: #4fd1a5; font-size: 12px; }
.sep { height: 1px; background: #ffffff14; margin: 6px 0; }
.foot .item { color: #b9c2d0; }
@media (prefers-color-scheme: light) {
.menu { background: #ffffff; border-color: rgba(0,0,0,.15); color: #1a1f28; }
.hdr { color: #7b8494; } .item:hover { background: rgba(0,0,0,.05); } .sep { background: rgba(0,0,0,.10); } .foot .item { color: #3c4453; }
}
</style></head>
<body>
<div class="menu">
<div class="hdr">Search with</div>
<div id="list"></div>
<div class="sep"></div>
<div class="foot">
<div class="item" id="detected" hidden><span class="ic"><span class="em"></span></span><span class="nm" id="detName"></span></div>
<div class="item" id="settings"><span class="ic"><span class="em">⚙️</span></span><span class="nm">Search settings…</span></div>
</div>
</div>
<script>
const $ = (id) => document.getElementById(id);
const esc = (s) => String(s || "").replace(/</g, "&lt;");
function report() { requestAnimationFrame(() => { try { window.picker.resize(document.querySelector(".menu").offsetHeight); } catch (e) {} }); }
window.picker.onData ? null : null;
window.picker.onEngines((d) => {
const list = $("list");
list.innerHTML = (d.engines || []).map((e) => {
const ic = e.favicon
? `<img src="${esc(e.favicon)}" onerror="this.replaceWith(Object.assign(document.createElement('span'),{className:'em',textContent:'${(e.sym||'🔍')}'}))">`
: `<span class="em">${e.sym || "🔍"}</span>`;
return `<div class="item" data-id="${esc(e.id)}"><span class="ic">${ic}</span><span class="nm">${esc(e.name)}</span>${e.id === d.current ? '<span class="chk">✓</span>' : ""}</div>`;
}).join("");
list.querySelectorAll(".item").forEach((el) => el.onclick = () => window.picker.pick(el.dataset.id));
// "Add this site's search" (OpenSearch scan)
const det = $("detected");
if (d.detected && d.detected.name) { det.hidden = false; $("detName").textContent = "Add " + d.detected.name; }
else det.hidden = true;
report();
});
$("detected").onclick = () => window.picker.addDetected();
$("settings").onclick = () => window.picker.openSettings();
</script>
</body></html>