Setup 972f6209639122f32f032d5f2f9fc5a4808e0d4a810f88ae38ec9a1275ac52ac
Portable a9771f054ec36b9aff6ddee958cecf7e84cdacd4d7932aa8385c445aab4d29be
User-visible rename: the Settings tab and its labels say "Extensions"
now instead of "Add-ons". Internal identifiers (disabledAddons, the
addons/ folder, IPC channels, capability strings) stay put — code
churn wasn't worth it, and users only see the user-facing text.
Draggable sidebar. sidebar-preload.js now injects a 5px grip strip
along the LEFT edge of every panel document. mousedown+mousemove
streams delta-x px to main via sidebar-drag IPC; main clamps to
[200, 800] and debounces a save to settings.sidebarWidth. Width is
restored on next launch. The default is still 340. Faint acid-green
highlight on hover so the affordance is discoverable.
New extension capability: session-proxy. An extension whose addon.json
declares "session-proxy" gets api.setSessionProxy(rules) which routes
to session.defaultSession.setProxy — the same primitive Tor already
uses under the hood. Rules can be a string ("socks5://host:port") or
an object matching Electron's setProxy shape; null clears. The
capability is opt-in: an extension without the declaration gets an
error if it tries to call setSessionProxy. This is the framework
surface a private 3-VPS relay extension would build on (extension
folder stays on the operator's disk only; nothing about it appears in
the public build).
Deployed: scp installers + manifest + tools/ + releases/ pages to
VPS, sia-upload of both trees, verified HEAD 200 and manifest 0.2.2.
56 lines
2.6 KiB
JavaScript
56 lines
2.6 KiB
JavaScript
// Preload shared by every add-on sidebar panel. Exposes a small, safe
|
|
// surface to the add-on's HTML. Main-side handlers derive the add-on
|
|
// identity from the sender's URL (the panel is always loaded from
|
|
// somewhere inside <userData>/addons/<id>/), so a random page that
|
|
// happens to see the API shape can't touch another add-on's storage.
|
|
const { contextBridge, ipcRenderer } = require("electron");
|
|
contextBridge.exposeInMainWorld("silentmode", {
|
|
storage: {
|
|
get: (key, fallback = null) => ipcRenderer.invoke("addon-storage-get", key, fallback),
|
|
set: (key, value) => ipcRenderer.invoke("addon-storage-set", key, value),
|
|
all: () => ipcRenderer.invoke("addon-storage-all"),
|
|
},
|
|
// Ask main which panel is currently visible — panels may want to
|
|
// suspend expensive work when hidden.
|
|
onVisibility: (cb) => ipcRenderer.on("sidebar-visibility", (_e, visible) => cb(!!visible)),
|
|
});
|
|
|
|
// Sidebar resize grip. Injected into every panel automatically so panel
|
|
// authors don't have to reinvent it. A thin strip along the LEFT edge
|
|
// (the boundary between the tab area and the sidebar) accepts mousedown
|
|
// and streams drag deltas to main until mouseup. Main clamps the width
|
|
// to [200, 800] and persists it in settings.sidebarWidth.
|
|
window.addEventListener("DOMContentLoaded", () => {
|
|
const grip = document.createElement("div");
|
|
grip.setAttribute("aria-label", "Resize sidebar");
|
|
grip.style.cssText = [
|
|
"position:fixed", "left:0", "top:0", "bottom:0",
|
|
"width:5px", "cursor:col-resize", "z-index:2147483647",
|
|
"background:transparent",
|
|
].join(";");
|
|
// A faint highlight on hover so the affordance is visible.
|
|
grip.addEventListener("mouseenter", () => { grip.style.background = "rgba(214,255,61,.20)"; });
|
|
grip.addEventListener("mouseleave", () => { if (!dragging) grip.style.background = "transparent"; });
|
|
document.body.appendChild(grip);
|
|
let dragging = false;
|
|
grip.addEventListener("mousedown", (e) => {
|
|
if (e.button !== 0) return;
|
|
e.preventDefault();
|
|
dragging = true;
|
|
document.body.style.userSelect = "none";
|
|
grip.style.background = "rgba(214,255,61,.35)";
|
|
});
|
|
window.addEventListener("mousemove", (e) => {
|
|
if (!dragging) return;
|
|
// Moving cursor LEFT = grow sidebar width. movementX is negative left.
|
|
if (e.movementX !== 0) ipcRenderer.invoke("sidebar-drag", -e.movementX);
|
|
});
|
|
const stop = () => {
|
|
if (!dragging) return;
|
|
dragging = false;
|
|
document.body.style.userSelect = "";
|
|
grip.style.background = "transparent";
|
|
};
|
|
window.addEventListener("mouseup", stop);
|
|
window.addEventListener("mouseleave", stop);
|
|
});
|