diff --git a/apps/desktop/src/components/main/body/index.tsx b/apps/desktop/src/components/main/body/index.tsx index 881c3c583c..70d2229c25 100644 --- a/apps/desktop/src/components/main/body/index.tsx +++ b/apps/desktop/src/components/main/body/index.tsx @@ -614,12 +614,22 @@ function useScrollActiveTabIntoView(tabs: Tab[]) { } function useTabsShortcuts() { - const { tabs, currentTab, close, select, restoreLastClosedTab } = useTabs( + const { + tabs, + currentTab, + close, + select, + selectNext, + selectPrev, + restoreLastClosedTab, + } = useTabs( useShallow((state) => ({ tabs: state.tabs, currentTab: state.currentTab, close: state.close, select: state.select, + selectNext: state.selectNext, + selectPrev: state.selectPrev, restoreLastClosedTab: state.restoreLastClosedTab, })), ); @@ -689,6 +699,28 @@ function useTabsShortcuts() { [tabs, select], ); + useHotkeys( + "mod+alt+left", + () => selectPrev(), + { + preventDefault: true, + enableOnFormTags: true, + enableOnContentEditable: true, + }, + [selectPrev], + ); + + useHotkeys( + "mod+alt+right", + () => selectNext(), + { + preventDefault: true, + enableOnFormTags: true, + enableOnContentEditable: true, + }, + [selectNext], + ); + useHotkeys( "mod+shift+t", () => restoreLastClosedTab(), diff --git a/apps/desktop/src/store/zustand/tabs/basic.ts b/apps/desktop/src/store/zustand/tabs/basic.ts index 306b5ffe2e..20652c79ce 100644 --- a/apps/desktop/src/store/zustand/tabs/basic.ts +++ b/apps/desktop/src/store/zustand/tabs/basic.ts @@ -15,6 +15,8 @@ export type BasicActions = { openCurrent: (tab: TabInput) => void; openNew: (tab: TabInput) => void; select: (tab: Tab) => void; + selectNext: () => void; + selectPrev: () => void; close: (tab: Tab) => void; reorder: (tabs: Tab[]) => void; closeOthers: (tab: Tab) => void; @@ -43,6 +45,34 @@ export const createBasicSlice = < const currentTab = nextTabs.find((t) => t.active) || null; set({ tabs: nextTabs, currentTab } as Partial); }, + selectNext: () => { + const { tabs, currentTab } = get(); + if (tabs.length === 0 || !currentTab) return; + + const currentIndex = tabs.findIndex((t) => isSameTab(t, currentTab)); + const nextIndex = (currentIndex + 1) % tabs.length; + const nextTab = tabs[nextIndex]; + + const nextTabs = setActiveFlags(tabs, nextTab); + set({ + tabs: nextTabs, + currentTab: { ...nextTab, active: true }, + } as Partial); + }, + selectPrev: () => { + const { tabs, currentTab } = get(); + if (tabs.length === 0 || !currentTab) return; + + const currentIndex = tabs.findIndex((t) => isSameTab(t, currentTab)); + const prevIndex = (currentIndex - 1 + tabs.length) % tabs.length; + const prevTab = tabs[prevIndex]; + + const nextTabs = setActiveFlags(tabs, prevTab); + set({ + tabs: nextTabs, + currentTab: { ...prevTab, active: true }, + } as Partial); + }, close: (tab) => { const { tabs, history, canClose } = get(); const tabToClose = tabs.find((t) => isSameTab(t, tab));