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 @@...@@ -6,6 +6,7 @@
66
7:root {7:root {
8 --app-scrollbar-width: 6px;8 --app-scrollbar-width: 6px;
9 --desktop-window-right-resize-inset: 0px;
9 --workspace-topbar-height: 52px;10 --workspace-topbar-height: 52px;
10 --workspace-controls-top: 0px;11 --workspace-controls-top: 0px;
11 --workspace-controls-left: calc(env(safe-area-inset-left) + 0.75rem);12 --workspace-controls-left: calc(env(safe-area-inset-left) + 0.75rem);
...@@ -375,6 +376,11 @@ body {...@@ -375,6 +376,11 @@ body {
375 overflow-y: hidden;376 overflow-y: hidden;
376 overscroll-behavior-y: none;377 overscroll-behavior-y: none;
377 padding-top: max(env(safe-area-inset-top), 0px);378 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;
378}384}
379385
380/* App-chrome grain. Baked into each surface's own background (behind386/* App-chrome grain. Baked into each surface's own background (behind
apps/web/src/lib/windowControlsOverlay.ts+26
...@@ -1,4 +1,8 @@...@@ -1,4 +1,8 @@
1import { isWindowsPlatform } from "./utils";
2
1const WCO_CLASS_NAME = "wco";3const WCO_CLASS_NAME = "wco";
4const ELECTRON_CLASS_NAME = "electron";
5const ELECTRON_WINDOWS_CLASS_NAME = "electron-windows";
26
3interface WindowControlsOverlayLike {7interface WindowControlsOverlayLike {
4 readonly visible: boolean;8 readonly visible: boolean;
...@@ -38,3 +42,25 @@ export function syncDocumentWindowControlsOverlayClass(): () => void {...@@ -38,3 +42,25 @@ export function syncDocumentWindowControlsOverlayClass(): () => void {
38 overlay.removeEventListener("geometrychange", update);42 overlay.removeEventListener("geometrychange", update);
39 };43 };
40}44}
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";...@@ -15,7 +15,10 @@ import { isElectron } from "./env";
15import { ManagedRelayAuthProvider } from "./cloud/managedAuth";15import { ManagedRelayAuthProvider } from "./cloud/managedAuth";
16import { hasCloudPublicConfig } from "./cloud/publicConfig";16import { hasCloudPublicConfig } from "./cloud/publicConfig";
17import { getRouter } from "./router";17import { getRouter } from "./router";
18import { syncDocumentWindowControlsOverlayClass } from "./lib/windowControlsOverlay";18import {
19 syncDocumentElectronPlatformClasses,
20 syncDocumentWindowControlsOverlayClass,
21} from "./lib/windowControlsOverlay";
19import { AppRoot } from "./AppRoot";22import { AppRoot } from "./AppRoot";
2023
21// Electron loads the app from a file-backed shell, so hash history avoids path resolution issues.24// 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();...@@ -24,6 +27,7 @@ const history = isElectron ? createHashHistory() : createBrowserHistory();
24const router = getRouter(history);27const router = getRouter(history);
2528
26if (isElectron) {29if (isElectron) {
30 syncDocumentElectronPlatformClasses(navigator.platform);
27 syncDocumentWindowControlsOverlayClass();31 syncDocumentWindowControlsOverlayClass();
28}32}
2933