返回 DeepSeek-Reasonix
chromeRegionBuilders.ts
根目录 / desktop / frontend / src / app-shell / chromeRegionBuilders.ts
1 import { defaultSidebarWidth, SIDEBAR_MAX_WIDTH } from "../store/layout";
2 import type { Translator } from "../lib/i18n";
3 import type { Meta, RemoteTabRefView, TabMeta } from "../lib/types";
4 import type { SidebarImTopicSource } from "../app-runtime/sidebarImProjection";
5 import type { useSessionBannerCommands } from "../app-runtime/useSessionBannerCommands";
6 import type { useProjectTopicCommands } from "../app-runtime/useProjectTopicCommands";
7 import type { useOnboardingCommands } from "../app-runtime/useOnboardingCommands";
8 import type { useShellGeometry } from "../app-runtime/useShellGeometry";
9 import type { useAppShellStores } from "../app-runtime/useAppShellStores";
10 import type { SessionStatusBannersProps } from "./SessionStatusBanners";
11 import type { SidebarRegionProps } from "./SidebarRegion";
12 import { sessionIdentityRoute } from "../lib/sessionIdentity";
13
14 type BannerCommands = ReturnType<typeof useSessionBannerCommands>;
15 type ShellStores = ReturnType<typeof useAppShellStores>;
16 type ProjectTopicCommands = ReturnType<typeof useProjectTopicCommands>;
17 type OnboardingCommands = ReturnType<typeof useOnboardingCommands>;
18
19 /** Pure prop assembly for the chrome regions (sidebar, app chrome, status
20 * banners); store and hook ownership stays with the caller. */
21
22 export function buildSidebarRegionProps(input: {
23 className: string;
24 shell: ShellStores;
25 t: Translator;
26 geometry: ReturnType<typeof useShellGeometry>;
27 projectTree: {
28 activeTab: TabMeta | undefined;
29 /** Owned by useActiveRemoteRef: this assembly must not rebuild it, because
30 * the project tree keys its tree walks on the object's identity. */
31 activeRemote: RemoteTabRefView | undefined;
32 activeScope?: string;
33 activeWorkspaceRoot?: string;
34 imTopicSources: Record<string, SidebarImTopicSource>;
35 refreshSignal: number;
36 searchExpanded: boolean;
37 searchFocusSignal: number;
38 showShortcutBadges: boolean;
39 shortcutPlatform: SidebarRegionProps["projectTree"]["shortcutPlatform"];
40 onVisibleTopicsChange: SidebarRegionProps["projectTree"]["onVisibleTopicsChange"];
41 };
42 topics: ProjectTopicCommands;
43 commands: {
44 onNewSession: () => void;
45 onOpenPalette: () => void;
46 onOpenTrash: () => void;
47 onOpenAutomation: () => void;
48 onOpenSettings: SidebarRegionProps["onOpenSettings"];
49 onOpenTopic: SidebarRegionProps["projectTree"]["onOpenTopic"];
50 };
51 paletteShortcut: string;
52 }): SidebarRegionProps {
53 const { geometry, topics, commands } = input;
54 const shell = input.shell;
55 return {
56 className: input.className,
57 collapsed: shell.sidebarCollapsed,
58 t: input.t,
59 onNewSession: commands.onNewSession,
60 onOpenPalette: commands.onOpenPalette,
61 paletteShortcut: input.paletteShortcut,
62 onOpenTrash: commands.onOpenTrash,
63 onOpenAutomation: commands.onOpenAutomation,
64 onOpenSettings: commands.onOpenSettings,
65 resize: {
66 min: geometry.sidebarResizeMinWidth, max: SIDEBAR_MAX_WIDTH, value: geometry.sidebarRenderWidth,
67 onPointerDown: geometry.startSidebarResize, onKeyDown: geometry.resizeSidebarWithKeyboard,
68 onReset: () => geometry.setExpandedSidebarWidth(defaultSidebarWidth()),
69 },
70 projectTree: {
71 activeScope: input.projectTree.activeScope ?? input.projectTree.activeTab?.scope,
72 activeWorkspaceRoot: input.projectTree.activeWorkspaceRoot ?? input.projectTree.activeTab?.workspaceRoot,
73 activeTopicId: input.projectTree.activeTab?.topicId, activeSessionPath: sessionIdentityRoute(input.projectTree.activeTab),
74 activeRemote: input.projectTree.activeRemote,
75 imTopicSources: input.projectTree.imTopicSources, onOpenTopic: commands.onOpenTopic,
76 onCreateTopic: topics.onCreateTopic, onCreateIsolatedWorktree: topics.onCreateIsolatedWorktree,
77 onTopicsChanged: topics.refreshProjectsAndTabs, onRenameTopic: topics.renameTopic, refreshSignal: input.projectTree.refreshSignal,
78 onAddProject: topics.onAddProject,
79 searchExpanded: input.projectTree.searchExpanded, searchFocusSignal: input.projectTree.searchFocusSignal,
80 showShortcutBadges: input.projectTree.showShortcutBadges, shortcutPlatform: input.projectTree.shortcutPlatform,
81 onVisibleTopicsChange: input.projectTree.onVisibleTopicsChange,
82 },
83 };
84 }
85
86 export function buildSessionStatusBannerProps(input: {
87 t: Translator;
88 activeTab: TabMeta | undefined;
89 leaseBlocked: SessionStatusBannersProps["leaseBlocked"];
90 meta: Meta | null | undefined;
91 configWarnings: SessionStatusBannersProps["configWarnings"];
92 dismissConfigWarnings: () => void;
93 updateChecksEnabled: boolean;
94 shell: ShellStores;
95 banners: BannerCommands;
96 onboarding: OnboardingCommands;
97 }): SessionStatusBannersProps {
98 const { banners, shell, onboarding } = input;
99 return {
100 t: input.t,
101 takenOver: Boolean(input.activeTab?.takenOver),
102 reclaimTabId: input.activeTab?.id ?? "",
103 reclaimBusyTabId: shell.reclaimBusyTab,
104 onReclaim: banners.reclaimSession,
105 leaseBlocked: input.leaseBlocked,
106 startupError: input.meta?.startupErr,
107 takeoverDialogTabId: shell.takeoverDialogTab,
108 onOpenTakeover: banners.openTakeoverDialog,
109 onCloseTakeover: banners.closeTakeoverDialog,
110 configWarnings: input.configWarnings,
111 onOpenConfigFile: banners.openConfigFile,
112 onReloadConfigFile: banners.reloadConfigFile,
113 onDismissConfigWarnings: input.dismissConfigWarnings,
114 providerSetupNeeded: shell.providerSetupNeeded,
115 needsOnboarding: shell.needsOnboarding,
116 onConfigureProvider: () => {
117 onboarding.chooseOnboardingProvider();
118 },
119 updateChecksEnabled: input.updateChecksEnabled,
120 onShowReleaseNotes: banners.showReleaseNotes,
121 };
122 }
123
124 /** The app/layout frame class lists; flags arrive from the caller's stores. */
125 export function buildAppShellClassNames(input: {
126 platform: string;
127 windowsFrameless: boolean;
128 browserPreview: boolean;
129 imDetailActive: boolean;
130 sidebarCollapsed: boolean;
131 sidebarResizing: boolean;
132 dockGridOpen: boolean;
133 dockOverlay: boolean;
134 terminalOpen: boolean;
135 terminalResizing: boolean;
136 dockOpen: boolean;
137 dockMaximized: boolean;
138 dockResizing: boolean;
139 }): { app: string; layout: string } {
140 return {
141 app: [
142 "app",
143 `app--${input.platform}`,
144 input.windowsFrameless ? "app--windows-frameless" : "",
145 input.browserPreview ? "app--browser-preview" : "",
146 "app--workbench",
147 ].filter(Boolean).join(" "),
148 layout: [
149 "layout",
150 "layout--workbench",
151 input.imDetailActive ? "layout--statusbar-hidden" : "",
152 input.sidebarCollapsed ? "layout--sidebar-collapsed" : "",
153 input.sidebarResizing ? "layout--resizing layout--sidebar-resizing" : "",
154 input.dockGridOpen ? "layout--workspace-open" : "",
155 input.dockOverlay ? "layout--workspace-overlay" : "",
156 "layout--terminal-drawer-open",
157 input.terminalOpen ? "layout--terminal-drawer-expanded" : "",
158 input.terminalResizing ? "layout--terminal-resizing" : "",
159 input.dockOpen && input.dockMaximized ? "layout--workspace-maximized" : "",
160 input.dockResizing ? "layout--resizing layout--workspace-resizing" : "",
161 ]
162 .filter(Boolean)
163 .join(" "),
164 };
165 }
166
166 lines TYPESCRIPT