Skip to content

Commit 9c12ff5

Browse files
Apply PR #19029: feat(app): hide desktop titlebar tools behind settings
2 parents 4a92d04 + fa9674e commit 9c12ff5

7 files changed

Lines changed: 308 additions & 161 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
@@ -76,6 +76,7 @@ export const SettingsGeneral: Component = () => {
7676
})
7777

7878
const linux = createMemo(() => platform.platform === "desktop" && platform.os === "linux")
79+
const desktop = createMemo(() => platform.platform === "desktop")
7980

8081
const check = () => {
8182
if (!platform.checkUpdate) return
@@ -263,6 +264,74 @@ export const SettingsGeneral: Component = () => {
263264
</div>
264265
)
265266

267+
const AdvancedSection = () => (
268+
<div class="flex flex-col gap-1">
269+
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
270+
271+
<SettingsList>
272+
<SettingsRow
273+
title={language.t("settings.general.row.showFileTree.title")}
274+
description={language.t("settings.general.row.showFileTree.description")}
275+
>
276+
<div data-action="settings-show-file-tree">
277+
<Switch
278+
checked={settings.general.showFileTree()}
279+
onChange={(checked) => settings.general.setShowFileTree(checked)}
280+
/>
281+
</div>
282+
</SettingsRow>
283+
284+
<SettingsRow
285+
title={language.t("settings.general.row.showNavigation.title")}
286+
description={language.t("settings.general.row.showNavigation.description")}
287+
>
288+
<div data-action="settings-show-navigation">
289+
<Switch
290+
checked={settings.general.showNavigation()}
291+
onChange={(checked) => settings.general.setShowNavigation(checked)}
292+
/>
293+
</div>
294+
</SettingsRow>
295+
296+
<SettingsRow
297+
title={language.t("settings.general.row.showSearch.title")}
298+
description={language.t("settings.general.row.showSearch.description")}
299+
>
300+
<div data-action="settings-show-search">
301+
<Switch
302+
checked={settings.general.showSearch()}
303+
onChange={(checked) => settings.general.setShowSearch(checked)}
304+
/>
305+
</div>
306+
</SettingsRow>
307+
308+
<SettingsRow
309+
title={language.t("settings.general.row.showTerminal.title")}
310+
description={language.t("settings.general.row.showTerminal.description")}
311+
>
312+
<div data-action="settings-show-terminal">
313+
<Switch
314+
checked={settings.general.showTerminal()}
315+
onChange={(checked) => settings.general.setShowTerminal(checked)}
316+
/>
317+
</div>
318+
</SettingsRow>
319+
320+
<SettingsRow
321+
title={language.t("settings.general.row.showStatus.title")}
322+
description={language.t("settings.general.row.showStatus.description")}
323+
>
324+
<div data-action="settings-show-status">
325+
<Switch
326+
checked={settings.general.showStatus()}
327+
onChange={(checked) => settings.general.setShowStatus(checked)}
328+
/>
329+
</div>
330+
</SettingsRow>
331+
</SettingsList>
332+
</div>
333+
)
334+
266335
const AppearanceSection = () => (
267336
<div class="flex flex-col gap-1">
268337
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
@@ -593,6 +662,10 @@ export const SettingsGeneral: Component = () => {
593662
)
594663
}}
595664
</Show>
665+
666+
<Show when={desktop()}>
667+
<AdvancedSection />
668+
</Show>
596669
</div>
597670
</div>
598671
)

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
@@ -91,6 +96,11 @@ const defaultSettings: Settings = {
9196
autoSave: true,
9297
releaseNotes: true,
9398
followup: "steer",
99+
showFileTree: false,
100+
showNavigation: false,
101+
showSearch: false,
102+
showStatus: false,
103+
showTerminal: false,
94104
showReasoningSummaries: false,
95105
shellToolPartsExpanded: false,
96106
editToolPartsExpanded: false,
@@ -156,6 +166,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
156166
setFollowup(value: "queue" | "steer") {
157167
setStore("general", "followup", value)
158168
},
169+
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
170+
setShowFileTree(value: boolean) {
171+
setStore("general", "showFileTree", value)
172+
},
173+
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
174+
setShowNavigation(value: boolean) {
175+
setStore("general", "showNavigation", value)
176+
},
177+
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
178+
setShowSearch(value: boolean) {
179+
setStore("general", "showSearch", value)
180+
},
181+
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
182+
setShowStatus(value: boolean) {
183+
setStore("general", "showStatus", value)
184+
},
185+
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
186+
setShowTerminal(value: boolean) {
187+
setStore("general", "showTerminal", value)
188+
},
159189
showReasoningSummaries: withFallback(
160190
() => store.general?.showReasoningSummaries,
161191
defaultSettings.general.showReasoningSummaries,

packages/app/src/i18n/en.ts

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

717717
"settings.general.section.appearance": "Appearance",
718+
"settings.general.section.advanced": "Advanced",
718719
"settings.general.section.notifications": "System notifications",
719720
"settings.general.section.updates": "Updates",
720721
"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)