Files
multica/packages/views/platform/use-immersive-mode.ts
Naiyuan Qing 7dad45d444 feat(desktop): immersive mode hides traffic lights for full-screen modals
Full-screen modals (create-workspace) covered the app titlebar, so the
Back button landed on top of the macOS traffic lights — where native
hit-test always wins and the button couldn't be clicked. The modal
also swallowed the window's drag region.

Introduce a desktop IPC channel window:setImmersive that calls
BrowserWindow.setWindowButtonVisibility, exposed through the existing
desktopAPI preload bridge. A small useImmersiveMode() hook in
@multica/views/platform toggles it for the component's lifetime and
is a no-op on web / non-macOS.

CreateWorkspaceModal now:
- calls useImmersiveMode() so traffic lights disappear while it's open
- adds a transparent top h-10 drag strip to restore window dragging
- moves the Back button from top-6 left-6 to top-12 left-12 with an
  explicit no-drag region so clicks always reach it

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 19:41:49 +08:00

29 lines
890 B
TypeScript

import { useEffect } from "react";
type ImmersiveCapableAPI = {
setImmersiveMode?: (immersive: boolean) => Promise<void> | void;
};
function getDesktopAPI(): ImmersiveCapableAPI | undefined {
if (typeof window === "undefined") return undefined;
return (window as unknown as { desktopAPI?: ImmersiveCapableAPI }).desktopAPI;
}
/**
* Enter "immersive" mode for the lifetime of the component that calls it.
*
* On macOS desktop this hides the traffic-light window controls so full-screen
* modals (create-workspace, onboarding, etc.) can place UI in the top-left
* corner without fighting the native controls' hit-test. On web or non-macOS
* desktop this is a no-op.
*/
export function useImmersiveMode(): void {
useEffect(() => {
const api = getDesktopAPI();
api?.setImmersiveMode?.(true);
return () => {
api?.setImmersiveMode?.(false);
};
}, []);
}