Skip to content

Commit f0f66e5

Browse files
Apply PR #19029: feat(app): hide desktop titlebar tools behind settings
2 parents 12d8332 + fa9674e commit f0f66e5

7 files changed

Lines changed: 306 additions & 159 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
@@ -74,6 +74,7 @@ export const SettingsGeneral: Component = () => {
7474
})
7575

7676
const linux = createMemo(() => platform.platform === "desktop" && platform.os === "linux")
77+
const desktop = createMemo(() => platform.platform === "desktop")
7778

7879
const check = () => {
7980
if (!platform.checkUpdate) return
@@ -276,6 +277,74 @@ export const SettingsGeneral: Component = () => {
276277
</div>
277278
)
278279

280+
const AdvancedSection = () => (
281+
<div class="flex flex-col gap-1">
282+
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
283+
284+
<SettingsList>
285+
<SettingsRow
286+
title={language.t("settings.general.row.showFileTree.title")}
287+
description={language.t("settings.general.row.showFileTree.description")}
288+
>
289+
<div data-action="settings-show-file-tree">
290+
<Switch
291+
checked={settings.general.showFileTree()}
292+
onChange={(checked) => settings.general.setShowFileTree(checked)}
293+
/>
294+
</div>
295+
</SettingsRow>
296+
297+
<SettingsRow
298+
title={language.t("settings.general.row.showNavigation.title")}
299+
description={language.t("settings.general.row.showNavigation.description")}
300+
>
301+
<div data-action="settings-show-navigation">
302+
<Switch
303+
checked={settings.general.showNavigation()}
304+
onChange={(checked) => settings.general.setShowNavigation(checked)}
305+
/>
306+
</div>
307+
</SettingsRow>
308+
309+
<SettingsRow
310+
title={language.t("settings.general.row.showSearch.title")}
311+
description={language.t("settings.general.row.showSearch.description")}
312+
>
313+
<div data-action="settings-show-search">
314+
<Switch
315+
checked={settings.general.showSearch()}
316+
onChange={(checked) => settings.general.setShowSearch(checked)}
317+
/>
318+
</div>
319+
</SettingsRow>
320+
321+
<SettingsRow
322+
title={language.t("settings.general.row.showTerminal.title")}
323+
description={language.t("settings.general.row.showTerminal.description")}
324+
>
325+
<div data-action="settings-show-terminal">
326+
<Switch
327+
checked={settings.general.showTerminal()}
328+
onChange={(checked) => settings.general.setShowTerminal(checked)}
329+
/>
330+
</div>
331+
</SettingsRow>
332+
333+
<SettingsRow
334+
title={language.t("settings.general.row.showStatus.title")}
335+
description={language.t("settings.general.row.showStatus.description")}
336+
>
337+
<div data-action="settings-show-status">
338+
<Switch
339+
checked={settings.general.showStatus()}
340+
onChange={(checked) => settings.general.setShowStatus(checked)}
341+
/>
342+
</div>
343+
</SettingsRow>
344+
</SettingsList>
345+
</div>
346+
)
347+
279348
const AppearanceSection = () => (
280349
<div class="flex flex-col gap-1">
281350
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
@@ -587,6 +656,10 @@ export const SettingsGeneral: Component = () => {
587656
)
588657
}}
589658
</Show>
659+
660+
<Show when={desktop()}>
661+
<AdvancedSection />
662+
</Show>
590663
</div>
591664
</div>
592665
)

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
@@ -47,6 +52,11 @@ const defaultSettings: Settings = {
4752
autoSave: true,
4853
releaseNotes: true,
4954
followup: "steer",
55+
showFileTree: false,
56+
showNavigation: false,
57+
showSearch: false,
58+
showStatus: false,
59+
showTerminal: false,
5060
showReasoningSummaries: false,
5161
shellToolPartsExpanded: true,
5262
editToolPartsExpanded: false,
@@ -143,6 +153,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
143153
setFollowup(value: "queue" | "steer") {
144154
setStore("general", "followup", value)
145155
},
156+
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
157+
setShowFileTree(value: boolean) {
158+
setStore("general", "showFileTree", value)
159+
},
160+
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
161+
setShowNavigation(value: boolean) {
162+
setStore("general", "showNavigation", value)
163+
},
164+
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
165+
setShowSearch(value: boolean) {
166+
setStore("general", "showSearch", value)
167+
},
168+
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
169+
setShowStatus(value: boolean) {
170+
setStore("general", "showStatus", value)
171+
},
172+
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
173+
setShowTerminal(value: boolean) {
174+
setStore("general", "showTerminal", value)
175+
},
146176
showReasoningSummaries: withFallback(
147177
() => store.general?.showReasoningSummaries,
148178
defaultSettings.general.showReasoningSummaries,

packages/app/src/i18n/en.ts

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

719719
"settings.general.section.appearance": "Appearance",
720+
"settings.general.section.advanced": "Advanced",
720721
"settings.general.section.notifications": "System notifications",
721722
"settings.general.section.updates": "Updates",
722723
"settings.general.section.sounds": "Sound effects",
@@ -737,6 +738,16 @@ export const dict = {
737738
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
738739
"settings.general.row.followup.option.queue": "Queue",
739740
"settings.general.row.followup.option.steer": "Steer",
741+
"settings.general.row.showFileTree.title": "File tree",
742+
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
743+
"settings.general.row.showNavigation.title": "Navigation controls",
744+
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
745+
"settings.general.row.showSearch.title": "Command palette",
746+
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
747+
"settings.general.row.showTerminal.title": "Terminal",
748+
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
749+
"settings.general.row.showStatus.title": "Server status",
750+
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
740751
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
741752
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
742753
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",

0 commit comments

Comments
 (0)