Skip to content

Commit e0665a0

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

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
@@ -49,6 +49,7 @@ export const SettingsGeneral: Component = () => {
4949
})
5050

5151
const linux = createMemo(() => platform.platform === "desktop" && platform.os === "linux")
52+
const desktop = createMemo(() => platform.platform === "desktop")
5253

5354
const check = () => {
5455
if (!platform.checkUpdate) return
@@ -253,6 +254,74 @@ export const SettingsGeneral: Component = () => {
253254
</div>
254255
)
255256

257+
const AdvancedSection = () => (
258+
<div class="flex flex-col gap-1">
259+
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3>
260+
261+
<SettingsList>
262+
<SettingsRow
263+
title={language.t("settings.general.row.showFileTree.title")}
264+
description={language.t("settings.general.row.showFileTree.description")}
265+
>
266+
<div data-action="settings-show-file-tree">
267+
<Switch
268+
checked={settings.general.showFileTree()}
269+
onChange={(checked) => settings.general.setShowFileTree(checked)}
270+
/>
271+
</div>
272+
</SettingsRow>
273+
274+
<SettingsRow
275+
title={language.t("settings.general.row.showNavigation.title")}
276+
description={language.t("settings.general.row.showNavigation.description")}
277+
>
278+
<div data-action="settings-show-navigation">
279+
<Switch
280+
checked={settings.general.showNavigation()}
281+
onChange={(checked) => settings.general.setShowNavigation(checked)}
282+
/>
283+
</div>
284+
</SettingsRow>
285+
286+
<SettingsRow
287+
title={language.t("settings.general.row.showSearch.title")}
288+
description={language.t("settings.general.row.showSearch.description")}
289+
>
290+
<div data-action="settings-show-search">
291+
<Switch
292+
checked={settings.general.showSearch()}
293+
onChange={(checked) => settings.general.setShowSearch(checked)}
294+
/>
295+
</div>
296+
</SettingsRow>
297+
298+
<SettingsRow
299+
title={language.t("settings.general.row.showTerminal.title")}
300+
description={language.t("settings.general.row.showTerminal.description")}
301+
>
302+
<div data-action="settings-show-terminal">
303+
<Switch
304+
checked={settings.general.showTerminal()}
305+
onChange={(checked) => settings.general.setShowTerminal(checked)}
306+
/>
307+
</div>
308+
</SettingsRow>
309+
310+
<SettingsRow
311+
title={language.t("settings.general.row.showStatus.title")}
312+
description={language.t("settings.general.row.showStatus.description")}
313+
>
314+
<div data-action="settings-show-status">
315+
<Switch
316+
checked={settings.general.showStatus()}
317+
onChange={(checked) => settings.general.setShowStatus(checked)}
318+
/>
319+
</div>
320+
</SettingsRow>
321+
</SettingsList>
322+
</div>
323+
)
324+
256325
const AppearanceSection = () => (
257326
<div class="flex flex-col gap-1">
258327
<h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3>
@@ -561,6 +630,10 @@ export const SettingsGeneral: Component = () => {
561630
)
562631
}}
563632
</Show>
633+
634+
<Show when={desktop()}>
635+
<AdvancedSection />
636+
</Show>
564637
</div>
565638
</div>
566639
)

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,
@@ -132,6 +142,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont
132142
setFollowup(value: "queue" | "steer") {
133143
setStore("general", "followup", value)
134144
},
145+
showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree),
146+
setShowFileTree(value: boolean) {
147+
setStore("general", "showFileTree", value)
148+
},
149+
showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation),
150+
setShowNavigation(value: boolean) {
151+
setStore("general", "showNavigation", value)
152+
},
153+
showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch),
154+
setShowSearch(value: boolean) {
155+
setStore("general", "showSearch", value)
156+
},
157+
showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus),
158+
setShowStatus(value: boolean) {
159+
setStore("general", "showStatus", value)
160+
},
161+
showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal),
162+
setShowTerminal(value: boolean) {
163+
setStore("general", "showTerminal", value)
164+
},
135165
showReasoningSummaries: withFallback(
136166
() => store.general?.showReasoningSummaries,
137167
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",
@@ -735,6 +736,16 @@ export const dict = {
735736
"settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue",
736737
"settings.general.row.followup.option.queue": "Queue",
737738
"settings.general.row.followup.option.steer": "Steer",
739+
"settings.general.row.showFileTree.title": "File tree",
740+
"settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions",
741+
"settings.general.row.showNavigation.title": "Navigation controls",
742+
"settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar",
743+
"settings.general.row.showSearch.title": "Command palette",
744+
"settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar",
745+
"settings.general.row.showTerminal.title": "Terminal",
746+
"settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar",
747+
"settings.general.row.showStatus.title": "Server status",
748+
"settings.general.row.showStatus.description": "Show the server status button in the desktop title bar",
738749
"settings.general.row.reasoningSummaries.title": "Show reasoning summaries",
739750
"settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline",
740751
"settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts",

0 commit comments

Comments
 (0)