authorgravatar for 92423096+nateEc@users.noreply.github.comYukun Shan <92423096+nateEc@users.noreply.github.com> 2026-07-18 03:52:42+08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-17 19:52:42+00:00
log7b8d12618b3d857874a1cc709d11c5df087b6390
treeaf7f38e9c637b7b2bde2f2f6d53f63f6cf995f82
parentbcd640bf4d81df20ac5686ff0ca86d861f909be2
signature Signed by PGP key B5690EEEBB952194

fix(web): inset Windows desktop scrollbars from resize edge (#4097)

Co-authored-by: Julius Marminge <julius0216@outlook.com> Co-authored-by: Julius Marminge <jmarminge@gmail.com>

3 files changed, 37 insertions(+), 1 deletions(-)

apps/web/src/index.css+6
......@@ -6,6 +6,7 @@
66
77:root {
88 --app-scrollbar-width: 6px;
9 --desktop-window-right-resize-inset: 0px;
910 --workspace-topbar-height: 52px;
1011 --workspace-controls-top: 0px;
1112 --workspace-controls-left: calc(env(safe-area-inset-left) + 0.75rem);
......@@ -375,6 +376,11 @@ body {
375376 overflow-y: hidden;
376377 overscroll-behavior-y: none;
377378 padding-top: max(env(safe-area-inset-top), 0px);
379 padding-right: var(--desktop-window-right-resize-inset);
380}
381
382.electron-windows {
383 --desktop-window-right-resize-inset: 6px;
378384}
379385
380386/* App-chrome grain. Baked into each surface's own background (behind
apps/web/src/lib/windowControlsOverlay.ts+26
......@@ -1,4 +1,8 @@
1import { isWindowsPlatform } from "./utils";
2
13const WCO_CLASS_NAME = "wco";
4const ELECTRON_CLASS_NAME = "electron";
5const ELECTRON_WINDOWS_CLASS_NAME = "electron-windows";
26
37interface WindowControlsOverlayLike {
48 readonly visible: boolean;
......@@ -38,3 +42,25 @@ export function syncDocumentWindowControlsOverlayClass(): () => void {
3842 overlay.removeEventListener("geometrychange", update);
3943 };
4044}
45
46export function getElectronPlatformClassNames(
47 platform: string,
48):
49 | readonly [typeof ELECTRON_CLASS_NAME]
50 | readonly [typeof ELECTRON_CLASS_NAME, typeof ELECTRON_WINDOWS_CLASS_NAME] {
51 return isWindowsPlatform(platform)
52 ? [ELECTRON_CLASS_NAME, ELECTRON_WINDOWS_CLASS_NAME]
53 : [ELECTRON_CLASS_NAME];
54}
55
56export function syncDocumentElectronPlatformClasses(platform: string): () => void {
57 if (typeof document === "undefined") {
58 return () => {};
59 }
60
61 const classNames = getElectronPlatformClassNames(platform);
62 document.documentElement.classList.add(...classNames);
63 return () => {
64 document.documentElement.classList.remove(...classNames);
65 };
66}
apps/web/src/main.tsx+5-1
......@@ -15,7 +15,10 @@ import { isElectron } from "./env";
1515import { ManagedRelayAuthProvider } from "./cloud/managedAuth";
1616import { hasCloudPublicConfig } from "./cloud/publicConfig";
1717import { getRouter } from "./router";
18import { syncDocumentWindowControlsOverlayClass } from "./lib/windowControlsOverlay";
18import {
19 syncDocumentElectronPlatformClasses,
20 syncDocumentWindowControlsOverlayClass,
21} from "./lib/windowControlsOverlay";
1922import { AppRoot } from "./AppRoot";
2023
2124// Electron loads the app from a file-backed shell, so hash history avoids path resolution issues.
......@@ -24,6 +27,7 @@ const history = isElectron ? createHashHistory() : createBrowserHistory();
2427const router = getRouter(history);
2528
2629if (isElectron) {
30 syncDocumentElectronPlatformClasses(navigator.platform);
2731 syncDocumentWindowControlsOverlayClass();
2832}
2933