diff options
| author | Jay <[email protected]> | 2026-04-16 23:31:00 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-17 03:31:00 +0000 |
| commit | fbbab9d6c8a03c4cd5bed0d13a85f52e3aca47ce (patch) | |
| tree | 883ade9bc40164adaf14e69069068971cda17cee | |
| parent | cccb907a9b3df7eb6fae71ee9e2392dccc73e9d3 (diff) | |
| download | opencode-fbbab9d6c8a03c4cd5bed0d13a85f52e3aca47ce.tar.gz opencode-fbbab9d6c8a03c4cd5bed0d13a85f52e3aca47ce.zip | |
feat(app): hide desktop titlebar tools behind settings (#19029)
Co-authored-by: Brendan Allan <[email protected]>
Co-authored-by: Brendan Allan <[email protected]>
| -rw-r--r-- | packages/app/src/components/session/session-header.tsx | 105 | ||||
| -rw-r--r-- | packages/app/src/components/settings-general.tsx | 74 | ||||
| -rw-r--r-- | packages/app/src/components/titlebar.tsx | 8 | ||||
| -rw-r--r-- | packages/app/src/context/settings.tsx | 30 | ||||
| -rw-r--r-- | packages/app/src/env.d.ts | 6 | ||||
| -rw-r--r-- | packages/app/src/i18n/en.ts | 11 | ||||
| -rw-r--r-- | packages/app/src/pages/session/session-side-panel.tsx | 176 | ||||
| -rw-r--r-- | packages/app/src/pages/session/use-session-commands.tsx | 21 |
8 files changed, 290 insertions, 141 deletions
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 7acfdfc37..021e5be67 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -8,7 +8,7 @@ import { Spinner } from "@opencode-ai/ui/spinner" import { showToast } from "@opencode-ai/ui/toast" import { Tooltip, TooltipKeybind } from "@opencode-ai/ui/tooltip" import { getFilename } from "@opencode-ai/shared/util/path" -import { createEffect, createMemo, For, Show } from "solid-js" +import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js" import { createStore } from "solid-js/store" import { Portal } from "solid-js/web" import { useCommand } from "@/context/command" @@ -16,6 +16,7 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { usePlatform } from "@/context/platform" import { useServer } from "@/context/server" +import { useSettings } from "@/context/settings" import { useSync } from "@/context/sync" import { useTerminal } from "@/context/terminal" import { focusTerminalById } from "@/pages/session/helpers" @@ -134,6 +135,7 @@ export function SessionHeader() { const server = useServer() const platform = usePlatform() const language = useLanguage() + const settings = useSettings() const sync = useSync() const terminal = useTerminal() const { params, view } = useSessionLayout() @@ -151,6 +153,11 @@ export function SessionHeader() { }) const hotkey = createMemo(() => command.keybind("file.open")) const os = createMemo(() => detectOS(platform)) + const isDesktopBeta = platform.platform === "desktop" && import.meta.env.VITE_OPENCODE_CHANNEL === "beta" + const search = createMemo(() => !isDesktopBeta || settings.general.showSearch()) + const tree = createMemo(() => !isDesktopBeta || settings.general.showFileTree()) + const term = createMemo(() => !isDesktopBeta || settings.general.showTerminal()) + const status = createMemo(() => !isDesktopBeta || settings.general.showStatus()) const [exists, setExists] = createStore<Partial<Record<OpenApp, boolean>>>({ finder: true, @@ -262,12 +269,16 @@ export function SessionHeader() { .catch((err: unknown) => showRequestError(language, err)) } - const centerMount = createMemo(() => document.getElementById("opencode-titlebar-center")) - const rightMount = createMemo(() => document.getElementById("opencode-titlebar-right")) + const [centerMount, setCenterMount] = createSignal<HTMLElement | null>(null) + const [rightMount, setRightMount] = createSignal<HTMLElement | null>(null) + onMount(() => { + setCenterMount(document.getElementById("opencode-titlebar-center")) + setRightMount(document.getElementById("opencode-titlebar-right")) + }) return ( <> - <Show when={centerMount()}> + <Show when={search() && centerMount()}> {(mount) => ( <Portal mount={mount()}> <Button @@ -415,24 +426,28 @@ export function SessionHeader() { </div> </Show> <div class="flex items-center gap-1"> - <Tooltip placement="bottom" value={language.t("status.popover.trigger")}> - <StatusPopover /> - </Tooltip> - <TooltipKeybind - title={language.t("command.terminal.toggle")} - keybind={command.keybind("terminal.toggle")} - > - <Button - variant="ghost" - class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0" - onClick={toggleTerminal} - aria-label={language.t("command.terminal.toggle")} - aria-expanded={view().terminal.opened()} - aria-controls="terminal-panel" + <Show when={status()}> + <Tooltip placement="bottom" value={language.t("status.popover.trigger")}> + <StatusPopover /> + </Tooltip> + </Show> + <Show when={term()}> + <TooltipKeybind + title={language.t("command.terminal.toggle")} + keybind={command.keybind("terminal.toggle")} > - <Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} /> - </Button> - </TooltipKeybind> + <Button + variant="ghost" + class="group/terminal-toggle titlebar-icon w-8 h-6 p-0 box-border shrink-0" + onClick={toggleTerminal} + aria-label={language.t("command.terminal.toggle")} + aria-expanded={view().terminal.opened()} + aria-controls="terminal-panel" + > + <Icon size="small" name={view().terminal.opened() ? "terminal-active" : "terminal"} /> + </Button> + </TooltipKeybind> + </Show> <div class="hidden md:flex items-center gap-1 shrink-0"> <TooltipKeybind @@ -451,30 +466,32 @@ export function SessionHeader() { </Button> </TooltipKeybind> - <TooltipKeybind - title={language.t("command.fileTree.toggle")} - keybind={command.keybind("fileTree.toggle")} - > - <Button - variant="ghost" - class="titlebar-icon w-8 h-6 p-0 box-border" - onClick={() => layout.fileTree.toggle()} - aria-label={language.t("command.fileTree.toggle")} - aria-expanded={layout.fileTree.opened()} - aria-controls="file-tree-panel" + <Show when={tree()}> + <TooltipKeybind + title={language.t("command.fileTree.toggle")} + keybind={command.keybind("fileTree.toggle")} > - <div class="relative flex items-center justify-center size-4"> - <Icon - size="small" - name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"} - classList={{ - "text-icon-strong": layout.fileTree.opened(), - "text-icon-weak": !layout.fileTree.opened(), - }} - /> - </div> - </Button> - </TooltipKeybind> + <Button + variant="ghost" + class="titlebar-icon w-8 h-6 p-0 box-border" + onClick={() => layout.fileTree.toggle()} + aria-label={language.t("command.fileTree.toggle")} + aria-expanded={layout.fileTree.opened()} + aria-controls="file-tree-panel" + > + <div class="relative flex items-center justify-center size-4"> + <Icon + size="small" + name={layout.fileTree.opened() ? "file-tree-active" : "file-tree"} + classList={{ + "text-icon-strong": layout.fileTree.opened(), + "text-icon-weak": !layout.fileTree.opened(), + }} + /> + </div> + </Button> + </TooltipKeybind> + </Show> </div> </div> </div> diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx index b4ac061df..c380fb69b 100644 --- a/packages/app/src/components/settings-general.tsx +++ b/packages/app/src/components/settings-general.tsx @@ -106,6 +106,7 @@ export const SettingsGeneral: Component = () => { permission.disableAutoAccept(params.id, value) } + const desktop = createMemo(() => platform.platform === "desktop") const check = () => { if (!platform.checkUpdate) return @@ -279,6 +280,74 @@ export const SettingsGeneral: Component = () => { </div> ) + const AdvancedSection = () => ( + <div class="flex flex-col gap-1"> + <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.advanced")}</h3> + + <SettingsList> + <SettingsRow + title={language.t("settings.general.row.showFileTree.title")} + description={language.t("settings.general.row.showFileTree.description")} + > + <div data-action="settings-show-file-tree"> + <Switch + checked={settings.general.showFileTree()} + onChange={(checked) => settings.general.setShowFileTree(checked)} + /> + </div> + </SettingsRow> + + <SettingsRow + title={language.t("settings.general.row.showNavigation.title")} + description={language.t("settings.general.row.showNavigation.description")} + > + <div data-action="settings-show-navigation"> + <Switch + checked={settings.general.showNavigation()} + onChange={(checked) => settings.general.setShowNavigation(checked)} + /> + </div> + </SettingsRow> + + <SettingsRow + title={language.t("settings.general.row.showSearch.title")} + description={language.t("settings.general.row.showSearch.description")} + > + <div data-action="settings-show-search"> + <Switch + checked={settings.general.showSearch()} + onChange={(checked) => settings.general.setShowSearch(checked)} + /> + </div> + </SettingsRow> + + <SettingsRow + title={language.t("settings.general.row.showTerminal.title")} + description={language.t("settings.general.row.showTerminal.description")} + > + <div data-action="settings-show-terminal"> + <Switch + checked={settings.general.showTerminal()} + onChange={(checked) => settings.general.setShowTerminal(checked)} + /> + </div> + </SettingsRow> + + <SettingsRow + title={language.t("settings.general.row.showStatus.title")} + description={language.t("settings.general.row.showStatus.description")} + > + <div data-action="settings-show-status"> + <Switch + checked={settings.general.showStatus()} + onChange={(checked) => settings.general.setShowStatus(checked)} + /> + </div> + </SettingsRow> + </SettingsList> + </div> + ) + const AppearanceSection = () => ( <div class="flex flex-col gap-1"> <h3 class="text-14-medium text-text-strong pb-2">{language.t("settings.general.section.appearance")}</h3> @@ -527,6 +596,7 @@ export const SettingsGeneral: Component = () => { </div> ) + console.log(import.meta.env) return ( <div class="flex flex-col h-full overflow-y-auto no-scrollbar px-4 pb-10 sm:px-10 sm:pb-10"> <div class="sticky top-0 z-10 bg-[linear-gradient(to_bottom,var(--surface-stronger-non-alpha)_calc(100%_-_24px),transparent)]"> @@ -609,6 +679,10 @@ export const SettingsGeneral: Component = () => { ) }} </Show> + + <Show when={desktop() && import.meta.env.VITE_OPENCODE_CHANNEL === "beta"}> + <AdvancedSection /> + </Show> </div> </div> ) diff --git a/packages/app/src/components/titlebar.tsx b/packages/app/src/components/titlebar.tsx index b7edb85ed..409fcbeff 100644 --- a/packages/app/src/components/titlebar.tsx +++ b/packages/app/src/components/titlebar.tsx @@ -11,6 +11,7 @@ import { useLayout } from "@/context/layout" import { usePlatform } from "@/context/platform" import { useCommand } from "@/context/command" import { useLanguage } from "@/context/language" +import { useSettings } from "@/context/settings" import { applyPath, backPath, forwardPath } from "./titlebar-history" type TauriDesktopWindow = { @@ -40,6 +41,7 @@ export function Titlebar() { const platform = usePlatform() const command = useCommand() const language = useLanguage() + const settings = useSettings() const theme = useTheme() const navigate = useNavigate() const location = useLocation() @@ -78,6 +80,7 @@ export function Titlebar() { const canBack = createMemo(() => history.index > 0) const canForward = createMemo(() => history.index < history.stack.length - 1) const hasProjects = createMemo(() => layout.projects.list().length > 0) + const nav = createMemo(() => import.meta.env.VITE_OPENCODE_CHANNEL !== "beta" || settings.general.showNavigation()) const back = () => { const next = backPath(history) @@ -255,13 +258,12 @@ export function Titlebar() { <div class="flex items-center shrink-0" classList={{ - "translate-x-0": !layout.sidebar.opened(), - "-translate-x-[36px]": layout.sidebar.opened(), + "-translate-x-[36px]": layout.sidebar.opened() && !!params.dir, "duration-180 ease-out": !layout.sidebar.opened(), "duration-180 ease-in": layout.sidebar.opened(), }} > - <Show when={hasProjects()}> + <Show when={hasProjects() && nav()}> <div class="flex items-center gap-0 transition-transform"> <Tooltip placement="bottom" value={language.t("common.goBack")} openDelay={2000}> <Button diff --git a/packages/app/src/context/settings.tsx b/packages/app/src/context/settings.tsx index afd03365e..a585789ce 100644 --- a/packages/app/src/context/settings.tsx +++ b/packages/app/src/context/settings.tsx @@ -23,6 +23,11 @@ export interface Settings { autoSave: boolean releaseNotes: boolean followup: "queue" | "steer" + showFileTree: boolean + showNavigation: boolean + showSearch: boolean + showStatus: boolean + showTerminal: boolean showReasoningSummaries: boolean shellToolPartsExpanded: boolean editToolPartsExpanded: boolean @@ -89,6 +94,11 @@ const defaultSettings: Settings = { autoSave: true, releaseNotes: true, followup: "steer", + showFileTree: false, + showNavigation: false, + showSearch: false, + showStatus: false, + showTerminal: false, showReasoningSummaries: false, shellToolPartsExpanded: false, editToolPartsExpanded: false, @@ -162,6 +172,26 @@ export const { use: useSettings, provider: SettingsProvider } = createSimpleCont setFollowup(value: "queue" | "steer") { setStore("general", "followup", value === "queue" ? "steer" : value) }, + showFileTree: withFallback(() => store.general?.showFileTree, defaultSettings.general.showFileTree), + setShowFileTree(value: boolean) { + setStore("general", "showFileTree", value) + }, + showNavigation: withFallback(() => store.general?.showNavigation, defaultSettings.general.showNavigation), + setShowNavigation(value: boolean) { + setStore("general", "showNavigation", value) + }, + showSearch: withFallback(() => store.general?.showSearch, defaultSettings.general.showSearch), + setShowSearch(value: boolean) { + setStore("general", "showSearch", value) + }, + showStatus: withFallback(() => store.general?.showStatus, defaultSettings.general.showStatus), + setShowStatus(value: boolean) { + setStore("general", "showStatus", value) + }, + showTerminal: withFallback(() => store.general?.showTerminal, defaultSettings.general.showTerminal), + setShowTerminal(value: boolean) { + setStore("general", "showTerminal", value) + }, showReasoningSummaries: withFallback( () => store.general?.showReasoningSummaries, defaultSettings.general.showReasoningSummaries, diff --git a/packages/app/src/env.d.ts b/packages/app/src/env.d.ts index 22e52f991..9b03d336f 100644 --- a/packages/app/src/env.d.ts +++ b/packages/app/src/env.d.ts @@ -1,16 +1,14 @@ -import "solid-js" - interface ImportMetaEnv { readonly VITE_OPENCODE_SERVER_HOST: string readonly VITE_OPENCODE_SERVER_PORT: string - readonly OPENCODE_CHANNEL?: "dev" | "beta" | "prod" + readonly VITE_OPENCODE_CHANNEL?: "dev" | "beta" | "prod" } interface ImportMeta { readonly env: ImportMetaEnv } -declare module "solid-js" { +export declare module "solid-js" { namespace JSX { interface Directives { sortable: true diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index c6bcc37b1..2cfb79714 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -719,6 +719,7 @@ export const dict = { "settings.desktop.wsl.description": "Run the OpenCode server inside WSL on Windows.", "settings.general.section.appearance": "Appearance", + "settings.general.section.advanced": "Advanced", "settings.general.section.notifications": "System notifications", "settings.general.section.updates": "Updates", "settings.general.section.sounds": "Sound effects", @@ -741,6 +742,16 @@ export const dict = { "settings.general.row.followup.description": "Choose whether follow-up prompts steer immediately or wait in a queue", "settings.general.row.followup.option.queue": "Queue", "settings.general.row.followup.option.steer": "Steer", + "settings.general.row.showFileTree.title": "File tree", + "settings.general.row.showFileTree.description": "Show the file tree toggle and panel in desktop sessions", + "settings.general.row.showNavigation.title": "Navigation controls", + "settings.general.row.showNavigation.description": "Show the back and forward buttons in the desktop title bar", + "settings.general.row.showSearch.title": "Command palette", + "settings.general.row.showSearch.description": "Show the search and command palette button in the desktop title bar", + "settings.general.row.showTerminal.title": "Terminal", + "settings.general.row.showTerminal.description": "Show the terminal button in the desktop title bar", + "settings.general.row.showStatus.title": "Server status", + "settings.general.row.showStatus.description": "Show the server status button in the desktop title bar", "settings.general.row.reasoningSummaries.title": "Show reasoning summaries", "settings.general.row.reasoningSummaries.description": "Display model reasoning summaries in the timeline", "settings.general.row.shellToolPartsExpanded.title": "Expand shell tool parts", diff --git a/packages/app/src/pages/session/session-side-panel.tsx b/packages/app/src/pages/session/session-side-panel.tsx index cddbea84d..06cbec48b 100644 --- a/packages/app/src/pages/session/session-side-panel.tsx +++ b/packages/app/src/pages/session/session-side-panel.tsx @@ -19,6 +19,9 @@ import { useCommand } from "@/context/command" import { useFile, type SelectedLineRange } from "@/context/file" import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" +import { usePlatform } from "@/context/platform" +import { useSettings } from "@/context/settings" +import { useSync } from "@/context/sync" import { createFileTabListSync } from "@/pages/session/file-tab-scroll" import { FileTabContent } from "@/pages/session/file-tabs" import { createOpenSessionFileTab, createSessionTabs, getTabReorderIndex, type Sizing } from "@/pages/session/helpers" @@ -39,6 +42,9 @@ export function SessionSidePanel(props: { size: Sizing }) { const layout = useLayout() + const platform = usePlatform() + const settings = useSettings() + const sync = useSync() const file = useFile() const language = useLanguage() const command = useCommand() @@ -46,9 +52,10 @@ export function SessionSidePanel(props: { const { sessionKey, tabs, view } = useSessionLayout() const isDesktop = createMediaQuery("(min-width: 768px)") + const shown = createMemo(() => platform.platform !== "desktop" || settings.general.showFileTree()) const reviewOpen = createMemo(() => isDesktop() && view().reviewPanel.opened()) - const fileOpen = createMemo(() => isDesktop() && layout.fileTree.opened()) + const fileOpen = createMemo(() => isDesktop() && shown() && layout.fileTree.opened()) const open = createMemo(() => reviewOpen() || fileOpen()) const reviewTab = createMemo(() => isDesktop()) const panelWidth = createMemo(() => { @@ -341,98 +348,99 @@ export function SessionSidePanel(props: { </div> </div> - <div - id="file-tree-panel" - aria-hidden={!fileOpen()} - inert={!fileOpen()} - class="relative min-w-0 h-full shrink-0 overflow-hidden" - classList={{ - "pointer-events-none": !fileOpen(), - "transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none": - !props.size.active(), - }} - style={{ width: treeWidth() }} - > + <Show when={shown()}> <div - class="h-full flex flex-col overflow-hidden group/filetree" - classList={{ "border-l border-border-weaker-base": reviewOpen() }} + id="file-tree-panel" + aria-hidden={!fileOpen()} + inert={!fileOpen()} + class="relative min-w-0 h-full shrink-0 overflow-hidden" + classList={{ + "pointer-events-none": !fileOpen(), + "transition-[width] duration-200 ease-[cubic-bezier(0.22,1,0.36,1)] will-change-[width] motion-reduce:transition-none": + !props.size.active(), + }} + style={{ width: treeWidth() }} > - <Tabs - variant="pill" - value={fileTreeTab()} - onChange={setFileTreeTabValue} - class="h-full" - data-scope="filetree" + <div + class="h-full flex flex-col overflow-hidden group/filetree" + classList={{ "border-l border-border-weaker-base": reviewOpen() }} > - <Tabs.List> - <Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}> - {props.reviewCount()}{" "} - {language.t( - props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other", - )} - </Tabs.Trigger> - <Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}> - {language.t("session.files.all")} - </Tabs.Trigger> - </Tabs.List> - <Tabs.Content value="changes" class="bg-background-stronger px-3 py-0"> - <Switch> - <Match when={props.hasReview() || !props.diffsReady()}> - <Show - when={props.diffsReady()} - fallback={ - <div class="px-2 py-2 text-12-regular text-text-weak"> - {language.t("common.loading")} - {language.t("common.loading.ellipsis")} - </div> - } - > + <Tabs + variant="pill" + value={fileTreeTab()} + onChange={setFileTreeTabValue} + class="h-full" + data-scope="filetree" + > + <Tabs.List> + <Tabs.Trigger value="changes" class="flex-1" classes={{ button: "w-full" }}> + {props.reviewCount()}{" "} + {language.t( + props.reviewCount() === 1 ? "session.review.change.one" : "session.review.change.other", + )} + </Tabs.Trigger> + <Tabs.Trigger value="all" class="flex-1" classes={{ button: "w-full" }}> + {language.t("session.files.all")} + </Tabs.Trigger> + </Tabs.List> + <Tabs.Content value="changes" class="bg-background-stronger px-3 py-0"> + <Switch> + <Match when={props.hasReview() || !props.diffsReady()}> + <Show + when={props.diffsReady()} + fallback={ + <div class="px-2 py-2 text-12-regular text-text-weak"> + {language.t("common.loading")} + {language.t("common.loading.ellipsis")} + </div> + } + > + <FileTree + path="" + class="pt-3" + allowed={diffFiles()} + kinds={kinds()} + draggable={false} + active={props.activeDiff} + onFileClick={(node) => props.focusReviewDiff(node.path)} + /> + </Show> + </Match> + </Switch> + </Tabs.Content> + <Tabs.Content value="all" class="bg-background-stronger px-3 py-0"> + <Switch> + <Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match> + <Match when={true}> <FileTree path="" class="pt-3" - allowed={diffFiles()} + modified={diffFiles()} kinds={kinds()} - draggable={false} - active={props.activeDiff} - onFileClick={(node) => props.focusReviewDiff(node.path)} + onFileClick={(node) => openTab(file.tab(node.path))} /> - </Show> - </Match> - <Match when={true}>{empty(props.empty())}</Match> - </Switch> - </Tabs.Content> - <Tabs.Content value="all" class="bg-background-stronger px-3 py-0"> - <Switch> - <Match when={nofiles()}>{empty(language.t("session.files.empty"))}</Match> - <Match when={true}> - <FileTree - path="" - class="pt-3" - modified={diffFiles()} - kinds={kinds()} - onFileClick={(node) => openTab(file.tab(node.path))} - /> - </Match> - </Switch> - </Tabs.Content> - </Tabs> - </div> - <Show when={fileOpen()}> - <div onPointerDown={() => props.size.start()}> - <ResizeHandle - direction="horizontal" - edge="start" - size={layout.fileTree.width()} - min={200} - max={480} - onResize={(width) => { - props.size.touch() - layout.fileTree.resize(width) - }} - /> + </Match> + </Switch> + </Tabs.Content> + </Tabs> </div> - </Show> - </div> + <Show when={fileOpen()}> + <div onPointerDown={() => props.size.start()}> + <ResizeHandle + direction="horizontal" + edge="start" + size={layout.fileTree.width()} + min={200} + max={480} + onResize={(width) => { + props.size.touch() + layout.fileTree.resize(width) + }} + /> + </div> + </Show> + </div> + </Show> </div> </aside> </Show> diff --git a/packages/app/src/pages/session/use-session-commands.tsx b/packages/app/src/pages/session/use-session-commands.tsx index b5d254463..9bbeb10bd 100644 --- a/packages/app/src/pages/session/use-session-commands.tsx +++ b/packages/app/src/pages/session/use-session-commands.tsx @@ -7,8 +7,10 @@ import { useLanguage } from "@/context/language" import { useLayout } from "@/context/layout" import { useLocal } from "@/context/local" import { usePermission } from "@/context/permission" +import { usePlatform } from "@/context/platform" import { usePrompt } from "@/context/prompt" import { useSDK } from "@/context/sdk" +import { useSettings } from "@/context/settings" import { useSync } from "@/context/sync" import { useTerminal } from "@/context/terminal" import { showToast } from "@opencode-ai/ui/toast" @@ -39,8 +41,10 @@ export const useSessionCommands = (actions: SessionCommandContext) => { const language = useLanguage() const local = useLocal() const permission = usePermission() + const platform = usePlatform() const prompt = usePrompt() const sdk = useSDK() + const settings = useSettings() const sync = useSync() const terminal = useTerminal() const layout = useLayout() @@ -66,6 +70,7 @@ export const useSessionCommands = (actions: SessionCommandContext) => { }) const activeFileTab = tabState.activeFileTab const closableTab = tabState.closableTab + const shown = () => platform.platform !== "desktop" || settings.general.showFileTree() const idle = { type: "idle" as const } const status = () => sync.data.session_status[params.id ?? ""] ?? idle @@ -457,12 +462,16 @@ export const useSessionCommands = (actions: SessionCommandContext) => { keybind: "mod+shift+r", onSelect: () => view().reviewPanel.toggle(), }), - viewCommand({ - id: "fileTree.toggle", - title: language.t("command.fileTree.toggle"), - keybind: "mod+\\", - onSelect: () => layout.fileTree.toggle(), - }), + ...(shown() + ? [ + viewCommand({ + id: "fileTree.toggle", + title: language.t("command.fileTree.toggle"), + keybind: "mod+\\", + onSelect: () => layout.fileTree.toggle(), + }), + ] + : []), viewCommand({ id: "input.focus", title: language.t("command.input.focus"), |
