theseus/settings.html

595 lines
39 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head><meta charset="utf-8"><title>Theseus — Settings</title>
<style>
:root{ --bg:#0b0e14; --panel:#141a24; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d; }
*{box-sizing:border-box}
body{margin:0;height:100vh;background:var(--bg);color:var(--ink);font:15px/1.6 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
.app{display:flex;height:100vh}
/* left sidebar menu */
.side{flex:none;width:220px;background:#0e131c;border-right:1px solid var(--line);padding:20px 12px;display:flex;flex-direction:column;gap:2px}
.brand{font-weight:700;color:var(--acid);font-size:15px;padding:4px 12px 16px}
.side a{display:block;padding:9px 12px;border-radius:8px;color:var(--mut);text-decoration:none;font-size:14px;cursor:pointer}
.side a:hover{background:#ffffff0a;color:var(--ink)}
.side a.active{background:rgba(214,255,61,.12);color:var(--acid)}
/* content */
.content{flex:1;overflow-y:auto;padding:2.4rem 2.4rem 4rem}
section{max-width:640px}
h1{font-size:1.4rem;margin:0 0 .2rem}
.lede{color:var(--mut);margin:0 0 1.8rem;font-size:13.5px}
h2.sub{font-size:11.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--dim);margin:1.8rem 0 .2rem;border-top:1px solid var(--line);padding-top:1.4rem}
.subd{color:var(--mut);margin:0 0 1rem;font-size:13px}
.row{display:flex;align-items:center;gap:16px;background:var(--panel);border:1px solid var(--line);
border-radius:12px;padding:14px 18px;margin-bottom:10px}
.row .txt{flex:1}
.row .t{font-weight:600}
.row .d{color:var(--mut);font-size:13px;margin-top:2px}
/* control column — mode select + optional value field on the same row so the
dropdown menus don't get cut off underneath, wraps only when narrow */
.ctl{display:flex;flex-direction:row;flex-wrap:wrap;gap:6px;align-items:center;justify-content:flex-end;flex:none;max-width:60%}
.ctl .coords{display:flex;gap:6px}
select,.ctl input{background:#1b2330;color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:7px 10px;font-size:13px;outline:none;min-width:140px}
select:focus,.ctl input:focus{border-color:#4b7bec}
.ctl input{width:170px} .ctl .coords input{width:92px;min-width:auto}
/* Chromium's native <select> popup uses the page's color-scheme; when it's
"light dark" (both accepted) Chromium picks by the OS, so a dark-theme app
on a light OS shows a light popup. main.js's applyTheme() maps to
nativeTheme.themeSource, which drives prefers-color-scheme — so pinning
color-scheme via that media query keeps the popup in sync automatically. */
:root { color-scheme: dark; }
@media (prefers-color-scheme: light) { :root { color-scheme: light; } }
/* Explicit option styling — Chromium respects it in the popup on Windows. */
select option { background: #1b2330; color: var(--ink); }
@media (prefers-color-scheme: light) { select option { background: #f1f3f7; color: #1a1f28; } }
code{font-family:ui-monospace,monospace;font-size:12px;background:#0e131b;border:1px solid var(--line);border-radius:5px;padding:1px 5px;color:#bfeae4}
.addeng{display:flex;gap:6px} .addeng input{flex:1;background:#1b2330;color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:8px 10px;font-size:13px;outline:none}
.addeng input:focus{border-color:#4b7bec}
.btn{border:1px solid #d6ff3d55;background:rgba(214,255,61,.12);color:#eaffb0;border-radius:8px;padding:8px 14px;font-size:13px;cursor:pointer}
.btn:hover{background:rgba(214,255,61,.22)}
/* segmented control — small toggle used elsewhere (kept for reuse) */
.segseg{display:inline-flex;background:#10151f;border:1px solid var(--line);border-radius:8px;padding:2px;gap:2px}
.segseg .seg{background:transparent;color:var(--mut);border:none;border-radius:6px;padding:6px 12px;font-size:13px;cursor:pointer;font:inherit;line-height:1.2}
.segseg .seg:hover{color:var(--ink)}
.segseg .seg.on{background:#1c2432;color:var(--ink);box-shadow:inset 0 0 0 1px var(--line)}
/* theme cards — three visual previews (System / Light / Dark) */
.themeCards{display:flex;gap:14px;margin:6px 0 4px;flex-wrap:wrap}
.themeCards .tc{background:transparent;border:2px solid var(--line);border-radius:10px;padding:10px;
display:flex;flex-direction:column;align-items:center;gap:8px;cursor:pointer;color:var(--ink);
font:inherit;font-size:13px;min-width:150px;transition:border-color .12s}
.themeCards .tc:hover{border-color:#4b7bec55}
.themeCards .tc.on{border-color:#4b7bec;box-shadow:0 0 0 1px #4b7bec inset}
.themeCards .mock{width:130px;height:82px;border-radius:6px;overflow:hidden;display:block;position:relative;
border:1px solid rgba(255,255,255,.08)}
.themeCards .mock .mm-chrome{position:absolute;left:0;right:0;top:0;height:22px;display:block}
.themeCards .mock .mm-chrome::before{content:"";position:absolute;left:8px;top:6px;width:8px;height:8px;border-radius:50%;background:#f6768a}
.themeCards .mock .mm-chrome::after {content:"";position:absolute;left:22px;top:6px;width:8px;height:8px;border-radius:50%;background:#f6c15c;box-shadow:14px 0 0 #6ec27d}
.themeCards .mock .mm-body{position:absolute;left:0;right:0;top:22px;bottom:0;display:block}
.themeCards .mock-light .mm-chrome{background:#e9ecf2}
.themeCards .mock-light .mm-body {background:#ffffff;background-image:linear-gradient(#0000000c 1px,transparent 1px);background-size:100% 12px;background-position:0 10px}
.themeCards .mock-dark .mm-chrome{background:#141b28}
.themeCards .mock-dark .mm-body {background:#0b0e14;background-image:linear-gradient(#ffffff10 1px,transparent 1px);background-size:100% 12px;background-position:0 10px}
.themeCards .mock-system .mm-chrome{background:linear-gradient(90deg,#141b28 0 50%,#e9ecf2 50% 100%)}
.themeCards .mock-system .mm-body{background:linear-gradient(90deg,#0b0e14 0 50%,#ffffff 50% 100%)}
.themeCards .tc-label{font-weight:500;color:var(--ink)}
.polrow{display:flex;align-items:center;gap:10px;background:#10151f;border:1px solid var(--line);border-radius:8px;padding:8px 12px;font-size:13px;cursor:pointer}
.polrow:hover{background:#141c28}
.polrow input{accent-color:#d6ff3d}
.pmuted{color:var(--mut)}
.ceng{display:flex;align-items:center;gap:8px;background:#10151f;border:1px solid var(--line);border-radius:8px;padding:6px 10px;margin-bottom:6px;font-size:13px}
.ceng .cs{font-size:14px;flex:none}
/* engine checklist */
.eng{display:flex;align-items:center;gap:10px;background:#10151f;border:1px solid var(--line);border-radius:8px;padding:6px 10px;margin-bottom:6px;font-size:13px}
.eng .eic{width:18px;height:18px;flex:none;display:grid;place-items:center}
.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{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}
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
.eng.off{opacity:.55}
.eng.off .enm{color:var(--mut)}
.ehdr{font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);margin:14px 0 6px;padding-top:2px}
.ehdr:first-child{margin-top:0}
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
/* right-click context menu for an engine row */
.ctxmenu{position:fixed;z-index:9999;background:#1c222c;border:1px solid var(--line);border-radius:8px;
box-shadow:0 12px 34px #000c;padding:4px;min-width:180px;font-size:13px;color:var(--ink)}
.ctxmenu .mi{padding:7px 12px;border-radius:5px;cursor:pointer;white-space:nowrap}
.ctxmenu .mi:hover{background:#ffffff10}
.ctxmenu .mi.danger{color:#f6768a}
.ctxmenu .mi.danger:hover{background:rgba(246,118,138,.12)}
@media (prefers-color-scheme: light){
.ctxmenu{background:#ffffff;border-color:rgba(0,0,0,.15)}
.ctxmenu .mi:hover{background:rgba(0,0,0,.05)}
}
/* engine catalog panel — appears under the enabled list when "+ Add" is clicked */
.engcat{margin-top:6px;padding:12px 12px 10px;background:#0e131c;border:1px solid var(--line);border-radius:10px}
.engcat .cat{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:6px;font-size:13px}
.engcat .cat:hover{background:#141b26}
.engcat .cat .eic{width:18px;height:18px;flex:none;display:grid;place-items:center}
.engcat .cat .eic .ei{width:16px;height:16px;border-radius:3px} .engcat .cat .eic .es{font-size:14px}
.engcat .cat .enm{flex:1}
.engcat .cat .kind{font-size:10.5px;letter-spacing:.05em;color:var(--dim);padding:1px 6px;border:1px solid var(--line);border-radius:999px}
.engcat .cat .add{background:transparent;border:1px solid var(--line);color:var(--ink);border-radius:6px;padding:4px 10px;font-size:12px;cursor:pointer}
.engcat .cat .add:hover{background:rgba(214,255,61,.14);border-color:#d6ff3d55;color:#eaffb0}
.engcat .cempty2{color:var(--dim);font-size:12.5px;padding:6px 8px}
.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}
.cempty{color:var(--dim);font-size:12.5px}
/* toggle */
.sw{position:relative;width:46px;height:26px;flex:none;cursor:pointer}
.sw input{opacity:0;width:0;height:0}
.track{position:absolute;inset:0;background:#2b3444;border:1px solid var(--line);border-radius:999px;transition:.15s}
.knob{position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:#8b98a9;transition:.15s}
.sw input:checked + .track{background:rgba(214,255,61,.25);border-color:#d6ff3d55}
.sw input:checked + .track .knob{transform:translateX(20px);background:var(--acid)}
.note{color:var(--dim);font-size:12.5px;margin-top:1.4rem;border-top:1px solid var(--line);padding-top:1rem}
/* light theme (placed last so these win over the dark base rules) */
@media (prefers-color-scheme: light){
:root{ --bg:#eef0f4; --panel:#ffffff; --line:rgba(0,0,0,.11); --ink:#1a1f28; --mut:#4a5262; --dim:#7b8494; }
.side{ background:#f6f8fb; }
.side a:hover{ background:rgba(0,0,0,.05); }
select, .ctl input, .addeng input{ background:#f1f3f7; }
.track{ background:#c8cfdb; }
.knob{ background:#8a93a2; }
code, .ceng, .eng{ background:#eef1f6; }
}
</style></head>
<body>
<div class="app">
<nav class="side">
<div class="brand">⛓ Theseus</div>
<a data-sec="general" class="active">General</a>
<a data-sec="search">Search</a>
<a data-sec="naming">Registries</a>
<a data-sec="performance">Performance</a>
<a data-sec="privacy">Privacy</a>
</nav>
<div class="content">
<!-- GENERAL -->
<section id="general">
<h1>General</h1>
<p class="lede">Changes apply immediately and are saved for next time.</p>
<h2 class="sub" style="border-top:0;padding-top:0;margin-top:0">Startup</h2>
<div class="row">
<div class="txt"><div class="t">Open previous windows and tabs</div><div class="d">Restore the tabs from your last session when Theseus starts.</div></div>
<label class="sw"><input type="checkbox" id="restoreSession"><span class="track"><span class="knob"></span></span></label>
</div>
<h2 class="sub">Appearance</h2>
<p class="subd">Choose a theme for the browser. <b>System</b> follows your operating system's light/dark setting.</p>
<div class="themeCards" id="theme" role="radiogroup" aria-label="Theme">
<button type="button" class="tc" data-val="system" role="radio" aria-checked="false">
<span class="mock mock-system"><span class="mm-chrome"></span><span class="mm-body"></span></span>
<span class="tc-label">System</span>
</button>
<button type="button" class="tc" data-val="light" role="radio" aria-checked="false">
<span class="mock mock-light"><span class="mm-chrome"></span><span class="mm-body"></span></span>
<span class="tc-label">Light</span>
</button>
<button type="button" class="tc" data-val="dark" role="radio" aria-checked="false">
<span class="mock mock-dark"><span class="mm-chrome"></span><span class="mm-body"></span></span>
<span class="tc-label">Dark</span>
</button>
</div>
</section>
<!-- SEARCH -->
<section id="search" hidden>
<h1>Search</h1>
<p class="lede">Pick what your address bar and the toolbar dropdown search with.</p>
<div class="row">
<div class="txt"><div class="t">Default search engine</div><div class="d">Used when you type into the address bar.</div></div>
<div class="ctl"><select id="searchEngine"></select></div>
</div>
<div class="row" style="flex-direction:column;align-items:stretch;gap:10px">
<div class="txt" style="display:flex;align-items:center;justify-content:space-between;gap:12px">
<div>
<div class="t">Additional search engines</div>
<div class="d">These appear in the toolbar dropdown. Drag to reorder. Toggle off to move an engine back to the catalog.</div>
</div>
<button id="engAddBtn" class="btn" type="button">+ Add search engine</button>
</div>
<div id="engineList"></div>
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
<!-- Catalog: hidden until "Add" is clicked. Three tiers, top to bottom:
1. curated built-ins the user hasn't enabled (tier="catalog")
2. wider bank filtered by a search box (tier="extra")
3. custom-URL form -->
<div id="engineCatalog" class="engcat" hidden>
<div class="ehdr">Add from catalog</div>
<div id="catalogList"></div>
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
<div class="ehdr" style="display:flex;align-items:center;justify-content:space-between;gap:8px">
<span>Discover more engines</span>
<input id="engineFilter" type="search" placeholder="Filter by name…" autocomplete="off"
style="background:#1b2330;color:var(--ink);border:1px solid var(--line);border-radius:6px;padding:4px 8px;font-size:12px;min-width:auto;width:170px">
</div>
<div id="extraList"></div>
<div class="ehdr">Or add a custom URL</div>
<div class="addeng">
<input id="engSym" placeholder="🔍" style="max-width:52px;text-align:center;flex:none">
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
<input id="engName" placeholder="Name (e.g. My SearXNG)">
<input id="engUrl" placeholder="https://example.com/search?q=%s">
<button id="engAdd" class="btn">Add</button>
</div>
</div>
</div>
</section>
<!-- NAMING -->
<section id="naming" hidden>
<h1>Registries</h1>
<p class="lede">How Theseus picks between the <b>BCNR / BCDN</b> and <b>ICANN / IANA</b>, when a name exists in both.</p>
<div class="row" style="flex-direction:column;align-items:stretch;gap:10px">
<div class="txt"><div class="t">Collision policy</div>
<div class="d">A name only exists in both registries when its TLD isn't BCNR-unique (e.g. <code>.de</code>). BCNR-unique TLDs (that only exist on BCNR) never conflict.</div></div>
<div id="policyList" style="display:flex;flex-direction:column;gap:6px">
<label class="polrow"><input type="radio" name="collisionPolicy" value="bcnr-first"><span><b>BCDN first</b> <span class="pmuted">— BCDN wins conflicts; falls back to ICANN for anything BCDN doesn't have.</span></span></label>
<label class="polrow"><input type="radio" name="collisionPolicy" value="icann-first"><span><b>ICANN first</b> <span class="pmuted">— ICANN wins conflicts; BCDN fills gaps for non-ICANN TLDs.</span></span></label>
<label class="polrow"><input type="radio" name="collisionPolicy" value="soft"><span><b>Ask each time</b> <span class="pmuted">— an "Open with…" prompt on conflict, remembered per name or per TLD.</span></span></label>
</div>
</div>
<div class="row" style="flex-direction:column;align-items:stretch;gap:8px">
<div class="txt"><div class="t">Remembered choices</div>
<div class="d">"Always use …" picks you made from the switcher or the prompt. Reset them to be asked again.</div></div>
<div id="colSummary" class="pmuted" style="font-size:12.5px"></div>
<div><button id="resetCollisions" class="btn">Reset remembered choices</button></div>
</div>
</section>
<!-- PERFORMANCE -->
<section id="performance" hidden>
<h1>Performance</h1>
<p class="lede">Keep Theseus light on resources.</p>
<div class="row">
<div class="txt"><div class="t">Throttle inactive tabs</div><div class="d">Background and inactive tabs use far less CPU. Recommended.</div></div>
<label class="sw"><input type="checkbox" id="backgroundThrottle"><span class="track"><span class="knob"></span></span></label>
</div>
</section>
<!-- PRIVACY -->
<section id="privacy" hidden>
<h1>Privacy</h1>
<p class="lede">Reduce tracking and lock down device access.</p>
<div class="row">
<div class="txt"><div class="t">WebRTC IP policy</div>
<div class="d">Controls which IP addresses WebRTC may reveal — the same thing the "WebRTC Network Limiter" extension does, built in. <b>Public interface only</b> hides your local IP; <b>Disable non-proxied UDP</b> is strongest. Tor forces the strongest automatically.</div></div>
<div class="ctl"><select id="webrtcMode">
<option value="default">Allow all (default)</option>
<option value="public_only">Public interface only</option>
<option value="public_private">Public + private interfaces</option>
<option value="disable_udp">Disable non-proxied UDP</option>
</select></div>
</div>
<div class="row">
<div class="txt"><div class="t">Block camera</div><div class="d">Deny camera by default — also hides its name from fingerprinting.</div></div>
<label class="sw"><input type="checkbox" id="blockCamera"><span class="track"><span class="knob"></span></span></label>
</div>
<div class="row">
<div class="txt"><div class="t">Block microphone</div><div class="d">Deny microphone by default — also hides its name from fingerprinting.</div></div>
<label class="sw"><input type="checkbox" id="blockMicrophone"><span class="track"><span class="knob"></span></span></label>
</div>
<div class="row">
<div class="txt"><div class="t">Hide media devices</div><div class="d">Blank the labels and IDs of all cameras, microphones <b>and speakers</b> from <code>enumerateDevices()</code> — closes a WebRTC fingerprinting leak, like Firefox.</div></div>
<label class="sw"><input type="checkbox" id="hideMediaDevices"><span class="track"><span class="knob"></span></span></label>
</div>
<h2 class="sub">Anti-fingerprinting</h2>
<p class="subd">For each: <b>Show</b> (real), <b>Hide</b> (neutral value), <b>Spoof</b> (a decoy), or <b>Manual</b> (set your own).</p>
<div class="row">
<div class="txt"><div class="t">Timezone</div><div class="d">What sites read via JavaScript (Intl / Date).</div></div>
<div class="ctl">
<select id="timezoneMode"><option value="show">Show real</option><option value="hide">Hide (UTC)</option><option value="spoof">Spoof (auto)</option><option value="manual">Manual…</option></select>
<input id="timezoneValue" list="tzList" placeholder="pick or type e.g. Europe/Berlin" hidden>
<datalist id="tzList">
<option value="UTC"><option value="Europe/London"><option value="Europe/Berlin"><option value="Europe/Paris"><option value="Europe/Moscow">
<option value="America/New_York"><option value="America/Chicago"><option value="America/Los_Angeles"><option value="America/Sao_Paulo">
<option value="Asia/Tokyo"><option value="Asia/Shanghai"><option value="Asia/Kolkata"><option value="Asia/Dubai"><option value="Australia/Sydney"><option value="Africa/Nairobi">
</datalist>
</div>
</div>
<div class="row">
<div class="txt"><div class="t">Language</div><div class="d">navigator.language and the Accept-Language header. <b>Spoof</b> reports a major world language; <b>Manual</b> lets you type any locale.</div></div>
<div class="ctl">
<select id="languageMode"><option value="show">Show real</option><option value="hide">Hide (en-US)</option><option value="spoof">Spoof (choose)</option><option value="manual">Manual…</option></select>
<select id="languageSpoof" hidden>
<option value="en-US">English</option>
<option value="zh-CN">Chinese (中文)</option>
<option value="es-ES">Spanish (Español)</option>
<option value="hi-IN">Hindi (हिन्दी)</option>
<option value="ar">Arabic (العربية)</option>
<option value="pt-BR">Portuguese (Português)</option>
<option value="ru-RU">Russian (Русский)</option>
<option value="fr-FR">French (Français)</option>
<option value="de-DE">German (Deutsch)</option>
<option value="ja-JP">Japanese (日本語)</option>
</select>
<input id="languageValue" list="langList" placeholder="pick or type e.g. it-IT" hidden>
<datalist id="langList">
<option value="en-US"><option value="en-GB"><option value="zh-CN"><option value="es-ES"><option value="hi-IN"><option value="ar">
<option value="pt-BR"><option value="ru-RU"><option value="fr-FR"><option value="de-DE"><option value="ja-JP"><option value="it-IT"><option value="ko-KR"><option value="nl-NL"><option value="tr-TR">
</datalist>
</div>
</div>
<div class="row">
<div class="txt"><div class="t">Location</div><div class="d"><b>Hide</b> denies geolocation; <b>Spoof</b> reports a chosen region; <b>Manual</b> reports exact coordinates.</div></div>
<div class="ctl">
<select id="locationMode"><option value="show">Show real</option><option value="hide">Hide (block)</option><option value="spoof">Spoof (region)</option><option value="manual">Manual…</option></select>
<select id="locationRegion" hidden>
<option value="europe">Europe</option>
<option value="asia">Asia</option>
<option value="north_america">North America</option>
<option value="south_america">South America</option>
<option value="africa">Africa</option>
<option value="middle_east">Middle East</option>
<option value="australia">Australia</option>
</select>
<div class="coords" id="locationCoords" hidden>
<input id="locationCity" list="cityList" placeholder="pick a city…" style="width:112px">
<input id="locationLat" placeholder="lat"><input id="locationLon" placeholder="lon">
</div>
<datalist id="cityList">
<option value="London"><option value="Berlin"><option value="Paris"><option value="Moscow"><option value="New York"><option value="Los Angeles">
<option value="São Paulo"><option value="Tokyo"><option value="Shanghai"><option value="Mumbai"><option value="Dubai"><option value="Sydney"><option value="Nairobi"><option value="Singapore">
</datalist>
</div>
</div>
<div class="note">These reduce tracking and hide your IP, but a custom browser can still be fingerprinted. For maximum anonymity, use the Tor Browser.</div>
</section>
</div>
</div>
<script>
const C = window.cfg;
// sidebar navigation
const sections = ["general", "search", "naming", "performance", "privacy"];
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
function showSection(sec) {
if (!sections.includes(sec)) return;
document.querySelectorAll(".side a").forEach((x) => x.classList.toggle("active", x.dataset.sec === sec));
for (const s of sections) document.getElementById(s).hidden = (s !== sec);
}
document.querySelectorAll(".side a").forEach((a) => a.onclick = () => showSection(a.dataset.sec));
// Main-process asks us to jump to a section (e.g. picker's "Search settings…"
// click routes to the Search section instead of the General default).
if (C && C.onFocusSection) C.onFocusSection((sec) => showSection(sec));
const TOGGLES = ["restoreSession", "backgroundThrottle", "blockCamera", "blockMicrophone", "hideMediaDevices"];
C.get().then((s) => {
for (const k of TOGGLES) {
const el = document.getElementById(k); if (!el) continue;
el.checked = !!s[k];
el.addEventListener("change", () => C.set(k, el.checked));
}
// search engines: default picker + custom-engine list + add form
const sel = document.getElementById("searchEngine");
const esc = (s) => String(s || "").replace(/</g, "&lt;");
const engIcon = (e) => e.favicon
? `<img class="ei" src="${esc(e.favicon)}" onerror="this.replaceWith(Object.assign(document.createElement('span'),{className:'es',textContent:'${e.sym || "🔍"}'}))">`
: `<span class="es">${e.sym || "🔍"}</span>`;
const ENGINE_KINDS = [
{ key: "search", label: "Search engines" },
{ key: "llm", label: "AI answer engines" },
];
function renderEngines(d) {
// default engine: pick from the ENABLED engines (those shown in the dropdown)
const enabled = d.engines.filter((e) => e.enabled);
// group the dropdown too, so search and LLM don't intermix
sel.innerHTML = ENGINE_KINDS.map(({ key, label }) => {
const opts = enabled.filter((e) => (e.kind || "search") === key)
.map((e) => `<option value="${e.id}">${(e.sym ? e.sym + " " : "")}${esc(e.name)}</option>`).join("");
return opts ? `<optgroup label="${label}">${opts}</optgroup>` : "";
}).join("");
sel.value = d.current;
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
// Main list = engines the user has INSTALLED. The toggle only flips
// enabled/disabled — the row STAYS. Right-click a row → "Remove from
// list" is what actually removes an engine (back to the catalog for
// built-ins, permanently for customs).
const list = document.getElementById("engineList");
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
const installed = d.engines.filter((e) => e.installed);
const rowFor = (e) => `<div class="eng${e.enabled ? "" : " off"}" data-id="${e.id}" data-kind="${e.kind || "search"}" data-builtin="${e.builtin ? 1 : 0}" draggable="true">` +
`<span class="grip" title="Drag to reorder"></span>` +
`<span class="eic">${engIcon(e)}</span><span class="enm">${esc(e.name)}</span>` +
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
`<label class="sw sm" title="${e.enabled ? "Turn off" : "Turn on"}"><input type="checkbox" data-id="${e.id}" ${e.enabled ? "checked" : ""}><span class="track"><span class="knob"></span></span></label>` +
`</div>`;
list.innerHTML = ENGINE_KINDS.map(({ key, label }) => {
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
const rows = installed.filter((e) => (e.kind || "search") === key).map(rowFor).join("");
if (!rows) return "";
return `<div class="ehdr">${label}</div>${rows}`;
}).join("");
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
// Two catalog panes, split by tier — filtered by !installed now, not
// !enabled (a toggled-off engine stays in the enabled list, not here):
// catalog — curated first-class built-ins the user hasn't installed
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
// extra — wider bank, filtered live by the "Discover more" search box
const cat = document.getElementById("catalogList");
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
const extra = document.getElementById("extraList");
const filterInput = document.getElementById("engineFilter");
const catRow = (e) => `<div class="cat" data-id="${e.id}">` +
`<span class="eic">${engIcon(e)}</span>` +
`<span class="enm">${esc(e.name)}</span>` +
`<span class="kind">${(e.kind || "search") === "llm" ? "AI" : "Search"}</span>` +
`<button class="add" data-add="${e.id}">+ Add</button></div>`;
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
const uninstalled = d.engines.filter((e) => e.builtin && !e.installed);
const catalogOff = uninstalled.filter((e) => (e.tier || "catalog") === "catalog");
const extraOff = uninstalled.filter((e) => e.tier === "extra");
if (cat) {
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
cat.innerHTML = catalogOff.length
? catalogOff.map(catRow).join("")
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
: `<div class="cempty2">All curated engines are already in your list. Discover more below or add a custom URL.</div>`;
cat.querySelectorAll(".add").forEach((b) => b.onclick = () => C.setEngineEnabled(b.dataset.add, true).then(renderEngines));
}
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
if (extra) {
const paintExtras = (q) => {
const filt = String(q || "").trim().toLowerCase();
const shown = filt ? extraOff.filter((e) => e.name.toLowerCase().includes(filt)) : extraOff;
extra.innerHTML = shown.length
? shown.map(catRow).join("")
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
: `<div class="cempty2">${filt ? "No engines match that filter." : "All discoverable engines are already in your list."}</div>`;
Theseus: download tracker, search split, discover-more tier, UX polish Bundle of UX + feature work. Split from packaging by intent so the diff is reviewable; the next Theseus rebuild ships it. Features - Download tracker (new): session.on("will-download") → per-item state {id, filename, url, mime, total, received, state, savePath, startedAt} with updated/done event handlers. New downloadsPop WebContentsView loads downloads.html (new file) + downloads-preload.js (new file); panel positioned under a new #downloads toolbar button between search and Tor. Full IPC: downloads-get, toggle/close/resize-downloads, download-open/show/cancel/clear, downloads-clear-all. In-memory only — cross-session persistence is a future addition. Button badge shows active count + spin/done/err color. - Search engines split by kind + tier: * kind: "search" | "llm" — separate headers in picker + settings ("Search with" / "Ask an AI"). Empty sections hidden. * tier: "catalog" | "extra" — Settings now has THREE panes behind the "+ Add search engine" button: curated catalog, wider discoverable bank filtered by a live search input, custom URL form. * DEFAULT_ENABLED unchanged (5 major engines). * Custom user-added engines carry tier="custom" (never in catalog/extra panes). - 9 tier="extra" engines added (all non-login ?q=): Marginalia, Stract, Yep, Presearch, MetaGer, Qwant, Swisscows, Naver, Baidu. Same rot rule as LLMs: if one starts bouncing to a login gate, drop it. Bug fixes - Loadbar collapses to 0px when idle (was reserving a permanent 2px strip below the address bar). .loadbar {height:0} + .loadbar.on {height:2px} + 120ms transition. - Native <select> popup theme sync via :root { color-scheme: dark } + @media(prefers-color-scheme: light). nativeTheme.themeSource already drives prefers-color-scheme, so the OS popup color follows the app theme automatically (fixed light popup on dark app / vice versa). - .ctl layout flipped to flex-direction: row with flex-wrap so anti-fingerprint mode + value fields fit side-by-side. Settings restructure - General section: Startup group at the top ("Open previous windows and tabs" toggle), then Appearance below with three visual THEME CARDS (System / Light / Dark) — small mock-browser previews per theme, Firefox-style, active card gets a blue ring. System pipes through to nativeTheme.themeSource = "system". - Search promoted to a top-level sidebar item between General and Naming. Search-engine controls moved out of General into Search. - Search section: enabled list shows only enabled engines, grouped by kind, drag-reorder within a kind. "+ Add search engine" opens the catalog/extras/custom-URL panel. Search engine catalog trims (already flagged in prior work) - Removed ChatGPT / Claude / You.com (login-gated ?q=). - Removed SearXNG (federated; every single-instance default rots). Docs - TheseusNavigator/PENDING.md and GOTCHAS.md born with this work (see the HANDOFF.md commit for the convention). - PENDING.md's own "session: 2026-08-02:theseus-ux-polish" group will be emptied after this ship lands. Preview harness - _preview.html + _settings-preview.html stubs updated with kind + tier + downloads seed + tier="extra" samples so the preview reflects reality. Both files are gitignored — local only. Coordination - Parallel session's collision-policy work (chrome.html registry chips, popover switcher, Naming section, in-tab collision prompt) already landed in commits 256079d/42b340f/b0d6375/78dddda. This commit adds cleanly on top.
2026-08-02 15:31:47 +02:00
extra.querySelectorAll(".add").forEach((b) => b.onclick = () => C.setEngineEnabled(b.dataset.add, true).then(renderEngines));
};
paintExtras(filterInput ? filterInput.value : "");
if (filterInput && !filterInput.dataset.wired) {
filterInput.dataset.wired = "1";
filterInput.addEventListener("input", () => paintExtras(filterInput.value));
}
}
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
// Toggle: pure on/off in the enabled set — the row stays visible either way.
list.querySelectorAll('input[type="checkbox"]').forEach((cb) => cb.onchange = () => C.setEngineEnabled(cb.dataset.id, cb.checked).then(renderEngines));
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
// Right-click any row → context menu with "Remove from list" (moves a
// built-in back to the catalog; deletes a custom entirely).
list.querySelectorAll(".eng").forEach((row) => {
row.addEventListener("contextmenu", (e) => {
e.preventDefault();
openEngineMenu(row, e.clientX, e.clientY);
});
});
// drag-and-drop reorder — same-kind only (dropping a Search engine into
// the LLM section would just re-group visually on next render, so we
// reject cross-kind drags outright).
let dragId = null;
let dragKind = null;
const sameKind = (row) => row.dataset.kind === dragKind;
list.querySelectorAll(".eng").forEach((row) => {
row.addEventListener("dragstart", (e) => { dragId = row.dataset.id; dragKind = row.dataset.kind; 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) => {
if (!sameKind(row)) { e.dataTransfer.dropEffect = "none"; return; }
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 || !sameKind(row)) 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);
});
});
}
Theseus: shield green polish, picker→Search section, toggle-vs-remove Three follow-up asks from the previous ship: 1. Shield "secure" colour bumped from #4fd1a5 (mint) to #3fb950 — the GitHub-style saturated green, matches the +N/-N diff colour the user pointed at as reference. 2. Engine-picker "Search settings…" now opens the Search section directly instead of General. New IPC channel `focus-section` fires from main after picker-open-settings, carried through settings-preload as `onFocusSection`, and the settings.html sidebar handler exposes showSection(sec) so any section can be focused programmatically. Works for both a fresh settings tab (fires on did-finish-load) and an already-open one (fires immediately). 3. Toggle no longer removes an engine from the list. Two-tier state: INSTALLED (visible in the Settings list) and ENABLED (toggled on in the toolbar dropdown). Toggling off keeps the row visible with an .off class (dimmed 55%). Right-click any row → new context menu with "Remove from list" is what actually removes an engine (built-ins go back to the catalog, customs are dropped entirely). Model changes: - New settings.installedEngines persistent array (defaults to DEFAULT_ENABLED). enabledEngines becomes a subset of installedEngines. - isInstalled(id) helper; allEngines() carries `installed: bool` alongside `enabled`. - New IPC `remove-from-list` (right-click action); exposed as removeFromList in settings-preload. - set-engine-enabled now also INSTALLS when enabling (the catalog "+ Add" flow), preserves installed state when disabling. - add-engine (custom URL) auto-adds the new id to enabledEngines too. - remove-engine (custom delete) prunes from enabledEngines as well. - Never-empty invariant kept: enabledEngines falls back to ["duckduckgo"] if everything gets removed. Settings UI: - Enabled list shows all INSTALLED engines (was: only enabled), rendered with toggle reflecting enabled state; rows carry data-builtin so the context menu picks the right remove IPC. - Catalog panel and Discover-more pane filter on !installed instead of !enabled — a toggled-off engine stays in the enabled list, not here. - Ctxmenu is a floating .ctxmenu div; closes on outside click / Escape. - .eng.off dims the row and mutes the name colour. Preview harness stubs updated to include the `installed` field on every engine + `removeFromList` and `onFocusSection` no-op stubs so _settings-preview.html renders the new UI accurately.
2026-08-06 01:41:31 +02:00
// Floating right-click menu for an engine row. Only one open at a time.
let ctxOpen = null;
function closeEngineMenu() { if (ctxOpen) { ctxOpen.remove(); ctxOpen = null; } }
function openEngineMenu(row, x, y) {
closeEngineMenu();
const id = row.dataset.id;
const builtin = row.dataset.builtin === "1";
const m = document.createElement("div");
m.className = "ctxmenu";
m.innerHTML = `<div class="mi danger" data-act="remove">Remove from list</div>`;
document.body.appendChild(m);
// Position, keeping the menu inside the viewport.
const rect = m.getBoundingClientRect();
const vw = document.documentElement.clientWidth, vh = document.documentElement.clientHeight;
m.style.left = Math.min(x, vw - rect.width - 6) + "px";
m.style.top = Math.min(y, vh - rect.height - 6) + "px";
m.querySelector('[data-act="remove"]').onclick = () => {
closeEngineMenu();
const call = builtin ? C.removeFromList(id) : C.removeEngine(id);
call.then(renderEngines);
};
ctxOpen = m;
setTimeout(() => {
const off = (ev) => { if (!m.contains(ev.target)) { closeEngineMenu(); document.removeEventListener("mousedown", off); document.removeEventListener("keydown", esc); } };
const esc = (ev) => { if (ev.key === "Escape") { closeEngineMenu(); document.removeEventListener("mousedown", off); document.removeEventListener("keydown", esc); } };
document.addEventListener("mousedown", off);
document.addEventListener("keydown", esc);
}, 0);
}
sel.onchange = () => C.set("searchEngine", sel.value);
// appearance (theme) — three visual cards: system | light | dark. Any
// unrecognised saved value falls back to "system" (follow the OS).
const th = document.getElementById("theme");
let themeValue = ["system", "light", "dark"].includes(s.theme) ? s.theme : "system";
const paintTheme = () => th.querySelectorAll(".tc").forEach((b) => {
const on = b.dataset.val === themeValue;
b.classList.toggle("on", on);
b.setAttribute("aria-checked", on ? "true" : "false");
});
paintTheme();
th.querySelectorAll(".tc").forEach((b) => b.onclick = () => {
themeValue = b.dataset.val; paintTheme(); C.set("theme", themeValue);
});
// WebRTC IP policy
const wm = document.getElementById("webrtcMode");
wm.value = s.webrtcMode || "public_only";
wm.onchange = () => C.set("webrtcMode", wm.value);
document.getElementById("engAdd").onclick = () => {
const name = document.getElementById("engName").value.trim();
const url = document.getElementById("engUrl").value.trim();
const sym = document.getElementById("engSym").value.trim();
if (!name || !url.includes("%s")) { alert("Enter a name and a URL containing %s (where the query goes)."); return; }
C.addEngine({ name, url, sym }).then((d) => {
document.getElementById("engName").value = ""; document.getElementById("engUrl").value = ""; document.getElementById("engSym").value = "";
renderEngines(d);
});
};
// "+ Add search engine" toggles the catalog panel below the enabled list.
const catBtn = document.getElementById("engAddBtn");
const catBox = document.getElementById("engineCatalog");
if (catBtn && catBox) {
catBtn.onclick = () => {
const open = catBox.hidden;
catBox.hidden = !open;
catBtn.textContent = open ? " Hide catalog" : "+ Add search engine";
};
}
C.engines().then(renderEngines);
// anti-fingerprinting mode selectors, with value field(s) shown on "manual"
const bind = (mode, showValIf, apply) => {
const m = document.getElementById(mode);
m.value = s[mode] || "show";
apply(m.value === "manual");
m.addEventListener("change", () => { C.set(mode, m.value); apply(m.value === "manual"); });
};
const val = (id) => { const v = document.getElementById(id); v.value = s[id] ?? ""; v.addEventListener("change", () => C.set(id, v.value.trim())); return v; };
const tzV = val("timezoneValue"), lgV = val("languageValue");
val("locationLat"); val("locationLon");
bind("timezoneMode", null, (manual) => tzV.hidden = !manual);
// language: top-10 dropdown when spoofing, free-text locale when manual
const lngMode = document.getElementById("languageMode");
const lngSpoof = document.getElementById("languageSpoof");
lngSpoof.value = s.languageSpoof || "en-US";
lngSpoof.addEventListener("change", () => C.set("languageSpoof", lngSpoof.value));
const applyLng = () => { lngSpoof.hidden = lngMode.value !== "spoof"; lgV.hidden = lngMode.value !== "manual"; };
lngMode.value = s.languageMode || "show";
applyLng();
lngMode.addEventListener("change", () => { C.set("languageMode", lngMode.value); applyLng(); });
// location: region dropdown when spoofing, exact coords when manual
const locMode = document.getElementById("locationMode");
const locRegion = document.getElementById("locationRegion");
const locCoords = document.getElementById("locationCoords");
locRegion.value = s.locationRegion || "europe";
locRegion.addEventListener("change", () => C.set("locationRegion", locRegion.value));
const applyLoc = () => { locRegion.hidden = locMode.value !== "spoof"; locCoords.hidden = locMode.value !== "manual"; };
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]));
});
// ---- Naming section: BCNR/ICANN collision policy + remembered choices ----
function refreshCollisions() {
C.collisionState().then((cs) => {
// pick the current radio
document.querySelectorAll('input[name="collisionPolicy"]').forEach((r) => { r.checked = (r.value === cs.policy); });
const nn = Object.keys(cs.byName || {}).length, tn = Object.keys(cs.byTld || {}).length;
const bc = (cs.bcnrTlds || []).length;
document.getElementById("colSummary").textContent =
`Remembered: ${nn} name${nn === 1 ? "" : "s"}, ${tn} TLD${tn === 1 ? "" : "s"}. `
+ `BCNR-native TLDs on chain: ${bc}.`;
}).catch(() => {});
}
refreshCollisions();
document.querySelectorAll('input[name="collisionPolicy"]').forEach((r) => {
r.addEventListener("change", () => { if (r.checked) C.setCollisionPolicy(r.value).then(refreshCollisions); });
});
document.getElementById("resetCollisions").onclick = () => {
C.resetCollisions().then(refreshCollisions);
};
});
</script>
</body>
</html>