Skip to content

Commit 3834ea4

Browse files
Apply PR #19029: feat(app): hide desktop titlebar tools behind settings
2 parents 91d5909 + fa9674e commit 3834ea4

7 files changed

Lines changed: 296 additions & 153 deletions

File tree

packages/app/src/components/session/session-header.tsx

Lines changed: 82 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { useLanguage } from "@/context/language"
1616
import { useLayout } from "@/context/layout"
1717
import { usePlatform } from "@/context/platform"
1818
import { useServer } from "@/context/server"
19+
import { useSettings } from "@/context/settings"
1920
import { useSync } from "@/context/sync"
2021
import { useTerminal } from "@/context/terminal"
2122
import { focusTerminalById } from "@/pages/session/helpers"
@@ -134,6 +135,7 @@ export function SessionHeader() {
134135
const server = useServer()
135136
const platform = usePlatform()
136137
const language = useLanguage()
138+
const settings = useSettings()
137139
const sync = useSync()
138140
const terminal = useTerminal()
139141
const { params, view } = useSessionLayout()
@@ -151,6 +153,10 @@ export function SessionHeader() {
151153
})
152154
const hotkey = createMemo(() => command.keybind("file.open"))
153155
const os = createMemo(() => detectOS(platform))
156+
const search = createMemo(() => platform.platform !== "desktop" || settings.general.showSearch())
157+
const tree = createMemo(() => platform.platform !== "desktop" || settings.general.showFileTree())
158+
const term = createMemo(() => platform.platform !== "desktop" || settings.general.showTerminal())
159+
const status = createMemo(() => platform.platform !== "desktop" || settings.general.showStatus())
154160

