From 1a31ac0393e355bcb7834ff0af0997abc565aeb5 Mon Sep 17 00:00:00 2001 From: Local Dev Date: Tue, 27 Oct 2026 18:04:49 +0200 Subject: [PATCH] =?UTF-8?q?Theseus=200.3.122:=20Settings=20restructure=20?= =?UTF-8?q?=E2=80=94=20General=20first-rows,=20top-level=20Ariadne=20&=20A?= =?UTF-8?q?egis,=20Sidebar=20native-apps=20card?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings page UX restructure. - Nav bar: reordered to General, Language, Search, Passwords, Performance, Privacy, Names & Certificates, Plug-ins, Ariadne's Thread, Aegis, Extensions, Sidebar, Apps. Dropped the top-level Theseus ID entry; Theseus ID is reachable from General now. Added two new top-level entries — Ariadne's Thread and Aegis — each a small landing section that chevrons into the existing plug-in sub-page (Ariadne) or opens the wallet panel via openPanel("aegis:main") (Aegis). - General section: first four rows are now Make-Theseus-default, Theseus Shield (chevron + on/off toggle), Startup (restore tabs), Updates (version + Check button), followed by a Theseus ID chevron row. Appearance / Developer tools / Registries / About stay below in the same order. Removed the "Default handling" sub-head; the default- browser and file-associations rows moved to the top. The Shield row uses listAddons() + setAddonEnabled("blocker", on) for state; the chevron falls back to openPanel("blocker:main"). - Names & Certificates: dropped the always-on BNS row at the top. - Plug-ins main page: Ariadne's Thread and Aegis rows removed — they moved to top-level. The page now links into the new landing sections. Hidden placeholders keep the DOM ids (ariadneStatusMain, aegisCheckMain …) so the shared refresh code keeps working. Sub-pages (plugins- ariadne, plugins-aegis) untouched. - Extensions list: Hermes and Pithos hidden from the list (they live in the Sidebar card now). docx-editor and pdf-editor sort last within each group so smaller utilities stay near the top. - Toolbar add-on strip (chrome.html): same last-sort rule for docx-editor and pdf-editor, applied to the rank() ordering so unknown keys without a saved dockOrder keep registration order and the editors land past them. - Sidebar section: added two cards at the top. "Theseus native apps" (Hermes + Pithos) and "Third-party apps" (the sidebar quick-links / Web apps). Native apps appear first. The Extension panels section still lists everything else that opens from the strip; Hermes and Pithos are filtered out of it so they don't appear twice. - Version bumped to 0.3.122. No new IPCs — reuses listAddons, setAddonEnabled, openPanel, sidebarLeftPanels, addonInvoke. --- chrome.html | 12 +- package.json | 2 +- settings.html | 296 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 223 insertions(+), 87 deletions(-) diff --git a/chrome.html b/chrome.html index 3bb2da43..1994c0e5 100644 --- a/chrome.html +++ b/chrome.html @@ -905,11 +905,19 @@ lastButtons.push({ kind: "menu", key: "m:" + m.addonId, addonId: m.addonId, icon: String(m.icon || "•"), title: m.title || m.addonId, items: m.items || [] }); } // User prefs: drag-reorder order and buttons hidden via the right-click - // menu. Unknown keys keep registration order after the ordered ones. + // menu. Unknown keys keep registration order after the ordered ones; the + // document editors sort LAST so smaller utilities (Notepad, Screenshot, + // Translate…) stay near the start of the strip. if (d.dock) lastDock = d.dock; const order = Array.isArray(lastDock.order) ? lastDock.order : []; const hidden = new Set(Array.isArray(lastDock.hidden) ? lastDock.hidden : []); - const rank = (k) => { const i = order.indexOf(k); return i < 0 ? order.length : i; }; + const LAST_ADDON_IDS = new Set(["docx-editor", "pdf-editor"]); + const addonIdOf = (k) => k.startsWith("p:") ? k.slice(2).split(":")[0] : k.slice(2); + const rank = (k) => { + const i = order.indexOf(k); + if (i >= 0) return i; + return LAST_ADDON_IDS.has(addonIdOf(k)) ? order.length + 1 : order.length; + }; lastButtons = lastButtons.filter((b) => !hidden.has(b.key)).map((b, i) => ({ ...b, i })).sort((a, b) => rank(a.key) - rank(b.key) || a.i - b.i); lastPanels = lastPanels.filter((p) => !hidden.has("p:" + p.panelId)); lastMenus = lastMenus.filter((m) => !hidden.has("m:" + m.addonId)); diff --git a/package.json b/package.json index abdf5df2..2ef56bf1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "theseus-navigator", - "version": "0.3.121", + "version": "0.3.122", "license": "MPL-2.0", "description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.", "author": "Silent Mode", diff --git a/settings.html b/settings.html index debee010..020fbd61 100644 --- a/settings.html +++ b/settings.html @@ -313,16 +313,17 @@
@@ -330,20 +331,47 @@

