From 19dc0649dd39bf6509a1631f4caf79806e93c2cb Mon Sep 17 00:00:00 2001 From: Local Dev Date: Sun, 4 Oct 2026 21:53:39 +0200 Subject: [PATCH] Theseus Settings: a Sidebar section for the left strip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Quick links sat in a small block under General, and the panel behaviour added this week (per-app widths, pins, the Opera-style auto-hide) had no place in Settings at all. Settings › Sidebar now holds the strip switch, the web apps (drag to reorder like Search engines, pin, reset a remembered width, remove), the extension panels on the strip (show or hide each one, pin, reset width) and three switches for when the open panel steps aside: a new tab, the right side panel opening, a click in the page. Apps gains "Add to sidebar", so an installed site can also open in the strip. --- main.js | 29 ++++++-- settings-preload.js | 1 + settings.html | 160 +++++++++++++++++++++++++++++++++++++------- 3 files changed, 159 insertions(+), 31 deletions(-) diff --git a/main.js b/main.js index c7544d6d..7f33b489 100644 --- a/main.js +++ b/main.js @@ -584,6 +584,15 @@ const SETTINGS_DEFAULTS = { { id: "x", url: "https://x.com/", title: "X" }, { id: "youtube", url: "https://www.youtube.com/", title: "YouTube" }, ], + // Settings › Sidebar. Per-app panel widths and pins (keys "q:" / + // "p:"), extension panels the user took off the strip, and when + // the open panel steps aside (Opera's rules, each one switchable). + leftPanelWidths: {}, + leftPanelPinned: {}, + leftPanelsHidden: [], + sidebarHideOnNewTab: true, + sidebarHideOnRightPanel: true, + sidebarHideOnPageClick: true, // Toolbar bar sizes. The URL bar is flex:1 by default so it eats all // remaining space; `compact`/`medium` cap it so the extension dock has // room to grow. The search box is fixed-width; hidden removes it. @@ -888,7 +897,7 @@ const SETTINGS_ONLY = new Set([ "password-add", "password-generate", "password-get", "password-list", "password-lock", "password-remove", "password-setup", "password-status", "password-unlock", "password-update", "recheck-update", "remove-from-list", "set-engine-enabled", "set-engine-order", - "settings-open-panel", "settings-section", "tor-state", + "settings-open-panel", "settings-section", "sidebar-left-panels", "tor-state", "webapps-list", "webapps-open", "webapps-remove", "vault-pin-clear", "vault-pin-set", "vault-pin-status", "vault-pin-unlock", // Raw seeds and WIFs. No page uses these (add-ons go through the @@ -3532,7 +3541,7 @@ function setSidebar(show, panelId) { sidebarActivePanelId = panel.panelId; try { sidebar.webContents.loadFile(panel.pageFile); } catch (e) { console.warn("sidebar loadFile failed:", e?.message); } } - hideLeftPanels(); + if (settings.sidebarHideOnRightPanel !== false) hideLeftPanels(); sidebarVisible = true; sidebar.setVisible(true); try { win.contentView.removeChildView(sidebar); win.contentView.addChildView(sidebar); } catch {} @@ -5013,7 +5022,7 @@ ipcMain.handle("navigate", (e, input) => { return navigateTab(t ? t.id : activeId, input); }); ipcMain.handle("search", (_e, q) => { if (leftPanelMax) setLeftPanelMax(false); return navigateTab(activeId, SEARCH(q)); }); -ipcMain.handle("new-tab", () => { hideLeftPanels(); return createTab(); }); +ipcMain.handle("new-tab", () => { if (settings.sidebarHideOnNewTab !== false) hideLeftPanels(); return createTab(); }); ipcMain.handle("close-tab", (_e, id) => closeTab(id)); ipcMain.handle("switch-tab", (_e, id) => setActive(id)); // Tab context menu backing IPCs. All scoped to a specific tab id so the @@ -7927,10 +7936,11 @@ ipcMain.handle("settings-set", (_e, key, val) => { // Quick-links strip: re-layout + push the new state to the strip's view so // show/hide and link edits take effect without a relaunch. If the active // panel's link was removed, close the panel. - if (key === "quickLinksShow" || key === "quickLinks") { + if (key === "quickLinksShow" || key === "quickLinks" || key === "leftPanelWidths" || key === "leftPanelPinned" || key === "leftPanelsHidden") { if (activeQuickLinkId && !(settings.quickLinks || []).some((L) => L.id === activeQuickLinkId)) { activeQuickLinkId = null; } + if (leftPanelId && leftPanelHidden(leftPanelId)) closeLeftPanel(); if (key === "quickLinksShow" && !settings.quickLinksShow) closeLeftPanel(); layout(); emitQuickLinksState(); @@ -7952,12 +7962,19 @@ function quickLinksPayload() { links: settings.quickLinks || [], openId: leftPanelId ? "p:" + leftPanelId : activeQuickLinkId, pinned: leftPanelPinned(), - panels: leftPanels().map((p) => ({ id: "p:" + p.panelId, title: p.addonName || p.title, icon: p.icon || "" })), + panels: leftPanels().filter((p) => !leftPanelHidden(p.panelId)).map((p) => ({ id: "p:" + p.panelId, title: p.addonName || p.title, icon: p.icon || "" })), }; } function emitQuickLinksState() { try { quicklinks?.webContents.send("quicklinks-state", quickLinksPayload()); } catch {} } +function leftPanelHidden(panelId) { + return Array.isArray(settings.leftPanelsHidden) && settings.leftPanelsHidden.includes("p:" + panelId); +} +// Settings › Sidebar lists every left extension panel, including hidden ones. +ipcMain.handle("sidebar-left-panels", () => leftPanels().map((p) => ({ + id: "p:" + p.panelId, title: p.addonName || p.title, icon: p.icon || "", hidden: leftPanelHidden(p.panelId), +}))); function leftPanelKey() { if (activeQuickLinkId) return "q:" + activeQuickLinkId; if (leftPanelId) return "p:" + leftPanelId; @@ -7997,7 +8014,7 @@ ipcMain.handle("quicklinks-pin", (e, on) => { }); // home-preload reports a pointerdown in a web tab's page. ipcMain.on("tab-pointerdown", (e) => { - if (!leftPanelKey() || leftPanelPinned()) return; + if (settings.sidebarHideOnPageClick === false || !leftPanelKey() || leftPanelPinned()) return; const t = tabs.find((x) => x.view?.webContents === e.sender); if (!t || t.id !== activeId) return; hideLeftPanels(); diff --git a/settings-preload.js b/settings-preload.js index 2f217317..1fb40a32 100644 --- a/settings-preload.js +++ b/settings-preload.js @@ -94,6 +94,7 @@ contextBridge.exposeInMainWorld("cfg", { recheckUpdate: () => ipcRenderer.invoke("recheck-update"), // Sites installed as apps (Settings › Apps). webapps: () => ipcRenderer.invoke("webapps-list"), + sidebarLeftPanels: () => ipcRenderer.invoke("sidebar-left-panels"), webappOpen: (key) => ipcRenderer.invoke("webapps-open", String(key || "")), webappRemove: (key) => ipcRenderer.invoke("webapps-remove", String(key || "")), onWebappsChanged: (cb) => ipcRenderer.on("webapps-changed", () => cb()), diff --git a/settings.html b/settings.html index de69bef6..58249a04 100644 --- a/settings.html +++ b/settings.html @@ -265,6 +265,7 @@