diff --git a/apps/desktop/src/window/DesktopWindow.ts b/apps/desktop/src/window/DesktopWindow.ts
index bf8c681448f..e975bf5ee41 100644
--- a/apps/desktop/src/window/DesktopWindow.ts
+++ b/apps/desktop/src/window/DesktopWindow.ts
@@ -553,7 +553,7 @@ export const make = Effect.gen(function* () {
runFork(flushBoundsPersist);
});
- if (environment.platform === "darwin") {
+ if (environment.platform === "darwin" || environment.platform === "win32") {
window.on("enter-full-screen", () => {
window.webContents.send(WINDOW_FULLSCREEN_STATE_CHANNEL, true);
});
diff --git a/apps/web/src/components/DiffPanelShell.tsx b/apps/web/src/components/DiffPanelShell.tsx
index c13af4d9560..8601200369f 100644
--- a/apps/web/src/components/DiffPanelShell.tsx
+++ b/apps/web/src/components/DiffPanelShell.tsx
@@ -13,7 +13,7 @@ function getDiffPanelHeaderRowClassName(mode: DiffPanelMode) {
"flex items-center justify-between gap-2",
mode === "embedded" ? "px-2" : "px-4",
shouldUseDragRegion
- ? "drag-region h-[52px] border-b border-border wco:h-[env(titlebar-area-height)] wco:pr-[calc(100vw-env(titlebar-area-width)-env(titlebar-area-x)+1em)]"
+ ? "workspace-topbar drag-region border-b border-border wco:pr-[var(--workspace-native-controls-inset)]"
: "surface-subheader",
);
}
diff --git a/apps/web/src/components/settings/ProjectSettingsPanel.tsx b/apps/web/src/components/settings/ProjectSettingsPanel.tsx
index 50cf9c31804..6ace78db1a3 100644
--- a/apps/web/src/components/settings/ProjectSettingsPanel.tsx
+++ b/apps/web/src/components/settings/ProjectSettingsPanel.tsx
@@ -187,7 +187,7 @@ export function ProjectSettingsPage({ projectKey }: { projectKey: string }) {
{isElectron && (
diff --git a/apps/web/src/components/usage/UsagePage.tsx b/apps/web/src/components/usage/UsagePage.tsx
index b550d673f6e..e20ef5f4cea 100644
--- a/apps/web/src/components/usage/UsagePage.tsx
+++ b/apps/web/src/components/usage/UsagePage.tsx
@@ -81,7 +81,7 @@ export function UsagePage() {
{isElectron && (
diff --git a/apps/web/src/index.css b/apps/web/src/index.css
index 72983930aaf..a7c69c3b969 100644
--- a/apps/web/src/index.css
+++ b/apps/web/src/index.css
@@ -1407,6 +1407,18 @@ body {
.electron-windows {
--desktop-window-right-resize-inset: 6px;
+ /* Matches DesktopWindow TITLEBAR_HEIGHT; WCO height can be transitional during restore. */
+ --workspace-topbar-height: 40px;
+ --workspace-controls-top: 0px;
+ --workspace-controls-left: 0.75rem;
+ --workspace-native-controls-width: calc(
+ 100vw - env(titlebar-area-width, 100vw) - env(titlebar-area-x, 0px)
+ );
+}
+
+.electron-windows.wco {
+ --workspace-controls-right: calc(var(--workspace-native-controls-width) + 0.75rem);
+ --workspace-native-controls-inset: var(--workspace-controls-right);
}
/* App-chrome grain. Baked into each surface's own background (behind
diff --git a/apps/web/src/lib/windowControlsOverlay.ts b/apps/web/src/lib/windowControlsOverlay.ts
index 42f9f13c7cd..16a4c2a4249 100644
--- a/apps/web/src/lib/windowControlsOverlay.ts
+++ b/apps/web/src/lib/windowControlsOverlay.ts
@@ -6,6 +6,7 @@ const ELECTRON_WINDOWS_CLASS_NAME = "electron-windows";
interface WindowControlsOverlayLike {
readonly visible: boolean;
+ readonly getTitlebarAreaRect: () => Pick
;
addEventListener(type: "geometrychange", listener: EventListener): void;
removeEventListener(type: "geometrychange", listener: EventListener): void;
}
@@ -28,18 +29,59 @@ export function syncDocumentWindowControlsOverlayClass(): () => void {
}
const overlay = getWindowControlsOverlay();
+ if (!overlay) return () => {};
+
+ const root = document.documentElement;
+ const isWindows = isWindowsPlatform(navigator.platform);
+ let wasVisible = overlay.visible;
+ let hasGeometry = false;
+ let fullscreen = isWindows && window.desktopBridge?.getWindowFullscreenState?.() === true;
+
+ const applyGeometry = () => {
+ const rect = overlay.getTitlebarAreaRect();
+ const rightInset = window.innerWidth - rect.right;
+ if (!(rect.width > 0 && rightInset > 0 && rightInset <= window.innerWidth)) return;
+
+ root.style.setProperty("--workspace-native-controls-width", `${rightInset}px`);
+ hasGeometry = true;
+ };
+
const update = () => {
- document.documentElement.classList.toggle(WCO_CLASS_NAME, overlay !== null && overlay.visible);
+ const visible = overlay.visible;
+ const preserveWindowsLayout = isWindows && !visible && hasGeometry && !fullscreen;
+ root.classList.toggle(WCO_CLASS_NAME, visible || preserveWindowsLayout);
+
+ if (!isWindows) return;
+
+ if (!visible) {
+ wasVisible = false;
+ return;
+ }
+
+ if (!wasVisible) {
+ wasVisible = true;
+ if (!hasGeometry) applyGeometry();
+ return;
+ }
+
+ applyGeometry();
};
+ const stopFullscreenListener = isWindows
+ ? window.desktopBridge?.onWindowFullscreenStateChange?.((value) => {
+ fullscreen = value;
+ update();
+ })
+ : undefined;
+
update();
- if (!overlay) {
- return () => {};
- }
overlay.addEventListener("geometrychange", update);
return () => {
+ stopFullscreenListener?.();
overlay.removeEventListener("geometrychange", update);
+ root.classList.remove(WCO_CLASS_NAME);
+ root.style.removeProperty("--workspace-native-controls-width");
};
}
diff --git a/apps/web/src/rightPanelLayout.ts b/apps/web/src/rightPanelLayout.ts
index 5528072e57b..5768a80041a 100644
--- a/apps/web/src/rightPanelLayout.ts
+++ b/apps/web/src/rightPanelLayout.ts
@@ -1,3 +1,3 @@
export const RIGHT_PANEL_INLINE_LAYOUT_MEDIA_QUERY = "(max-width: 980px)";
export const RIGHT_PANEL_SHEET_CLASS_NAME =
- "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[env(titlebar-area-height)] wco:h-[calc(100%-env(titlebar-area-height))] wco:max-h-[calc(100%-env(titlebar-area-height))]";
+ "w-[min(42vw,28rem)] min-w-80 max-w-[28rem] p-0 max-[760px]:w-[min(88vw,24rem)] max-[760px]:min-w-0 wco:mt-[var(--workspace-topbar-height)] wco:h-[calc(100%-var(--workspace-topbar-height))] wco:max-h-[calc(100%-var(--workspace-topbar-height))]";
diff --git a/apps/web/src/routes/settings.tsx b/apps/web/src/routes/settings.tsx
index f14793ba544..99a4c28e984 100644
--- a/apps/web/src/routes/settings.tsx
+++ b/apps/web/src/routes/settings.tsx
@@ -93,7 +93,7 @@ function SettingsContentLayout() {
{isElectron && (