返回 DeepSeek-Reasonix
AppChrome.tsx
根目录 / desktop / frontend / src / components / AppChrome.tsx
1 import { PanelLeft, PanelRight, Search } from "lucide-react";
2 import { TabBar } from "./TabBar";
3 import type { TabMeta } from "../lib/types";
4 import { useT } from "../lib/i18n";
5
6 type DesktopPlatform = "darwin" | "windows" | "linux";
7
8 interface AppChromeProps {
9 platform: DesktopPlatform;
10 browserPreviewChrome: boolean;
11 workbenchChrome?: boolean;
12 tabs: TabMeta[];
13 activeTabId?: string;
14 revealActiveSignal: number;
15 commandCompact: boolean;
16 sidebarTogglePressed: boolean;
17 sidebarExpandBlocked: boolean;
18 sidebarCollapsed: boolean;
19 sidebarToggleTitle: string;
20 workspacePanelMaximized: boolean;
21 workspacePanelRenderable: boolean;
22 workspaceTogglePressed: boolean;
23 workspacePanelLabel: string;
24 onToggleSidebar: () => void;
25 onToggleWorkspacePanel: () => void;
26 onTabChange: (tabId: string) => void;
27 onTabClose: (tabId: string) => void;
28 onTabsClose: (tabIds: string[], nextActiveTabId?: string) => void;
29 onTabsReorder: (tabIds: string[]) => void;
30 onNewTab: () => void;
31 onOpenPalette: () => void;
32 }
33
34 export function AppChrome({
35 platform,
36 browserPreviewChrome,
37 workbenchChrome = false,
38 tabs,
39 activeTabId,
40 revealActiveSignal,
41 commandCompact,
42 sidebarTogglePressed,
43 sidebarExpandBlocked,
44 sidebarCollapsed,
45 sidebarToggleTitle,
46 workspacePanelMaximized,
47 workspacePanelRenderable,
48 workspaceTogglePressed,
49 workspacePanelLabel,
50 onToggleSidebar,
51 onToggleWorkspacePanel,
52 onTabChange,
53 onTabClose,
54 onTabsClose,
55 onTabsReorder,
56 onNewTab,
57 onOpenPalette,
58 }: AppChromeProps) {
59 const t = useT();
60 const darwinChrome = platform === "darwin";
61 const titlebarDragRail = darwinChrome || platform === "windows";
62 const chromeClassName = [
63 "app-chrome",
64 "app-chrome--tabs",
65 darwinChrome ? "app-chrome--darwin-tabs" : "app-chrome--native-tabs",
66 workbenchChrome ? "app-chrome--workbench" : "",
67 !darwinChrome ? "app-chrome--identityless" : "",
68 `app-chrome--platform-${platform}`,
69 ].filter(Boolean).join(" ");
70 const tabBar = (
71 <TabBar
72 tabs={tabs}
73 activeTabId={activeTabId}
74 revealActiveSignal={revealActiveSignal}
75 onTabChange={onTabChange}
76 onTabClose={onTabClose}
77 onTabsClose={onTabsClose}
78 onTabsReorder={onTabsReorder}
79 onNewTab={onNewTab}
80 onOpenPalette={undefined}
81 commandCompact={commandCompact}
82 />
83 );
84
85 return (
86 <header className={chromeClassName}>
87 {browserPreviewChrome && darwinChrome && (
88 <div className="app-chrome__traffic" aria-hidden="true">
89 <span />
90 <span />
91 <span />
92 </div>
93 )}
94 {titlebarDragRail && <span className="app-chrome__drag-rail" aria-hidden="true" />}
95 <button
96 className={[
97 "app-chrome__panel-toggle",
98 "app-chrome__panel-toggle--left",
99 sidebarTogglePressed ? "app-chrome__panel-toggle--pressed" : "",
100 sidebarExpandBlocked ? "app-chrome__panel-toggle--blocked" : "",
101 ].filter(Boolean).join(" ")}
102 type="button"
103 onClick={sidebarExpandBlocked ? undefined : onToggleSidebar}
104 aria-label={sidebarToggleTitle}
105 aria-pressed={!sidebarCollapsed}
106 aria-disabled={sidebarExpandBlocked}
107 >
108 <PanelLeft size={16} />
109 </button>
110 {workbenchChrome && (
111 <button
112 className="app-chrome__workbench-search"
113 type="button"
114 onClick={onOpenPalette}
115 aria-label={t("palette.placeholder")}
116 >
117 <Search size={18} />
118 </button>
119 )}
120
121 {workbenchChrome ? (
122 <span className="app-chrome__spacer" aria-hidden="true" />
123 ) : darwinChrome ? (
124 <>
125 <div className="app-chrome__tab-strip app-chrome__tab-strip--darwin">
126 {tabBar}
127 </div>
128 <div
129 className={[
130 "app-chrome__tools",
131 "app-chrome__tools--fixed",
132 workspaceTogglePressed ? "app-chrome__tools--workspace-pressed" : "",
133 ].filter(Boolean).join(" ")}
134 aria-label={t("tabBar.commandSearch")}
135 >
136 <button
137 className={[
138 "tabbar__command",
139 "tabbar__command--compact",
140 "app-chrome__command",
141 ].filter(Boolean).join(" ")}
142 type="button"
143 onClick={onOpenPalette}
144 aria-label={t("palette.placeholder")}
145 title={t("palette.placeholder")}
146 >
147 <Search size={16} className="tabbar__command-icon" />
148 </button>
149 </div>
150 </>
151 ) : (
152 <>
153 <div className="app-chrome__tab-strip app-chrome__tab-strip--native">
154 {tabBar}
155 </div>
156 <div
157 className={[
158 "app-chrome__tools",
159 workspaceTogglePressed ? "app-chrome__tools--workspace-pressed" : "",
160 ].filter(Boolean).join(" ")}
161 aria-label={t("tabBar.commandSearch")}
162 >
163 <button
164 className={[
165 "tabbar__command",
166 "tabbar__command--compact",
167 "app-chrome__command",
168 ].filter(Boolean).join(" ")}
169 type="button"
170 onClick={onOpenPalette}
171 aria-label={t("palette.placeholder")}
172 title={t("palette.placeholder")}
173 >
174 <Search size={16} className="tabbar__command-icon" />
175 </button>
176 </div>
177 </>
178 )}
179
180 {!workspacePanelMaximized && (
181 <button
182 className={[
183 "app-chrome__panel-toggle",
184 "app-chrome__panel-toggle--right",
185 workspacePanelRenderable ? "app-chrome__panel-toggle--active" : "",
186 workspaceTogglePressed ? "app-chrome__panel-toggle--pressed" : "",
187 ].filter(Boolean).join(" ")}
188 type="button"
189 onClick={onToggleWorkspacePanel}
190 aria-label={workspacePanelLabel}
191 aria-pressed={workspacePanelRenderable}
192 >
193 <PanelRight size={16} />
194 </button>
195 )}
196 </header>
197 );
198 }
199
199 lines Plain Text