Skip to content

Commit c1bdb1f

Browse files
authored
Merge pull request #1014 from enricoros/claude/issue-1013-20260306-1801
feat: add Ctrl+( / Ctrl+) shortcuts to toggle left drawer and right panel
2 parents 7f5ff30 + dde22a0 commit c1bdb1f

File tree

4 files changed

+35
-1
lines changed

4 files changed

+35
-1
lines changed

src/common/components/shortcuts/globalShortcutsHandler.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ function _handleGlobalShortcutKeyDown(event: KeyboardEvent) {
3737
(shortcut.shift && !event.shiftKey) || (!shortcut.shift && event.shiftKey))
3838
continue;
3939

40+
// Skip if a text input element is focused and the shortcut opts into this guard
41+
if (shortcut.skipIfInput && _isTextInputFocused())
42+
continue;
43+
4044
// Execute the action (and prevent the default browser action)
4145
event.preventDefault();
4246
event.stopPropagation();
@@ -66,3 +70,22 @@ function _uninstallGlobalShortcutHandler() {
6670
isHandlerInstalled = false;
6771
}
6872
}
73+
74+
/** Returns true if the active element (or an ancestor with focus) is a text input, textarea, or contenteditable. */
75+
function _isTextInputFocused(): boolean {
76+
const el = document.activeElement;
77+
if (!el || el === document.body)
78+
return false;
79+
if (el instanceof HTMLInputElement && (el.type === 'text' || el.type === 'search' || el.type === 'url' || el.type === 'email' || el.type === 'password' || el.type === 'number' || el.type === 'tel'))
80+
return true;
81+
if (el instanceof HTMLTextAreaElement)
82+
return true;
83+
// check the element and its ancestors for contenteditable
84+
let node: Element | null = el;
85+
while (node) {
86+
if (node instanceof HTMLElement && node.isContentEditable)
87+
return true;
88+
node = node.parentElement;
89+
}
90+
return false;
91+
}

src/common/components/shortcuts/shortcutsCatalog.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,4 +53,11 @@ export const shortcutsCatalog: ShortcutCatalogCategory[] = [
5353
{ key: '/', ctrl: true, shift: true, description: 'Shortcuts' },
5454
],
5555
},
56+
{
57+
label: 'Layout',
58+
items: [
59+
{ key: '(', ctrl: true, shift: true, description: 'Toggle left drawer' },
60+
{ key: ')', ctrl: true, shift: true, description: 'Toggle right panel' },
61+
],
62+
},
5663
] as const;

src/common/components/shortcuts/useGlobalShortcuts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export interface ShortcutDefinition {
3030

3131
export interface ShortcutObject extends ShortcutDefinition {
3232
disabled?: boolean;
33+
skipIfInput?: boolean; // skip if a text input, textarea, contenteditable (or child thereof) is focused
3334
action: (() => void) | '_specialPrintShortcuts';
3435
endDecoratorIcon?: typeof SvgIcon;
3536
level?: number; // if set, it will exclusively show icons at that level of priority and hide the others

src/common/layout/optima/OptimaLayout.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { MobileDrawer } from './drawer/MobileDrawer';
2222
import { MobilePanel } from './panel/MobilePanel';
2323
import { Modals } from './Modals';
2424
import { PageWrapper } from './PageWrapper';
25-
import { optimaActions, optimaOpenModels, optimaOpenPreferences } from './useOptima';
25+
import { optimaActions, optimaOpenModels, optimaOpenPreferences, optimaToggleDrawer, optimaTogglePanel } from './useOptima';
2626

2727

2828
// this undoes the PanelGroup styling on mobile, as it's not needed
@@ -80,6 +80,9 @@ export function OptimaLayout(props: { suspendAutoModelsSetup?: boolean, children
8080
// Shortcuts
8181
{ key: Is.OS.MacOS ? '/' : '?', ctrl: true, shift: true, action: optimaActions().openKeyboardShortcuts },
8282
{ key: 'h', ctrl: true, shift: true, action: '_specialPrintShortcuts' },
83+
// Layout
84+
{ key: '(', ctrl: true, shift: true, action: () => optimaToggleDrawer() },
85+
{ key: ')', ctrl: true, shift: true, action: () => optimaTogglePanel() },
8386
], []));
8487

8588
return <>

0 commit comments

Comments
 (0)