diff --git a/apps/server/src/keybindings.test.ts b/apps/server/src/keybindings.test.ts index b674688f041..24a137d933f 100644 --- a/apps/server/src/keybindings.test.ts +++ b/apps/server/src/keybindings.test.ts @@ -203,6 +203,7 @@ it.layer(NodeServices.layer)("keybindings", (it) => { assert.equal(defaultsByCommand.get("projectSearch.toggle"), "mod+shift+f"); assert.equal(defaultsByCommand.get("sidebar.toggle"), "mod+b"); assert.equal(defaultsByCommand.get("rightPanel.toggle"), "mod+alt+b"); + assert.isFalse(defaultsByCommand.has("rightPanel.toggleMaximized")); assert.equal(defaultsByCommand.get("terminal.splitVertical"), "mod+shift+d"); assert.equal(defaultsByCommand.get("modelPicker.jump.1"), "mod+1"); assert.equal(defaultsByCommand.get("modelPicker.jump.9"), "mod+9"); diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index d2d3e908c1c..feac2d5978c 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -4739,6 +4739,13 @@ function ChatViewContent(props: ChatViewProps) { return; } + if (command === "rightPanel.toggleMaximized") { + event.preventDefault(); + event.stopPropagation(); + toggleRightPanelMaximized(); + return; + } + if (command === "terminal.split") { event.preventDefault(); event.stopPropagation(); @@ -4834,6 +4841,7 @@ function ChatViewContent(props: ChatViewProps) { keybindings, onToggleDiff, toggleRightPanel, + toggleRightPanelMaximized, toggleTerminalVisibility, composerRef, ]); diff --git a/apps/web/src/components/settings/KeybindingsSettings.logic.test.ts b/apps/web/src/components/settings/KeybindingsSettings.logic.test.ts index 22a91b7c150..90eaaef9941 100644 --- a/apps/web/src/components/settings/KeybindingsSettings.logic.test.ts +++ b/apps/web/src/components/settings/KeybindingsSettings.logic.test.ts @@ -135,7 +135,7 @@ describe("KeybindingsSettings.logic", () => { expect(options).not.toContain("customModeActive"); }); - it("builds command options from defaults and resolved project bindings", () => { + it("builds command options from built-in commands and resolved project bindings", () => { const options = buildKeybindingCommandOptions([ { command: "script.setup-db.run", @@ -150,7 +150,9 @@ describe("KeybindingsSettings.logic", () => { }, ] satisfies ResolvedKeybindingsConfig); - expect(options).toEqual(expect.arrayContaining(["chat.new", "script.setup-db.run"])); + expect(options).toEqual( + expect.arrayContaining(["chat.new", "rightPanel.toggleMaximized", "script.setup-db.run"]), + ); }); it("reports unknown when variables without rejecting parseable expressions", () => { diff --git a/apps/web/src/components/settings/KeybindingsSettings.logic.ts b/apps/web/src/components/settings/KeybindingsSettings.logic.ts index da54e86e42e..8c15111e196 100644 --- a/apps/web/src/components/settings/KeybindingsSettings.logic.ts +++ b/apps/web/src/components/settings/KeybindingsSettings.logic.ts @@ -1,4 +1,5 @@ import { + STATIC_KEYBINDING_COMMANDS, type KeybindingCommand, type KeybindingShortcut, type KeybindingWhenNode, @@ -255,10 +256,7 @@ export function buildWhenVariableOptions(): ReadonlyArray { export function buildKeybindingCommandOptions( keybindings: ResolvedKeybindingsConfig, ): ReadonlyArray { - const commands = new Set(); - for (const binding of DEFAULT_RESOLVED_KEYBINDINGS) { - commands.add(binding.command); - } + const commands = new Set(STATIC_KEYBINDING_COMMANDS); for (const binding of keybindings) { commands.add(binding.command); } diff --git a/apps/web/src/keybindings.test.ts b/apps/web/src/keybindings.test.ts index 11aa97dc8e8..da76e13d56e 100644 --- a/apps/web/src/keybindings.test.ts +++ b/apps/web/src/keybindings.test.ts @@ -679,6 +679,22 @@ describe("resolveShortcutCommand", () => { ); }); + it("resolves a custom right panel maximize binding", () => { + const keybindings = compile([ + { + shortcut: modShortcut("m", { shiftKey: true }), + command: "rightPanel.toggleMaximized", + }, + ]); + + assert.strictEqual( + resolveShortcutCommand(event({ key: "m", metaKey: true, shiftKey: true }), keybindings, { + platform: "MacIntel", + }), + "rightPanel.toggleMaximized", + ); + }); + it("matches bracket shortcuts using the physical key code", () => { assert.strictEqual( resolveShortcutCommand( diff --git a/docs/user/keybindings.md b/docs/user/keybindings.md index f7f6facbe59..63264bed10b 100644 --- a/docs/user/keybindings.md +++ b/docs/user/keybindings.md @@ -47,6 +47,9 @@ Use **Inspect** to pick an element in the app and reveal its color token. Inspec successful pick; its hover glow and badge preview the element and token that click will select. **Cancel** or `Escape` exits Inspect and clears its selection and spotlight. +`rightPanel.toggleMaximized` maximizes or restores the open right panel. It has no default shortcut, +so add one in **Settings** → **Keybindings** if you want to use it. + The command palette searches active thread titles, projects, branches, user messages, and final agent responses across connected environments. Message matches show one labeled excerpt while keeping the thread's project, branch, and machine context visible. Message search begins after two diff --git a/packages/contracts/src/keybindings.test.ts b/packages/contracts/src/keybindings.test.ts index 342e4467893..71d8624a8ae 100644 --- a/packages/contracts/src/keybindings.test.ts +++ b/packages/contracts/src/keybindings.test.ts @@ -42,6 +42,12 @@ it.effect("parses keybinding rules", () => }); assert.strictEqual(parsedRightPanelToggle.command, "rightPanel.toggle"); + const parsedRightPanelToggleMaximized = yield* decode(KeybindingRule, { + key: "mod+shift+m", + command: "rightPanel.toggleMaximized", + }); + assert.strictEqual(parsedRightPanelToggleMaximized.command, "rightPanel.toggleMaximized"); + const parsedClose = yield* decode(KeybindingRule, { key: "mod+w", command: "terminal.close", diff --git a/packages/contracts/src/keybindings.ts b/packages/contracts/src/keybindings.ts index 3fcbf6ef5fd..19276c41e7b 100644 --- a/packages/contracts/src/keybindings.ts +++ b/packages/contracts/src/keybindings.ts @@ -47,7 +47,7 @@ export const MODEL_PICKER_KEYBINDING_COMMANDS = [ ] as const; export type ModelPickerKeybindingCommand = (typeof MODEL_PICKER_KEYBINDING_COMMANDS)[number]; -const STATIC_KEYBINDING_COMMANDS = [ +export const STATIC_KEYBINDING_COMMANDS = [ "sidebar.toggle", "terminal.toggle", "terminal.split", @@ -55,6 +55,7 @@ const STATIC_KEYBINDING_COMMANDS = [ "terminal.new", "terminal.close", "rightPanel.toggle", + "rightPanel.toggleMaximized", "diff.toggle", "preview.toggle", "preview.refresh",