0.3.38: brand-green scrollbars everywhere + captureTab widens the viewport when sidebar shrinks the tab
Two changes shipped together (main.js touched by both this session and a
parallel session in different regions):
Scrollbars — from the "empty white space should be grey, thumb should
be Bitcoin Cash green" ask:
* new SCROLLBAR_CSS constant + styleScrollbars(wc) helper injects the
theme on every dom-ready
* thumb #0AC18E (BCH primary), track rgba(120,130,150,0.18) subtle
neutral grey so it works on both dark and light surfaces without
hardcoding either; 6px radius, 2px inset via background-clip:padding-box
* modern scrollbar-color on <html> for Chromium 121+; ::-webkit- rules
with !important as the fallback / override for sites that theme
their own scrollbars — scrollbar-width intentionally left alone so
a page that hides scrollbars entirely keeps that behaviour
* hooked into every wc we own: createTab, chrome, popover, enginePicker,
downloadsPop, addressPicker, pwFillPop, linkStatus, sidebar (so every
add-on panel like Aegis picks it up), approvalPop
* fires once immediately if the wc is already past dom-ready when we
attach — fixed views load fast during startup, we'd otherwise miss
captureTab full-page — from the parallel session's screenshot work:
* before Page.captureScreenshot with captureBeyondViewport we now
override Emulation.setDeviceMetricsOverride to the window's full
content width so an open sidebar (or other on-screen chrome that
narrowed the tab view) doesn't clip the shot — capture comes back at
the page's natural full width, not the visible width
* attach the debugger for the call if it isn't attached, detach on
return; clear the metrics override in finally so the tab returns to
its normal layout regardless of success
This commit is contained in:
parent
e36d2b361c
commit
d7d4e7eb4e
2 changed files with 85 additions and 6 deletions
78
main.js
78
main.js
|
|
@ -1610,10 +1610,41 @@ function initAddons() {
|
|||
}
|
||||
if (mode === "full") {
|
||||
// Page.captureScreenshot with captureBeyondViewport does the whole
|
||||
// scrollable page in one shot, no setBounds gymnastics needed.
|
||||
// scrollable page. Before we shoot, force the layout viewport to the
|
||||
// window's full content width via Emulation.setDeviceMetricsOverride
|
||||
// so an open sidebar (or any other on-screen chrome that narrowed
|
||||
// the tab view) doesn't clip the capture — the shot always comes
|
||||
// back at the page's natural full width, not the visible width.
|
||||
const wasAttached = wc.debugger.isAttached();
|
||||
if (!wasAttached) {
|
||||
try { wc.debugger.attach("1.3"); }
|
||||
catch (e) { if (!/already attached/i.test(String(e?.message))) throw e; }
|
||||
}
|
||||
let overrode = false;
|
||||
try {
|
||||
const winW = (win?.getContentBounds()?.width) || 0;
|
||||
const tabB = t.view.getBounds();
|
||||
const need = winW > tabB.width + 24 ? winW : 0;
|
||||
if (need > 0) {
|
||||
// dsf 0 = "let Chromium keep the real device scale factor".
|
||||
// mobile false, deviceScaleFactor 0 keeps typography sane;
|
||||
// height 0 tells CDP "use the current viewport height".
|
||||
await wc.debugger.sendCommand("Emulation.setDeviceMetricsOverride", {
|
||||
width: need, height: 0, deviceScaleFactor: 0, mobile: false,
|
||||
});
|
||||
overrode = true;
|
||||
// A frame or two so the reflow settles before we snapshot.
|
||||
await new Promise((r) => setTimeout(r, 250));
|
||||
}
|
||||
const r = await cdpCapture({ full: true });
|
||||
console.log(`[addons] [${addonId}] captureTab full ${r.width}x${r.height}`);
|
||||
console.log(`[addons] [${addonId}] captureTab full ${r.width}x${r.height}${overrode ? ` (viewport widened to ${need}px)` : ""}`);
|
||||
return { dataUrl: r.dataUrl, width: r.width, height: r.height, host, format };
|
||||
} finally {
|
||||
if (overrode) {
|
||||
try { await wc.debugger.sendCommand("Emulation.clearDeviceMetricsOverride"); } catch {}
|
||||
}
|
||||
if (!wasAttached) { try { wc.debugger.detach(); } catch {} }
|
||||
}
|
||||
}
|
||||
if (mode === "region") {
|
||||
const src = String(opts?.overlaySource || "");
|
||||
|
|
@ -2177,6 +2208,34 @@ function loadErrorPage(t, id, { url, code, desc }) {
|
|||
if (id === activeId) pushNav(t.prov);
|
||||
emitTabs();
|
||||
}
|
||||
// Scrollbar theme injected into every webContents we own — tabs, chrome,
|
||||
// sidebar, all the floating popovers, and every add-on panel host. Track
|
||||
// picks up a subtle neutral grey (works on both dark and light surfaces
|
||||
// without hardcoding either); thumb is the BCH primary #0AC18E so every
|
||||
// scroll surface reads as Silent Mode's. `scrollbar-color` is the modern
|
||||
// standard (Chromium ≥ 121); the ::-webkit- fallback gives us fine control
|
||||
// over width, radius and hover state on older engines. `!important` on the
|
||||
// track / thumb wins over per-page overrides so the branding stays visible
|
||||
// even on sites that theme their own scrollbars — but we deliberately don't
|
||||
// force `scrollbar-width` so a page that has hidden its scrollbars entirely
|
||||
// keeps that behaviour.
|
||||
const SCROLLBAR_CSS = `
|
||||
html { scrollbar-color: #0AC18E rgba(120,130,150,0.18); }
|
||||
::-webkit-scrollbar { width: 12px; height: 12px; background: rgba(120,130,150,0.18) !important; }
|
||||
::-webkit-scrollbar-track { background: rgba(120,130,150,0.18) !important; }
|
||||
::-webkit-scrollbar-thumb { background: #0AC18E !important; border-radius: 6px;
|
||||
border: 2px solid transparent; background-clip: padding-box !important; }
|
||||
::-webkit-scrollbar-thumb:hover { background: #14e0a5 !important; background-clip: padding-box !important; }
|
||||
::-webkit-scrollbar-corner { background: transparent !important; }
|
||||
`;
|
||||
function styleScrollbars(wc) {
|
||||
if (!wc) return;
|
||||
const inject = () => { try { wc.insertCSS(SCROLLBAR_CSS); } catch {} };
|
||||
wc.on("dom-ready", inject);
|
||||
// For a wc that's already past dom-ready when we attach (fixed views load
|
||||
// fast during startup), fire once explicitly.
|
||||
try { if (!wc.isLoading()) inject(); } catch {}
|
||||
}
|
||||
function createTab(initial, opts = {}) {
|
||||
const id = ++tabSeq;
|
||||
// Non-settings tabs get home-preload so the built-in home page can round-
|
||||
|
|
@ -2197,6 +2256,7 @@ function createTab(initial, opts = {}) {
|
|||
// mode users don't get a dark stub while a page paints.
|
||||
try { view.setBackgroundColor(nativeTheme.shouldUseDarkColors ? "#0b0e14" : "#ffffff"); } catch {}
|
||||
const wc = view.webContents;
|
||||
styleScrollbars(wc);
|
||||
try { wc.setWebRTCIPHandlingPolicy(webrtcPolicy()); } catch {}
|
||||
try { wc.setBackgroundThrottling(settings.backgroundThrottle); } catch {}
|
||||
applyFingerprint(wc);
|
||||
|
|
@ -2398,52 +2458,64 @@ function createWindow() {
|
|||
});
|
||||
chrome = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "preload.js") } });
|
||||
win.contentView.addChildView(chrome);
|
||||
styleScrollbars(chrome.webContents);
|
||||
chrome.webContents.loadFile("chrome.html");
|
||||
// Floating site-info overlay (hidden until the address-bar badge is clicked).
|
||||
popover = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "popover-preload.js") } });
|
||||
try { popover.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(popover);
|
||||
styleScrollbars(popover.webContents);
|
||||
popover.webContents.loadFile("popover.html");
|
||||
popover.setVisible(false);
|
||||
// Floating engine-picker overlay (custom dropdown with real favicons).
|
||||
enginePicker = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "engine-picker-preload.js") } });
|
||||
try { enginePicker.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(enginePicker);
|
||||
styleScrollbars(enginePicker.webContents);
|
||||
enginePicker.webContents.loadFile("engine-picker.html");
|
||||
enginePicker.setVisible(false);
|
||||
// Floating downloads panel — shows active + recent downloads.
|
||||
downloadsPop = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "downloads-preload.js") } });
|
||||
try { downloadsPop.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(downloadsPop);
|
||||
styleScrollbars(downloadsPop.webContents);
|
||||
downloadsPop.webContents.loadFile("downloads.html");
|
||||
downloadsPop.setVisible(false);
|
||||
// Floating address-bar suggestions dropdown.
|
||||
addressPicker = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "address-picker-preload.js") } });
|
||||
try { addressPicker.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(addressPicker);
|
||||
styleScrollbars(addressPicker.webContents);
|
||||
addressPicker.webContents.loadFile("address-picker.html");
|
||||
addressPicker.setVisible(false);
|
||||
// Floating password-fill picker.
|
||||
pwFillPop = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "pw-fill-preload.js") } });
|
||||
try { pwFillPop.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(pwFillPop);
|
||||
styleScrollbars(pwFillPop.webContents);
|
||||
pwFillPop.webContents.loadFile("pw-fill.html");
|
||||
pwFillPop.setVisible(false);
|
||||
// Link-hover status pill (bottom-left of window).
|
||||
linkStatus = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "link-status-preload.js") } });
|
||||
try { linkStatus.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(linkStatus);
|
||||
styleScrollbars(linkStatus.webContents);
|
||||
linkStatus.webContents.loadFile("link-status.html");
|
||||
linkStatus.setVisible(false);
|
||||
// Add-on sidebar host. Doesn't loadFile until an add-on panel is opened.
|
||||
// Add-on sidebar host. Doesn't loadFile until an add-on panel is opened —
|
||||
// styleScrollbars hooks dom-ready, which fires per navigation, so every
|
||||
// panel loaded into this view (Aegis, Screenshot, etc.) picks up the
|
||||
// brand scrollbar the moment its DOM is ready.
|
||||
sidebar = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "sidebar-preload.js") } });
|
||||
win.contentView.addChildView(sidebar);
|
||||
styleScrollbars(sidebar.webContents);
|
||||
sidebar.setVisible(false);
|
||||
// Add-on approval overlay (approval-modal capability). Transparent view
|
||||
// over the tab area, loaded once, shown per request.
|
||||
approvalPop = new WebContentsView({ webPreferences: { preload: path.join(__dirname, "approval-preload.js") } });
|
||||
try { approvalPop.setBackgroundColor("#00000000"); } catch {}
|
||||
win.contentView.addChildView(approvalPop);
|
||||
styleScrollbars(approvalPop.webContents);
|
||||
approvalPop.webContents.loadFile("approval.html");
|
||||
approvalPop.setVisible(false);
|
||||
chrome.webContents.once("did-finish-load", () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "theseus-navigator",
|
||||
"version": "0.3.37",
|
||||
"version": "0.3.38",
|
||||
"description": "Theseus Navigator — a browser that follows the thread. By Silent Mode, a Deviant project.",
|
||||
"author": "Silent Mode",
|
||||
"main": "main.js",
|
||||
|
|
@ -11,15 +11,22 @@
|
|||
"dist": "electron-builder --win nsis portable"
|
||||
},
|
||||
"dependencies": {
|
||||
"@bch-wc2/interfaces": "^0.0.16",
|
||||
"@bitauth/libauth": "^3.1.0-next.8",
|
||||
"@bitcoinerlab/secp256k1": "^1.2.0",
|
||||
"@noble/curves": "^2.0.1",
|
||||
"@noble/hashes": "^2.0.1",
|
||||
"@scure/bip32": "^2.0.1",
|
||||
"@wizardconnect/core": "^0.2.4",
|
||||
"@wizardconnect/wallet": "^0.2.3",
|
||||
"bip32": "^4.0.0",
|
||||
"bip39": "^3.1.0",
|
||||
"bitcoinjs-lib": "^6.1.7",
|
||||
"ecpair": "^2.1.0",
|
||||
"eventemitter3": "^5.0.1",
|
||||
"fetch-socks": "^1.3.3",
|
||||
"isomorphic-ws": "^5.0.0",
|
||||
"lossless-json": "^4.0.2",
|
||||
"nostr-tools": "^2.10.4",
|
||||
"psl": "^1.15.0",
|
||||
"socks-proxy-agent": "^10.1.0",
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue