From e13011bbbdfa5df39e06cf9cb244467df57e9d71 Mon Sep 17 00:00:00 2001 From: Aleksander Grygier Date: Fri, 21 Aug 2026 15:14:08 +0200 Subject: [PATCH] chat : add keyboard shortcut to jump between conversation tabs Shift+Cmd/Ctrl+Left/Right cycles the open tabs, mirroring the existing Shift+Cmd/Ctrl+Up/Down conversation navigation. Assisted-by: pi --- .../hooks/use-keyboard-shortcuts.svelte.ts | 12 +++++++++ tools/ui/src/routes/+layout.svelte | 25 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tools/ui/src/lib/hooks/use-keyboard-shortcuts.svelte.ts b/tools/ui/src/lib/hooks/use-keyboard-shortcuts.svelte.ts index eb67b378d8..2a99e962de 100644 --- a/tools/ui/src/lib/hooks/use-keyboard-shortcuts.svelte.ts +++ b/tools/ui/src/lib/hooks/use-keyboard-shortcuts.svelte.ts @@ -9,6 +9,8 @@ interface KeyboardShortcutsCallbacks { deleteActiveConversation?: () => void; navigateToPrevConversation?: () => void; navigateToNextConversation?: () => void; + navigateToPrevTab?: () => void; + navigateToNextTab?: () => void; toggleSidebar?: () => void; } @@ -82,6 +84,16 @@ export function useKeyboardShortcuts(callbacks: KeyboardShortcutsCallbacks) { event.preventDefault(); callbacks.navigateToNextConversation?.(); } + + if (isCmdOrCtrl && event.shiftKey && event.key === KeyboardKey.ARROW_LEFT) { + event.preventDefault(); + callbacks.navigateToPrevTab?.(); + } + + if (isCmdOrCtrl && event.shiftKey && event.key === KeyboardKey.ARROW_RIGHT) { + event.preventDefault(); + callbacks.navigateToNextTab?.(); + } } return { handleKeydown }; diff --git a/tools/ui/src/routes/+layout.svelte b/tools/ui/src/routes/+layout.svelte index 6d301accbf..46e51cd41b 100644 --- a/tools/ui/src/routes/+layout.svelte +++ b/tools/ui/src/routes/+layout.svelte @@ -76,6 +76,27 @@ } } + function navigateToTab(direction: -1 | 1) { + // only makes sense with conversation tabs enabled + if (!settingsStore.config.conversationTabs) return; + + const openTabs = tabsStore.openTabs; + + if (openTabs.length === 0) return; + + const activeId = page.params.id ?? NEW_CHAT_TAB_ID; + const idx = openTabs.indexOf(activeId); + // active tab not in list (e.g. a non-chat route): start from an edge + const targetIdx = + idx === -1 + ? direction === 1 + ? 0 + : openTabs.length - 1 + : (idx + direction + openTabs.length) % openTabs.length; + + void tabsStore.activate(openTabs[targetIdx]); + } + function navigateToConversation(direction: -1 | 1) { const allConvs = conversationsStore.conversations; @@ -120,7 +141,9 @@ const { handleKeydown } = useKeyboardShortcuts({ editActiveConversation: () => chatSidebar?.editActiveConversation?.(), navigateToNextConversation: () => navigateToConversation(1), - navigateToPrevConversation: () => navigateToConversation(-1) + navigateToNextTab: () => navigateToTab(1), + navigateToPrevConversation: () => navigateToConversation(-1), + navigateToPrevTab: () => navigateToTab(-1) }); function checkApiKey() {