返回 DeepSeek-Reasonix
useAppChromeCommands.ts
根目录 / desktop / frontend / src / app-runtime / useAppChromeCommands.ts
1 import type { MouseEvent as ReactMouseEvent, Dispatch, SetStateAction } from "react";
2 import { useCommittedCommand } from "../lib/useCommittedCommand";
3 import { isMacOSWorkbenchSidebarTitlebar, type DesktopPlatform } from "../lib/desktopPlatform";
4 import { nativeWindowCommands, syncMainWindowMaximised } from "./useNativeWindowController";
5 import type { SettingsTab, SettingsView } from "../lib/types";
6 import type { SettingsInitialFocus } from "../components/SettingsPanel";
7
8 export type AppChromeCommandsInput = {
9 platform: DesktopPlatform;
10 windowsFrameless: boolean;
11 closeTransientOverlays: () => void;
12 clearImDetail: () => void;
13 setSettingsFocus: Dispatch<SetStateAction<SettingsInitialFocus | null>>;
14 setSettingsTarget: Dispatch<SetStateAction<SettingsTab | null>>;
15 setSidebarSearchOpen: Dispatch<SetStateAction<boolean>>;
16 setSidebarSearchFocusSignal: Dispatch<SetStateAction<number>>;
17 refreshMeta: () => Promise<unknown>;
18 refreshProviderSetupState: () => Promise<unknown>;
19 reloadDesktopPreferences: (settings?: SettingsView | null) => Promise<unknown>;
20 };
21
22 function reportNativeWindowFailure(error: unknown): void {
23 console.warn("native window action failed", error);
24 }
25
26 /**
27 * Owns the window-chrome and settings-surface commands: native window
28 * minimize/toggle/close with the maximised re-sync, the frameless titlebar
29 * double-click zoom, settings open/close/changed, bot settings entries and
30 * the sidebar search toggle. All are stable committed commands; consumers in
31 * the chrome, sidebar, IM detail and overlay regions only wire them.
32 */
33 export function useAppChromeCommands(input: AppChromeCommandsInput) {
34 const openBotSettings = useCommittedCommand(() => {
35 input.closeTransientOverlays();
36 input.clearImDetail();
37 input.setSettingsFocus(null);
38 input.setSettingsTarget("bots");
39 });
40
41 const openBotAllowlistSettings = useCommittedCommand((connectionId: string) => {
42 input.closeTransientOverlays();
43 input.clearImDetail();
44 input.setSettingsFocus({ target: "bot-allowlist", connectionId });
45 input.setSettingsTarget("bots");
46 });
47
48 // The OS drag region ignores anything with detail !== 1, so a double click
49 // on a --reasonix-draggable region never reaches the shell. Both platforms that hide
50 // their native title bar need this handled here.
51 const chromeDoubleClickZooms = input.windowsFrameless || input.platform === "darwin";
52 const handleChromeTitlebarDoubleClick = useCommittedCommand((event: ReactMouseEvent<HTMLDivElement>) => {
53 if (!chromeDoubleClickZooms) return;
54 const target = event.target as HTMLElement | null;
55 const onChromeSurface = target?.closest(".topicbar, .workbench-dock__tools, .management-screen__chrome");
56 const onMacOSWorkbenchSidebarTitlebar = isMacOSWorkbenchSidebarTitlebar(target, event.clientY, input.platform);
57 if (!onChromeSurface && !onMacOSWorkbenchSidebarTitlebar) return;
58 if (target?.closest("button, input, textarea, select, a, [role='button'], [role='tab'], .windows-window-controls")) return;
59 event.preventDefault();
60 void nativeWindowCommands.toggleMaximize().then(syncMainWindowMaximised)
61 .catch(reportNativeWindowFailure);
62 });
63 const minimizeMainWindow = useCommittedCommand(() => {
64 void nativeWindowCommands.minimize().catch(reportNativeWindowFailure);
65 });
66 const toggleMainWindowMaximized = useCommittedCommand(() => {
67 void nativeWindowCommands.toggleMaximize().then(syncMainWindowMaximised)
68 .catch(reportNativeWindowFailure);
69 });
70 const closeMainWindow = useCommittedCommand(() => {
71 void nativeWindowCommands.close().catch(reportNativeWindowFailure);
72 });
73 const closeSettings = useCommittedCommand(() => {
74 input.setSettingsFocus(null);
75 input.setSettingsTarget(null);
76 });
77 const handleSettingsChanged = useCommittedCommand((settings?: SettingsView | null) => {
78 void input.refreshMeta();
79 void input.refreshProviderSetupState().catch(() => {});
80 void input.reloadDesktopPreferences(settings);
81 });
82 const openSidebarSettings = useCommittedCommand((tab: SettingsTab) => {
83 input.closeTransientOverlays();
84 input.setSettingsTarget(tab);
85 });
86 const toggleSidebarSearch = useCommittedCommand(() => {
87 input.setSidebarSearchOpen((open) => !open);
88 input.setSidebarSearchFocusSignal((signal) => signal + 1);
89 });
90
91 return {
92 openBotSettings,
93 openBotAllowlistSettings,
94 handleChromeTitlebarDoubleClick,
95 minimizeMainWindow,
96 toggleMainWindowMaximized,
97 closeMainWindow,
98 closeSettings,
99 handleSettingsChanged,
100 openSidebarSettings,
101 toggleSidebarSearch,
102 };
103 }
104
104 lines TYPESCRIPT