General

Changes apply immediately and are saved for next time.

-

Startup

+ + + + +
+
+
Theseus Shield ›
+
Click to open its own settings. Blocks third-party trackers and ads on every site.
+
+ +
+
-
Open previous windows and tabs
Restore the tabs from your last session when Theseus starts, even when history is cleared on quit.
+
Startup
Restore the tabs from your last session when Theseus starts.
-
-
-
Updates
-
Theseus checks the release manifest shortly after launch — and retries with backoff if that first attempt is offline — then every 6 hours while it is running. Click below to check right now.
-
-
Loading…
-
- -
+ +
+
Updates
Loading…
+
+
+ +

Appearance

Choose a theme for the browser. System follows your operating system's light/dark setting.

@@ -400,22 +428,6 @@
- - -

About

Theseus Navigator is free software
@@ -486,14 +498,6 @@

Name resolvers

-
-
-
Bitcoin Cash Name System (BNS)
-
.x, .bch, .sia, .coin, .dgb, and the rest of the seeded TLDs. Powered by Ariadne's Thread.
-
- -
-
Ethereum Name Service (ENS)
@@ -599,38 +603,69 @@ - -
-
-
Aegis — built-in wallet ›
-
Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB). Ships in the box, updates over-the-air.
-
loading…
+ + + + + @@ -1130,7 +1165,17 @@
The sparkle button at the bottom of the strip opens your default AI engine (right-click it to pick from any you've enabled, or set up more under Search).
-

Web apps

+ +

Theseus native apps

+

System apps bundled with Theseus. They open from the sidebar strip.

+
+
+
+ +

Third-party apps

Sites that open in the panel. Switch one off to take it off the strip; it stays here, still signed in, for switching back on. A site you installed as an app can be added from Apps.

@@ -1141,7 +1186,7 @@

Extension panels

-

Extensions that open from the strip. Switch one off to take it off the strip; the extension keeps working.

+

Extensions that open from the strip. Switch one off to take it off the strip; the extension keeps working. The native apps above live under their own card.

@@ -1240,7 +1285,7 @@ try { if (C && typeof C.appVersion === "function") { C.appVersion().then((v) => { - updStatus.textContent = v ? `You're on v${v}.` : "Version unavailable — try Check for updates."; + updStatus.textContent = v ? `Theseus current version v${v}.` : "Version unavailable — try Check for updates."; }).catch((e) => { updStatus.textContent = "Could not read version: " + (e?.message || e) + " — try Check for updates."; }); @@ -1272,7 +1317,6 @@ (async () => { const row = document.getElementById("defaultBrowserRow"); const assocRow = document.getElementById("fileAssocsRow"); - const head = document.getElementById("defHandlingHead"); const defBrowser = document.getElementById("defaultBrowser"); const assoc = document.getElementById("fileAssocs"); const openSys = document.getElementById("openSysDefaults"); @@ -1280,7 +1324,7 @@ try { const d = await cfg.defaultBrowserState(); if (!d.supported) return; - head.hidden = false; row.hidden = false; assocRow.hidden = false; + row.hidden = false; assocRow.hidden = false; defBrowser.checked = !!d.isDefault; assoc.checked = !!d.hasAssocs; } catch {} @@ -1301,6 +1345,51 @@ openSys.addEventListener("click", () => cfg.openSystemDefaults()); refresh(); })(); + // General › Theseus Shield row — chevron opens the Shield add-on's panel; + // toggle flips the blocker on/off. State comes from listAddons(). + (function () { + const openEl = document.getElementById("generalShieldOpen"); + const onEl = document.getElementById("generalShieldOn"); + if (!openEl || !onEl) return; + const openShield = () => { + // Prefer the add-on's own panel; fall back to the Extensions page. + if (C && typeof C.openPanel === "function") { + try { C.openPanel("blocker:main"); return; } catch {} + } + try { showSection("addons"); } catch {} + }; + openEl.addEventListener("click", openShield); + openEl.addEventListener("keydown", (e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); openShield(); } }); + async function refresh() { + try { + const list = await (C.listAddons ? C.listAddons() : Promise.resolve({})); + const blocker = ((list && list.installed) || []).find((a) => a.id === "blocker"); + onEl.checked = !!(blocker && blocker.enabled); + } catch {} + } + onEl.addEventListener("change", async () => { + try { if (C.setAddonEnabled) await C.setAddonEnabled("blocker", onEl.checked); } catch {} + // Give the host a moment to flip, then refresh so the toggle shows the + // real state (an add-on that refused the flip stays as it was). + setTimeout(refresh, 400); + }); + refresh(); + document.addEventListener("section", (e) => { if (e.detail === "general") refresh(); }); + })(); + // Aegis landing-section chevron — opens Aegis's own sidebar panel. Falls + // back to the plug-in sub-page if the panel isn't registered. + (function () { + const row = document.getElementById("aegisOpenRow"); + if (!row) return; + row.addEventListener("click", async (e) => { + // The row's own data-go would route to Settings, not the Aegis panel. + e.preventDefault(); e.stopPropagation(); + if (C && typeof C.openPanel === "function") { + try { await C.openPanel("aegis:main"); return; } catch {} + } + try { showSection("plugins/aegis"); } catch {} + }); + })(); // sidebar navigation // "naming" is intentionally absent: the Registries section was folded // into General in 0.3.21. Leaving the id in this list threw a @@ -1672,26 +1761,47 @@ if (C.onSettingsUpdate) C.onSettingsUpdate((next) => { cur = next; render(next.quickLinks || []); }); })(); // ---- Extension panels on the strip (Sidebar) --------------------------- + // Two cards: native apps (Hermes + Pithos) are rendered into #sbNativeApps, + // every other left panel into #sbPanels. The native-id test matches a + // panel.id of the form "p::" (what sidebar-left-panels + // returns), so hermes:main / pithos:main land in the native card. (function () { + const nativeBox = document.getElementById("sbNativeApps"); const box = document.getElementById("sbPanels"); - if (!box || !C.sidebarLeftPanels) return; + if ((!nativeBox && !box) || !C.sidebarLeftPanels) return; const esc = (v) => String(v || "").replace(/[&<>"']/g, (c) => ({ "&":"&","<":"<",">":">","\"":""","'":"'" })[c]); + const NATIVE_IDS = new Set(["hermes", "pithos"]); + const addonOf = (pid) => String(pid || "").replace(/^p:/, "").split(":")[0]; + const isNative = (p) => NATIVE_IDS.has(addonOf(p.id)); let cur = s; + function rowHtml(p, widths, B) { + const icon = /^data:image\//.test(p.icon) ? `` : esc(p.icon || (p.title || "?").slice(0, 1)); + return `
+
${icon}
+
${esc(p.title)}
${p.hidden ? "Off the strip" : "On the strip"}${widths[p.id] ? " · " + Number(widths[p.id]) + " px" : ""}
+ ${B ? B.widthBtnHtml(widths[p.id], p.id) : ""} + ${B ? B.onStripHtml(!p.hidden, p.id) : ""}
`; + } async function render() { let panels = []; try { panels = (await C.sidebarLeftPanels()) || []; } catch {} const widths = cur.leftPanelWidths || {}; const B = window.__sbButtons; - if (!panels.length) { box.innerHTML = `
No extension opens from the strip.
`; return; } - box.innerHTML = panels.map((p) => { - const icon = /^data:image\//.test(p.icon) ? `` : esc(p.icon || (p.title || "?").slice(0, 1)); - return `
-
${icon}
-
${esc(p.title)}
${p.hidden ? "Off the strip" : "On the strip"}${widths[p.id] ? " · " + Number(widths[p.id]) + " px" : ""}
- ${B ? B.widthBtnHtml(widths[p.id], p.id) : ""} - ${B ? B.onStripHtml(!p.hidden, p.id) : ""}
`; - }).join(""); - if (B) B.wireOnStrip(box); - if (window.__sbWireWidth) window.__sbWireWidth(box); + const native = panels.filter(isNative); + const rest = panels.filter((p) => !isNative(p)); + if (nativeBox) { + nativeBox.innerHTML = native.length + ? native.map((p) => rowHtml(p, widths, B)).join("") + : `
Hermes and Pithos are not available.
`; + if (B) B.wireOnStrip(nativeBox); + if (window.__sbWireWidth) window.__sbWireWidth(nativeBox); + } + if (box) { + box.innerHTML = rest.length + ? rest.map((p) => rowHtml(p, widths, B)).join("") + : `
No extension opens from the strip.
`; + if (B) B.wireOnStrip(box); + if (window.__sbWireWidth) window.__sbWireWidth(box); + } } render(); document.addEventListener("section", (e) => { if (String(e.detail) === "sidebar") render(); }); @@ -3048,10 +3158,26 @@ "session-proxy": "Can route the browser's traffic through a proxy it controls.", "tab-control": "Can open, read and operate your web tabs for a program on this computer that you connect to it, on sites you approve one by one.", }; + // Extensions list ordering rules: + // HIDDEN_IDS — Hermes and Pithos are Theseus native apps; they appear in + // the Sidebar settings card instead of here. + // LAST_IDS — docx-editor and pdf-editor sort last within each group so + // the smaller utilities (Notepad, Screenshot, Translate, …) + // stay near the top of the list. + const ADDONS_HIDDEN_IDS = new Set(["hermes", "pithos"]); + const ADDONS_LAST_IDS = ["docx-editor", "pdf-editor"]; + function addonSortLast(a, b) { + const ai = ADDONS_LAST_IDS.indexOf(a.id); + const bi = ADDONS_LAST_IDS.indexOf(b.id); + const ar = ai < 0 ? -1 : ai; + const br = bi < 0 ? -1 : bi; + return ar - br; + } function renderAddons(snap) { lastAddonSnap = snap; // Plug-ins (Aegis, category "plugin") have their own cards under Plug-ins. - const items = ((snap && snap.installed) || []).filter((a) => a.category !== "plugin"); + const items = ((snap && snap.installed) || []) + .filter((a) => a.category !== "plugin" && !ADDONS_HIDDEN_IDS.has(a.id)); if (!items.length) { addonsList.innerHTML = '
No extensions installed. Install one from theseus.x/extensions, or drop a folder into the extensions directory.
'; return; @@ -3071,8 +3197,10 @@ + '' + '
'; }; - const enabled = items.filter((a) => !a.error && a.enabled); - const disabled = items.filter((a) => !a.error && !a.enabled); + // Stable sort inside each bucket keeps registration order; the compare + // only moves ADDONS_LAST_IDS to the end of their bucket. + const enabled = items.filter((a) => !a.error && a.enabled).sort(addonSortLast); + const disabled = items.filter((a) => !a.error && !a.enabled).sort(addonSortLast); const failed = items.filter((a) => a.error); let html = ""; if (enabled.length) html += '
Enabled
' + enabled.map(rowFor).join("");