Theseus 0.3.122: Settings restructure — General first-rows, top-level Ariadne & Aegis, Sidebar native-apps card
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.
This commit is contained in:
parent
41eb0acec9
commit
1a31ac0393
3 changed files with 223 additions and 87 deletions
12
chrome.html
12
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));
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
296
settings.html
296
settings.html
|
|
@ -313,16 +313,17 @@
|
|||
<nav class="side">
|
||||
<div class="brand">⛓ Theseus</div>
|
||||
<a data-sec="general" class="active">General</a>
|
||||
<a data-sec="sidebar">Sidebar</a>
|
||||
<a data-sec="language">Language</a>
|
||||
<a data-sec="search">Search</a>
|
||||
<a data-sec="passwords">Passwords</a>
|
||||
<a data-sec="theseusid">Theseus ID</a>
|
||||
<a data-sec="performance">Performance</a>
|
||||
<a data-sec="privacy">Privacy</a>
|
||||
<a data-sec="names">Names & Certificates</a>
|
||||
<a data-sec="plugins">Plug-ins</a>
|
||||
<a data-sec="ariadne">Ariadne's Thread</a>
|
||||
<a data-sec="aegis">Aegis</a>
|
||||
<a data-sec="addons">Extensions</a>
|
||||
<a data-sec="sidebar">Sidebar</a>
|
||||
<a data-sec="apps">Apps</a>
|
||||
</nav>
|
||||
<div class="content">
|
||||
|
|
@ -330,20 +331,47 @@
|
|||
<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>
|
||||
<!-- Default-browser row — moved to the top of General. Hidden until the
|
||||
platform-check (Windows only, today) reveals it. -->
|
||||
<div class="row" id="defaultBrowserRow" hidden>
|
||||
<div class="txt">
|
||||
<div class="t">Make Theseus the default browser</div>
|
||||
<div class="d">Register Theseus for <code>http</code> and <code>https</code> links. Windows still asks you to confirm the switch in <b>Settings › Default apps</b>; the button opens that page.</div>
|
||||
<div class="acts"><button class="btn small ghost" id="openSysDefaults">Open Default Apps…</button></div>
|
||||
</div>
|
||||
<label class="sw"><input type="checkbox" id="defaultBrowser"><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
<div class="row" id="fileAssocsRow" hidden>
|
||||
<div class="txt">
|
||||
<div class="t">Show "Open with Theseus" in file menus</div>
|
||||
<div class="d">Right-click an <code>.html</code>, <code>.htm</code>, <code>.pdf</code>, <code>.svg</code> or <code>.xhtml</code> file and Theseus appears in the Open-with menu. Theseus opens it as a local-file tab.</div>
|
||||
</div>
|
||||
<label class="sw"><input type="checkbox" id="fileAssocs"><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
<!-- Theseus Shield — chevron opens the Shield add-on's own panel; the
|
||||
toggle on the right flips it on/off. State comes from listAddons(). -->
|
||||
<div class="row" id="generalShieldRow">
|
||||
<div class="txt" id="generalShieldOpen" role="button" tabindex="0" style="cursor:pointer" title="Open Theseus Shield">
|
||||
<div class="t">Theseus Shield <span class="chev">›</span></div>
|
||||
<div class="d">Click to open its own settings. Blocks third-party trackers and ads on every site.</div>
|
||||
</div>
|
||||
<label class="sw" title="Turn Shield on/off"><input type="checkbox" id="generalShieldOn"><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
<!-- Startup — the restoreSession toggle lives here as a one-line row. -->
|
||||
<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, even when history is cleared on quit.</div></div>
|
||||
<div class="txt"><div class="t">Startup</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>
|
||||
<div class="row" style="flex-direction:column;align-items:stretch;gap:8px">
|
||||
<div class="txt">
|
||||
<div class="t">Updates</div>
|
||||
<div class="d">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.</div>
|
||||
</div>
|
||||
<div id="updStatus" class="pmuted" style="font-size:12.5px">Loading…</div>
|
||||
<div style="display:flex;gap:8px;flex-wrap:wrap">
|
||||
<button id="updCheck" class="btn">Check for updates</button>
|
||||
</div>
|
||||
<!-- Updates — version + Check button, compressed to one line. The init
|
||||
in initUpdatesPanel() still writes to #updStatus / #updCheck. -->
|
||||
<div class="row">
|
||||
<div class="txt"><div class="t">Updates</div><div class="d" id="updStatus">Loading…</div></div>
|
||||
<div class="ctl"><button id="updCheck" class="btn">Check for updates</button></div>
|
||||
</div>
|
||||
<!-- Theseus ID moved out of the top nav — reach its sub-page from here. -->
|
||||
<div class="row link" data-go="theseusid">
|
||||
<div class="txt"><div class="t">Theseus ID</div><div class="d">Your Silent Mode account, kept in your Theseus Vault.</div></div>
|
||||
<span class="chev">›</span>
|
||||
</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>
|
||||
|
|
@ -400,22 +428,6 @@
|
|||
<div id="blkSummary" class="pmuted" style="font-size:12.5px"></div>
|
||||
<div><button id="resetBlocklist" class="btn">Forget "continue anyway" choices</button></div>
|
||||
</div>
|
||||
<h2 class="sub" id="defHandlingHead" hidden>Default handling</h2>
|
||||
<div class="row" id="defaultBrowserRow" hidden>
|
||||
<div class="txt">
|
||||
<div class="t">Make Theseus the default browser</div>
|
||||
<div class="d">Register Theseus for <code>http</code> and <code>https</code> links. Windows still asks you to confirm the switch in <b>Settings › Default apps</b>; the button opens that page.</div>
|
||||
<div class="acts"><button class="btn small ghost" id="openSysDefaults">Open Default Apps…</button></div>
|
||||
</div>
|
||||
<label class="sw"><input type="checkbox" id="defaultBrowser"><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
<div class="row" id="fileAssocsRow" hidden>
|
||||
<div class="txt">
|
||||
<div class="t">Show "Open with Theseus" in file menus</div>
|
||||
<div class="d">Right-click an <code>.html</code>, <code>.htm</code>, <code>.pdf</code>, <code>.svg</code> or <code>.xhtml</code> file and Theseus appears in the Open-with menu. Theseus opens it as a local-file tab.</div>
|
||||
</div>
|
||||
<label class="sw"><input type="checkbox" id="fileAssocs"><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
<h2 class="sub">About</h2>
|
||||
<div class="row">
|
||||
<div class="txt"><div class="t">Theseus Navigator is free software</div>
|
||||
|
|
@ -486,14 +498,6 @@
|
|||
|
||||
<h2 class="sub" style="border-top:0;padding-top:0;margin-top:0">Name resolvers</h2>
|
||||
|
||||
<div class="row">
|
||||
<div class="txt">
|
||||
<div class="t">Bitcoin Cash Name System (BNS)</div>
|
||||
<div class="d"><i>.x</i>, <i>.bch</i>, <i>.sia</i>, <i>.coin</i>, <i>.dgb</i>, and the rest of the seeded TLDs. Powered by <a data-go="plugins/ariadne" style="color:var(--acid-text);cursor:pointer">Ariadne's Thread</a>.</div>
|
||||
</div>
|
||||
<label class="sw" title="BNS is built in and always on"><input type="checkbox" checked disabled><span class="track"><span class="knob"></span></span></label>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="txt">
|
||||
<div class="t">Ethereum Name Service (ENS)</div>
|
||||
|
|
@ -599,38 +603,69 @@
|
|||
|
||||
<section id="plugins" hidden>
|
||||
<h1>Plug-ins</h1>
|
||||
<p class="lede">Silent Mode components that live alongside Theseus — each with its own on/off, updates and settings page.</p>
|
||||
<p class="lede">Silent Mode components that live alongside Theseus — each with its own on/off, updates and settings page. Ariadne's Thread and Aegis now have their own entries in the sidebar.</p>
|
||||
<div class="row" style="justify-content:flex-end;gap:8px"><a class="btn" style="text-decoration:none;display:inline-flex;align-items:center" href="https://theseus.x/plug-ins/" target="_blank" rel="noopener" title="Current signed versions, hashes and how plug-ins update">About plug-ins on theseus.x ↗</a></div>
|
||||
|
||||
<!-- Ariadne's Thread -->
|
||||
<div class="row plug-row">
|
||||
<div class="txt plug-open" data-go="plugins/ariadne" role="button" tabindex="0" title="Open Ariadne's Thread settings">
|
||||
<div class="t">Ariadne's Thread <span class="pmuted" style="font-weight:400">— system-wide resolver</span> <span class="chev">›</span></div>
|
||||
<div class="d">Resolves BCDN names for every browser on this machine — not just Theseus.</div>
|
||||
<div id="ariadneStatusMain" class="pmuted" style="font-size:12.5px;margin-top:4px">checking…</div>
|
||||
</div>
|
||||
<div class="plug-ctl">
|
||||
<button id="ariadneInstallMain" class="btn small" hidden>Install</button>
|
||||
<button id="ariadneUpdateMain" class="btn small" hidden>Update</button>
|
||||
<button id="ariadneCheckMain" class="btn small" title="Refresh Ariadne status">Refresh</button>
|
||||
<label class="sw" id="ariadneSwWrap" title="Turn Ariadne on/off">
|
||||
<input type="checkbox" id="ariadneToggleMain">
|
||||
<span class="track"><span class="knob"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="row link" data-go="ariadne">
|
||||
<div class="txt"><div class="t">Ariadne's Thread</div><div class="d">System-wide BCDN resolver.</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="row link" data-go="aegis">
|
||||
<div class="txt"><div class="t">Aegis</div><div class="d">Built-in multi-chain wallet.</div></div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<!-- Hidden hooks: the plug-in init code wires several controls below by
|
||||
id (status, toggles, install/update/apply buttons). Keep them in the
|
||||
DOM so the sub-pages (plugins-ariadne / plugins-aegis) still work;
|
||||
moving the plug-ins to top-level nav entries did not change their
|
||||
sub-pages. These are offscreen placeholders that mirror the sub-page
|
||||
controls, read by the shared refresh functions. -->
|
||||
<div hidden aria-hidden="true" id="pluginsMainHooks">
|
||||
<span id="ariadneStatusMain"></span>
|
||||
<button id="ariadneInstallMain"></button>
|
||||
<button id="ariadneUpdateMain"></button>
|
||||
<button id="ariadneCheckMain"></button>
|
||||
<span id="ariadneSwWrap"><input type="checkbox" id="ariadneToggleMain"></span>
|
||||
<span id="aegisStatusMain"></span>
|
||||
<button id="aegisCheckMain"></button>
|
||||
<button id="aegisApplyMain"></button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Aegis -->
|
||||
<div class="row plug-row">
|
||||
<div class="txt plug-open" data-go="plugins/aegis" role="button" tabindex="0" title="Open Aegis settings">
|
||||
<div class="t">Aegis <span class="pmuted" style="font-weight:400">— built-in wallet</span> <span class="chev">›</span></div>
|
||||
<div class="d">Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB). Ships in the box, updates over-the-air.</div>
|
||||
<div id="aegisStatusMain" class="pmuted" style="font-size:12.5px;margin-top:4px">loading…</div>
|
||||
<!-- Top-level landing section for Ariadne's Thread. Chevrons into the
|
||||
existing sub-page under Plug-ins, where install / policy / sources /
|
||||
status / uninstall live. The sub-page keeps its "Plug-ins ›" crumb
|
||||
so Ariadne stays reachable from either entry. -->
|
||||
<section id="ariadne" hidden>
|
||||
<h1>Ariadne's Thread</h1>
|
||||
<p class="lede">A local daemon that resolves BCDN names for <b>every browser on this machine</b>, not just Theseus. Theseus has its own built-in resolver either way; this plug-in is for Chrome, Edge, Firefox and the rest.</p>
|
||||
<div class="row link" data-go="plugins/ariadne">
|
||||
<div class="txt">
|
||||
<div class="t">Open Ariadne's Thread settings</div>
|
||||
<div class="d">Install, update, uninstall; collision policy, sources and the live status report.</div>
|
||||
</div>
|
||||
<div class="plug-ctl">
|
||||
<button id="aegisCheckMain" class="btn small">Check for updates</button>
|
||||
<button id="aegisApplyMain" class="btn small" hidden>Apply update</button>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Top-level landing section for Aegis. The chevron opens the Aegis
|
||||
panel in the sidebar (openPanel), falling back to its sub-page under
|
||||
Plug-ins if the panel isn't registered. -->
|
||||
<section id="aegis" hidden>
|
||||
<h1>Aegis</h1>
|
||||
<p class="lede">Multi-chain wallet (BCH, BTC, TRX, ETH, SOL, SC, DGB) that ships with Theseus and updates over-the-air.</p>
|
||||
<div class="row link" id="aegisOpenRow">
|
||||
<div class="txt">
|
||||
<div class="t">Open the Aegis wallet</div>
|
||||
<div class="d">Opens Aegis in the sidebar panel beside the page.</div>
|
||||
</div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
<div class="row link" data-go="plugins/aegis">
|
||||
<div class="txt">
|
||||
<div class="t">Aegis plug-in settings</div>
|
||||
<div class="d">Version, updates and Apply update now.</div>
|
||||
</div>
|
||||
<span class="chev">›</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
|
@ -1130,7 +1165,17 @@
|
|||
<div class="d">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 <a data-go="search" style="color:var(--acid-text);cursor:pointer">Search</a>).</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="sub">Web apps</h2>
|
||||
<!-- Card A: Theseus native apps (Hermes, Pithos) — bundled system apps.
|
||||
Rendered from sidebarLeftPanels(); filtered to the native-app ids. -->
|
||||
<h2 class="sub">Theseus native apps</h2>
|
||||
<p class="subd">System apps bundled with Theseus. They open from the sidebar strip.</p>
|
||||
<div class="row" style="flex-direction:column;align-items:stretch;gap:6px">
|
||||
<div id="sbNativeApps" style="display:flex;flex-direction:column;gap:6px"></div>
|
||||
</div>
|
||||
<!-- Card B: Third-party apps — the sidebar quick-links (Proton,
|
||||
Telegram, WhatsApp, YouTube, X, …). Same qlList the Web apps
|
||||
section used to drive, with the add-input below. -->
|
||||
<h2 class="sub">Third-party apps</h2>
|
||||
<p class="subd">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.</p>
|
||||
<div class="row" style="flex-direction:column;align-items:stretch;gap:8px">
|
||||
<div id="qlList" style="display:flex;flex-direction:column;gap:6px"></div>
|
||||
|
|
@ -1141,7 +1186,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<h2 class="sub">Extension panels</h2>
|
||||
<p class="subd">Extensions that open from the strip. Switch one off to take it off the strip; the extension keeps working.</p>
|
||||
<p class="subd">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.</p>
|
||||
<div class="row" style="flex-direction:column;align-items:stretch;gap:6px">
|
||||
<div id="sbPanels" style="display:flex;flex-direction:column;gap:6px"></div>
|
||||
</div>
|
||||
|
|
@ -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:<addon>:<panel>" (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) ? `<img src="${esc(p.icon)}" alt="" style="width:20px;height:20px">` : esc(p.icon || (p.title || "?").slice(0, 1));
|
||||
return `<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:8px 12px">
|
||||
<div style="width:28px;height:28px;border-radius:6px;background:rgba(255,255,255,.06);display:grid;place-items:center;flex:none">${icon}</div>
|
||||
<div style="flex:1;min-width:140px;${p.hidden ? "opacity:.5" : ""}"><div style="font-weight:600">${esc(p.title)}</div><div style="font-size:12px;color:var(--mut)">${p.hidden ? "Off the strip" : "On the strip"}${widths[p.id] ? " · " + Number(widths[p.id]) + " px" : ""}</div></div>
|
||||
${B ? B.widthBtnHtml(widths[p.id], p.id) : ""}
|
||||
${B ? B.onStripHtml(!p.hidden, p.id) : ""}</div>`;
|
||||
}
|
||||
async function render() {
|
||||
let panels = []; try { panels = (await C.sidebarLeftPanels()) || []; } catch {}
|
||||
const widths = cur.leftPanelWidths || {};
|
||||
const B = window.__sbButtons;
|
||||
if (!panels.length) { box.innerHTML = `<div class="pmuted" style="font-size:12.5px">No extension opens from the strip.</div>`; return; }
|
||||
box.innerHTML = panels.map((p) => {
|
||||
const icon = /^data:image\//.test(p.icon) ? `<img src="${esc(p.icon)}" alt="" style="width:20px;height:20px">` : esc(p.icon || (p.title || "?").slice(0, 1));
|
||||
return `<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:8px 12px">
|
||||
<div style="width:28px;height:28px;border-radius:6px;background:rgba(255,255,255,.06);display:grid;place-items:center;flex:none">${icon}</div>
|
||||
<div style="flex:1;min-width:140px;${p.hidden ? "opacity:.5" : ""}"><div style="font-weight:600">${esc(p.title)}</div><div style="font-size:12px;color:var(--mut)">${p.hidden ? "Off the strip" : "On the strip"}${widths[p.id] ? " · " + Number(widths[p.id]) + " px" : ""}</div></div>
|
||||
${B ? B.widthBtnHtml(widths[p.id], p.id) : ""}
|
||||
${B ? B.onStripHtml(!p.hidden, p.id) : ""}</div>`;
|
||||
}).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("")
|
||||
: `<div class="pmuted" style="font-size:12.5px">Hermes and Pithos are not available.</div>`;
|
||||
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("")
|
||||
: `<div class="pmuted" style="font-size:12.5px">No extension opens from the strip.</div>`;
|
||||
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 = '<div class="d" style="color:var(--dim)">No extensions installed. Install one from theseus.x/extensions, or drop a folder into the extensions directory.</div>';
|
||||
return;
|
||||
|
|
@ -3071,8 +3197,10 @@
|
|||
+ '<button class="xmore" data-more="' + escapeAttr(a.id) + '" title="More options" aria-label="More options">⋯</button></span>'
|
||||
+ '</div>';
|
||||
};
|
||||
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 += '<div class="xgrp">Enabled</div>' + enabled.map(rowFor).join("");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue