diff --git a/surfaces/gui/e2e/onboarding-drag.spec.ts b/surfaces/gui/e2e/onboarding-drag.spec.ts new file mode 100644 index 00000000..52b15690 --- /dev/null +++ b/surfaces/gui/e2e/onboarding-drag.spec.ts @@ -0,0 +1,40 @@ +// Issue #95: on macOS the window has no native title bar while onboarding is on screen +// (App.tsx's `overlay`, gated to `platformOS() === "macos"` — hidden_title(true) in +// src-tauri/src/lib.rs), so the ONLY way to move the window is a `data-tauri-drag-region` +// element. Onboarding's full-viewport backdrop (z-50) sits over both of the app's drag +// surfaces (Sidebar's brand row, App.tsx's topbar), and carries no drag region of its own, +// so the window is stuck until onboarding finishes. +import { expect } from "@playwright/test"; +import { test } from "./fixtures"; + +async function openOnboarding(page) { + await page.goto("/"); + await page.getByTestId("account-row").click(); + await page.getByTestId("account-menu").getByRole("button", { name: "Settings" }).click(); + await page.getByRole("button", { name: "Run setup again" }).click(); + await expect(page.getByTestId("ob-step-model")).toBeVisible(); +} + +test("macOS: a drag region is reachable while onboarding covers the screen", async ({ page }) => { + await page.addInitScript(() => { + (window as any).__TAURI__ = {}; + (window as any).__OCW_PLATFORM__ = "macos"; + }); + await openOnboarding(page); + + // The overlay title bar is macOS-only; confirm it actually engaged for this run. + await expect(page.locator(".app.tauri-overlay").first()).toBeVisible(); + + const dragRegions = page.locator("[data-tauri-drag-region]"); + await expect(dragRegions.first()).toBeVisible(); + + // The mechanism Tauri relies on: the element the OS would hit-test at the drag + // region's own coordinates must BE that element, not something stacked on top of it. + const reachable = await dragRegions.first().evaluate((el) => { + const r = el.getBoundingClientRect(); + const x = r.left + Math.min(10, r.width / 2); + const y = r.top + r.height / 2; + return document.elementFromPoint(x, y) === el; + }); + expect(reachable).toBe(true); +}); diff --git a/surfaces/gui/src/components/Onboarding.tsx b/surfaces/gui/src/components/Onboarding.tsx index 5cfe88a2..458dfcb7 100644 --- a/surfaces/gui/src/components/Onboarding.tsx +++ b/surfaces/gui/src/components/Onboarding.tsx @@ -10,7 +10,9 @@ import { } from "../api"; import { ConnectorBadge } from "../connectors/ConnectorIcon"; import { ProviderCards, ProviderForm, useProviderSetup } from "../providers/ProviderSetup"; +import { isTauri, platformOS } from "../tauri"; import { Spinner } from "./AutomationQuickstart"; +import { Icon } from "./Icon"; // First-run onboarding (UX-DECISIONS §24 → §29 → §39): model → your tools → go. // §39 (owner design, 2026-07-18): step 1 is a PROVIDER GALLERY — 13 real brand @@ -109,8 +111,22 @@ export function Onboarding({ onDone }: { onDone: (next?: "work" | "gallery" | "a ); + // macOS overlay title bar (hidden native title bar, App.tsx's `overlay`): the app's only + // drag surfaces (Sidebar's brand row, App.tsx's topbar) sit UNDER this full-viewport + // backdrop and can't be reached, same gap the boot splash already covers (App.tsx + // ~line 1130) before the sidebar even mounts. Mirror that same strip here, above the + // backdrop's z-50 (z-180), so the window stays movable while onboarding is on screen. + const overlay = isTauri() && platformOS() === "macos"; + return (
+ {overlay && ( +
+ + OpenWorkerBETA + +
+ )} {/* FIXED height across all three steps (owner call 2026-07-12, reaffirmed §39: the modal must never resize — the gallery⇄form swap happens inside this box). */}