gui: gate the macOS overlay layout to macOS

Shell injects the OS; Windows/Linux keep the native title bar with no traffic-light insets.
Thin scrollbars on Windows/Linux so panels stop losing width to classic scrollbars.
This commit is contained in:
Rohit C Prasad
2026-07-21 23:16:40 -07:00
parent f6ad97274d
commit 628b6a82d3
6 changed files with 62 additions and 3 deletions
@@ -0,0 +1,23 @@
import { test, expect } from "./fixtures";
// The macOS overlay layout (traffic-light insets) must never apply on Windows —
// Windows keeps its native title bar (alignment bug, 2026-07-21). The shell injects
// __OCW_PLATFORM__; this simulates each platform and checks the overlay class.
test("windows platform gets no tauri-overlay layout", async ({ page }) => {
await page.addInitScript(() => {
(window as any).__TAURI__ = {}; // simulate the desktop shell
(window as any).__OCW_PLATFORM__ = "windows";
});
await page.goto("/");
await expect(page.locator("html")).toHaveAttribute("data-platform", "windows");
await expect(page.locator(".app.tauri-overlay")).toHaveCount(0);
});
test("macos platform keeps the overlay layout", async ({ page }) => {
await page.addInitScript(() => {
(window as any).__TAURI__ = {};
(window as any).__OCW_PLATFORM__ = "macos";
});
await page.goto("/");
await expect(page.locator(".app.tauri-overlay").first()).toBeVisible();
});
+4 -1
View File
@@ -577,7 +577,10 @@ pub fn run() {
let http = format!("http://127.0.0.1:{port}");
let ws = format!("ws://127.0.0.1:{port}");
// Debug-format yields a quoted JS string literal.
let inject = format!("window.__COWORKER_HTTP__={http:?};window.__COWORKER_WS__={ws:?};");
let inject = format!(
"window.__COWORKER_HTTP__={http:?};window.__COWORKER_WS__={ws:?};window.__OCW_PLATFORM__={:?};",
std::env::consts::OS
);
tauri::Builder::default()
// MUST be the first plugin: when a second launch happens (e.g. the user relaunches
+5 -2
View File
@@ -33,7 +33,7 @@ import { baseName } from "./paths";
import { itemsFromMessages } from "./itemsFromMessages";
import { streamMode } from "./streamGate";
import { InboxItemCard } from "./components/InboxItemCard";
import { isTauri, startWindowDrag } from "./tauri";
import { isTauri, platformOS, startWindowDrag } from "./tauri";
import { Icon } from "./components/Icon";
import { Sidebar } from "./components/Sidebar";
import { Transcript } from "./components/Transcript";
@@ -1027,7 +1027,10 @@ export function App() {
// tauri-overlay class + draws fake traffic lights at the real position) so the top-left can be
// tuned in the preview without a DMG build. Never active in the real app (isTauri() short-circuits).
const simOverlay = !desktop && new URLSearchParams(window.location.search).has("overlay");
const overlay = desktop || simOverlay;
// Overlay layout is macOS-ONLY: Windows/Linux keep the native title bar, so the mac
// compensations (traffic-light insets, lowered top strips) must not apply there —
// they rendered as misalignments under Windows' native bar (caught 2026-07-21).
const overlay = (desktop && platformOS() === "macos") || simOverlay;
const beginWindowDrag = (event: PointerEvent) => {
if (!desktop || event.button !== 0) return;
startWindowDrag();
+3
View File
@@ -2,10 +2,13 @@ import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import { initTheme } from "./theme";
import { platformOS } from "./tauri";
import "./tailwind.css";
import "./styles.css";
initTheme();
// Platform hook for CSS (html[data-platform="windows"] scrollbar styling etc.).
document.documentElement.dataset.platform = platformOS();
// A file dropped OUTSIDE a drop target (the composer) must never navigate the webview to the
// file itself — the browser/WKWebView default. Drop targets stopPropagation-free preventDefault
+17
View File
@@ -1544,3 +1544,20 @@ html[data-theme="dark"] .hiw-sticky { background: #eab308; color: #3d2c05; }
@keyframes toast-pulse { 50% { opacity: .35; } }
.toast-drain { animation: toast-drain 5s linear forwards; }
@keyframes toast-drain { to { width: 0; } }
/* ============ Windows (WebView2) polish ============ */
/* Classic Windows scrollbars consume ~17px of layout width that macOS's overlay
scrollbars don't panels tuned on Mac ended up cramped/misaligned (caught
2026-07-21). Thin, quiet scrollbars matching the app's neutral palette; scoped
to data-platform so macOS keeps its native overlay behavior. */
html[data-platform="windows"] ::-webkit-scrollbar,
html[data-platform="linux"] ::-webkit-scrollbar { width: 10px; height: 10px; }
html[data-platform="windows"] ::-webkit-scrollbar-track,
html[data-platform="linux"] ::-webkit-scrollbar-track { background: transparent; }
html[data-platform="windows"] ::-webkit-scrollbar-thumb,
html[data-platform="linux"] ::-webkit-scrollbar-thumb {
background: var(--line-strong); border-radius: 5px;
border: 2px solid transparent; background-clip: content-box;
}
html[data-platform="windows"] ::-webkit-scrollbar-thumb:hover,
html[data-platform="linux"] ::-webkit-scrollbar-thumb:hover { background-color: var(--faint); }
+10
View File
@@ -6,6 +6,16 @@
export const isTauri = (): boolean =>
typeof (globalThis as any).__TAURI__ !== "undefined";
// "macos" | "windows" | "linux" — injected by the shell (std::env::consts::OS) before the
// SPA loads; userAgent fallback covers browser dev. The macOS overlay-titlebar layout (and
// its traffic-light compensations) must NEVER apply on Windows, which keeps its native
// title bar (alignment bug, caught on Windows 2026-07-21).
export const platformOS = (): string => {
const injected = (globalThis as any).__OCW_PLATFORM__;
if (typeof injected === "string" && injected) return injected;
return /mac/i.test(navigator.userAgent) ? "macos" : /win/i.test(navigator.userAgent) ? "windows" : "linux";
};
export type DictationStatus = {
recording: boolean;
model_installed: boolean;