155161
const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({
156162
finder: true,
@@ -267,35 +273,37 @@ export function SessionHeader() {
267273

268274
return (
269275
<>
270-
<Show when={centerMount()}>
271-
{(mount) => (
272-
<Portal mount={mount()}>
273-
<Button
274-
type="button"
275-
variant="ghost"
276-
size="small"
277-
class="hidden md:flex w-[240px] max-w-full min-w-0 items-center gap-2 justify-between rounded-md border border-border-weak-base bg-surface-panel shadow-none cursor-default"
278-
onClick={() => command.trigger("file.open")}
279-
aria-label={language.t("session.header.searchFiles")}
280-
>
281-
<div class="flex min-w-0 flex-1 items-center overflow-visible">
282-
<span class="flex-1 min-w-0 text-12-regular text-text-weak truncate text-left">
283-
{language.t("session.header.search.placeholder", {
284-
project: name(),
285-
})}
286-
</span>
287-
</div>
276+
<Show when={search()}>
277+
<Show when={centerMount()}>
278+
{(mount) => (
279+
<Portal mount={mount()}>
280+
<Button
281+
type="button"
282+
variant="ghost"
283+
size="small"
284+
class="hidden md:flex w-[240px] max-w-full min-w-0 items-center gap-2 justify-between rounded-md border border-border-weak-base bg-surface-panel shadow-none cursor-default"
285+
onClick={() => command.trigger("file.open")}
286+
aria-label={language.t("session.header.searchFiles")}
287+
>
288+
<div class="flex min-w-0 flex-1 items-center overflow-visible">
289+
<span class="flex-1 min-w-0 text-12-regular text-text-weak truncate text-left">
290+
{language.t("session.header.search.placeholder", {
291+
project: name(),
292+
})}
293+
</span>
294+
</div>
288295

289-
<Show when={hotkey()}>
290-
{(keybind) => (
291-
<Keybind class="shrink-0 !border-0 !bg-transparent !shadow-none px-0 text-text-weaker">
292-
{keybind()}
293-
</Keybind>
294-
)}
295-
</Show>
296-
</Button>
297-
</Portal>
298-
)}
296+
<Show when={hotkey()}>
297+
{(keybind) => (
298+
<Keybind class="shrink-0 !border-0 !bg-transparent !shadow-none px-0 text-text-weaker">
299+
{keybind()}
300+
</Keybind>
301+
)}
302+
</Show>
303+
</Button>
304+
</Portal>
305+
)}
306+
</Show>
299307
</Show>
300308
<Show when={rightMount()}>
301309
{(mount) => (
@@ -415,24 +423,28 @@ export function SessionHeader() {
415423
</div>
416424
</Show>
417425
<div class="flex items-center gap-1">
418-
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
419-
<StatusPopover />
420-
</Tooltip>
421-
<TooltipKeybind
422-
title={language.t("command.terminal.toggle")}
423-
keybind={command.keybind("terminal.toggle")}
424-
>
425-
<Button
426-
variant="ghost"
427-
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
428-
onClick={toggleTerminal}
429-
aria-label={language.t("command.terminal.toggle")}
430-
aria-expanded={view().terminal.opened()}
431-
aria-controls="terminal-panel"
426+
<Show when={status()}>
427+
<Tooltip placement="bottom" value={language.t("status.popover.trigger")}>
428+
<StatusPopover />
429+
</Tooltip>
430+
</Show>
431+
<Show when={term()}>
432+
<TooltipKeybind
433+
title={language.t("command.terminal.toggle")}
434+
keybind={command.keybind("terminal.toggle")}
432435
>
433-
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
434-
</Button>
435-
</TooltipKeybind>
436+
<Button
437+
variant="ghost"
438+
class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0"
439+
onClick={toggleTerminal}
440+
aria-label={language.t("command.terminal.toggle")}
441+
aria-expanded={view().terminal.opened()}
442+
aria-controls="terminal-panel"
443+
>
444+
<Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} />
445+
</Button>
446+
</TooltipKeybind>
447+
</Show>
436448

437449
<div class="hidden md:flex items-center gap-1 shrink-0">
438450
<TooltipKeybind
@@ -451,30 +463,32 @@ export function SessionHeader() {
451463
</Button>
452464
</TooltipKeybind>
453465

454-
<TooltipKeybind
455-
title={language.t("command.fileTree.toggle")}
456-
keybind={command.keybind("fileTree.toggle")}
457-
>
458-
<Button
459-
variant="ghost"
460-
class="titlebar-icon w-8 h-6 p-0 box-border"
461-
onClick={() => layout.fileTree.toggle()}
462-
aria-label={language.t("command.fileTree.toggle")}
463-
aria-expanded={layout.fileTree.opened()}
464-
aria-controls="file-tree-panel"
466+
<Show when={tree()}>
467+
<TooltipKeybind
468+
title={language.t("command.fileTree.toggle")}
469+
keybind={command.keybind("fileTree.toggle")}
465470
>
466-
<div class="relative flex items-center justify-center size-4">
467-
<Icon
468-
size="small"
469-
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
470-
classList={{
471-
"text-icon-strong": layout.fileTree.opened(),
472-
"text-icon-weak": !layout.fileTree.opened(),
473-
}}
474-
/>
475-
</div>
476-
</Button>
477-
</TooltipKeybind>
471+
<Button
472+
variant="ghost"
473+
class="titlebar-icon w-8 h-6 p-0 box-border"
474+
onClick={() => layout.fileTree.toggle()}
475+
aria-label={language.t("command.fileTree.toggle")}
476+
aria-expanded={layout.fileTree.opened()}
477+
aria-controls="file-tree-panel"
478+
>
479+
<div class="relative flex items-center justify-center size-4">
480+
<Icon
481+
size="small"
482+
name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"}
483+
classList={{
484+
"text-icon-strong": layout.fileTree.opened(),
485+
"text-icon-weak": !layout.fileTree.opened(),
486+
}}
487+
/>
488+
</div>
489+
</Button>
490+
</TooltipKeybind>
491+
</Show>
478492
</div>
479493
</div>
480494
</div>

packages/app/src/components/settings-general.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ export const SettingsGeneral: Component = () => {
106106

107107
permission.disableAutoAccept(params.id, value)
108108
}
109+
const desktop = createMemo(() => platform.platform === "desktop")
109110

110111
const check = () => {
111112
if (!platform.checkUpdate) return
@@ -279,6 +280,74 @@ export const SettingsGeneral: Component = () => {
279280
</div>
280281
)
281282

283+
const AdvancedSection = () => (
284+
<div class="flex flex-col gap-1">
285+
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
286+
287+
<SettingsList>
288+
<SettingsRow
289+
title={language.t("settings.general.row.showFileTree.title")}
290+
description={language.t("settings.general.row.showFileTree.description")}
291+
>
292+
<div data-action="settings-show-file-tree">
293+
<Switch
294+
checked={settings.general.showFileTree()}
295+
onChange={(checked) => settings.general.setShowFileTree(checked)}
296+
/>
297+
</div>
298+
</SettingsRow>
299+
300+
<SettingsRow
301+
title={language.t("settings.general.row.showNavigation.title")}
302+
description={language.t("settings.general.row.showNavigation.description")}
303+
>
304+
<div data-action="settings-show-navigation">
305+
<Switch
306+
checked={settings.general.showNavigation()}
307+
onChange={(checked) => settings.general.setShowNavigation(checked)}
308+
/>
309+
</div>
310+
</SettingsRow>
311+
312+
<SettingsRow
313+
title={language.t("settings.general.row.showSearch.title")}
314+
description={language.t("settings.general.row.showSearch.description")}
315+
>
316+
<div data-action="settings-show-search">
317+
<Switch
318+
checked={settings.general.showSearch()}
319+
onChange={(checked) => settings.general.setShowSearch(checked)}
320+
/>
321+
</div>
322+
</SettingsRow>
323+
324+
<SettingsRow
325+
title={language.t("settings.general.row.showTerminal.title")}
326+
description={language.t("settings.general.row.showTerminal.description")}
327+
>
328+
<div data-action="settings-show-terminal">
329+
<Switch
330+
checked={settings.general.showTerminal()}
331+
onChange={(checked) => settings.general.setShowTerminal(checked)}
332+
/>
333+
</div>
334+
</SettingsRow>
335+
336+
<SettingsRow
337+
title={language.t("settings.general.row.showStatus.title")}
338+
description={language.t("settings.general.row.showStatus.description")}
339+
>
340+
<div data-action="settings-show-status">
341+
<Switch
342+
checked={settings.general.showStatus()}
343+
onChange={(checked) => settings.general.setShowStatus(checked)}
344+
/>
345+
</div>
346+
</SettingsRow>
347+
</SettingsList>
348+
</div>
349+
)
350+
282351
const AppearanceSection = () => (
283352
<div class="flex flex-col gap-1">
284353
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
@@ -609,6 +678,10 @@ export const SettingsGeneral: Component = () => {
609678
)
610679
}}
611680
</Show>
681+
682+
<Show when={desktop()}>
683+
<AdvancedSection />
684+
</Show>
612685
</div>
613686
</div>
614687
)

packages/app/src/components/titlebar.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { useLayout } from "@/context/layout"
1111
import { usePlatform } from "@/context/platform"
1212
import { useCommand } from "@/context/command"
1313
import { useLanguage } from "@/context/language"
14+
import { useSettings } from "@/context/settings"
1415
import { applyPath, backPath, forwardPath } from "./titlebar-history"
1516

1617
type TauriDesktopWindow = {
@@ -40,6 +41,7 @@ export function Titlebar() {
4041
const platform = usePlatform()
4142
const command = useCommand()
4243
const language = useLanguage()
44+
const settings = useSettings()
4345
const theme = useTheme()
4446
const navigate = useNavigate()
4547
const location = useLocation()
@@ -78,6 +80,7 @@ export function Titlebar() {
7880
const canBack = createMemo(() => history.index > 0)
7981
const canForward = createMemo(() => history.index < history.stack.length - 1)
8082
const hasProjects = createMemo(() => layout.projects.list().length > 0)
83+
const nav = createMemo(() => platform.platform !== "desktop" || settings.general.showNavigation())
8184

8285
const back = () => {
8386
const next = backPath(history)
@@ -252,7 +255,7 @@ export function Titlebar() {
252255
</div>
253256
</div>
254257
</Show>
255-
<Show when={hasProjects()}>
258+
<Show when={hasProjects() && nav()}>
256259
<div
257260
class="flex items-center gap-0 transition-transform"
258261
classList={{

packages/app/src/context/settings.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ export interface Settings {
2323
autoSave: boolean
2424
releaseNotes: boolean
2525
followup: "queue" | "steer"
26+
showFileTree: boolean
27+
showNavigation: boolean
28+
showSearch: boolean
29+
showStatus: boolean
30+
showTerminal: boolean
2631
showReasoningSummaries: boolean
2732
shellToolPartsExpanded: boolean
2833
editToolPartsExpanded: boolean
@@ -89,6 +94,11 @@ const defaultSettings: Settings = {
8994
autoSave: true,
9095
releaseNotes: true,
9196
followup: "steer",
97+
showFileTree: false,
98+
showNavigation: false,
99+
showSearch: false,
100+
showStatus: false,
101+
showTerminal: false,
92102
showReasoningSummaries: false,
93103
shellToolPartsExpanded: false,
94104
editToolPartsExpanded: false,
@@ -162,6 +172,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
162172
setFollowup(value: "queue" | "steer") {
163173
setStore("general", "followup", value === "queue" ? "steer" : value)
164174
},
175+
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
176+
setShowFileTree(value: boolean) {
177+
setStore("general", "showFileTree", value)
178+
},
179+
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
180+
setShowNavigation(value: boolean) {
181+
setStore("general", "showNavigation", value)
182+
},
183+
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
184+
setShowSearch(value: boolean) {
185+
setStore("general", "showSearch", value)
186+
},
187+
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
188+
setShowStatus(value: boolean) {
189+
setStore("general", "showStatus", value)
190+
},
191+
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
192+
setShowTerminal(value: boolean) {
193+
setStore("general", "showTerminal", value)
194+
},
165195
showReasoningSummaries: withFallback(
166196
() => store.general?.showReasoningSummaries,
167197
defaultSettings.general.showReasoningSummaries,

packages/app/src/i18n/en.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,7 @@ export const dict = {
719719
"settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.",
720720

721721
"settings.general.section.appearance": "Appearance",
722+
"settings.general.section.advanced": "Advanced",
722723
"settings.general.section.notifications": "System notifications",
723724
"settings.general.section.updates": "Updates",
724725
"settings.general.section.sounds": "Sound effects",
@@ -741,6 +742,16 @@ export const dict = {
741742
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
742743
"settings.general.row.followup.option.queue": "Queue",
743744
"settings.general.row.followup.option.steer": "Steer",
745+
"settings.general.row.showFileTree.title": "File tree",
746+
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
747+
"settings.general.row.showNavigation.title": "Navigation controls",
748+
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
749+
"settings.general.row.showSearch.title": "Command palette",
750+
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
751+
"settings.general.row.showTerminal.title": "Terminal",
752+
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
753+
"settings.general.row.showStatus.title": "Server status",
754+
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
744755
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
745756
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
746757
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",

0 commit comments

Comments
 (0)