From 01af1389392d110fabaf4567fee3fa2dae18fde3 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Fri, 10 Apr 2026 18:50:50 +0700 Subject: [PATCH] feat(app): add keyboard shortcut to cycle themes --- packages/app/src/app/_layout.tsx | 12 ++++++++- .../app/src/hooks/use-keyboard-shortcuts.ts | 8 ++++++ packages/app/src/keyboard/actions.ts | 1 + .../app/src/keyboard/keyboard-shortcuts.ts | 26 +++++++++++++++++++ 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/packages/app/src/app/_layout.tsx b/packages/app/src/app/_layout.tsx index e1b41b450..da1cdec90 100644 --- a/packages/app/src/app/_layout.tsx +++ b/packages/app/src/app/_layout.tsx @@ -14,7 +14,7 @@ import { BottomSheetModalProvider } from "@gorhom/bottom-sheet"; import { PortalProvider } from "@gorhom/portal"; import { VoiceProvider } from "@/contexts/voice-context"; import { useAppSettings } from "@/hooks/use-settings"; -import { THEME_TO_UNISTYLES } from "@/styles/theme"; +import { THEME_TO_UNISTYLES, type ThemeName } from "@/styles/theme"; import { useFaviconStatus } from "@/hooks/use-favicon-status"; import { View, Text } from "react-native"; import { UnistylesRuntime, useUnistyles } from "react-native-unistyles"; @@ -358,6 +358,8 @@ interface AppContainerProps { chromeEnabled?: boolean; } +const THEME_CYCLE_ORDER: ThemeName[] = ["dark", "zinc", "midnight", "claude", "ghostty", "light"]; + function AppContainer({ children, selectedAgentId, @@ -365,6 +367,7 @@ function AppContainer({ }: AppContainerProps) { const { theme } = useUnistyles(); const daemons = useHosts(); + const { settings, updateSettings } = useAppSettings(); const toggleAgentList = usePanelStore((state) => state.toggleAgentList); const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer); const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars); @@ -373,6 +376,12 @@ function AppContainer({ const agentListOpen = usePanelStore((state) => state.desktop.agentListOpen); const sidebarWidth = usePanelStore((state) => state.sidebarWidth); + const cycleTheme = useCallback(() => { + const currentIndex = THEME_CYCLE_ORDER.indexOf(settings.theme as ThemeName); + const nextIndex = (currentIndex + 1) % THEME_CYCLE_ORDER.length; + void updateSettings({ theme: THEME_CYCLE_ORDER[nextIndex]! }); + }, [settings.theme, updateSettings]); + const isCompactLayout = useIsCompactFormFactor(); const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0; @@ -413,6 +422,7 @@ function AppContainer({ toggleFileExplorer, toggleBothSidebars, toggleFocusMode, + cycleTheme, }); const containerStyle = useMemo( diff --git a/packages/app/src/hooks/use-keyboard-shortcuts.ts b/packages/app/src/hooks/use-keyboard-shortcuts.ts index edbc739f1..4ec95766f 100644 --- a/packages/app/src/hooks/use-keyboard-shortcuts.ts +++ b/packages/app/src/hooks/use-keyboard-shortcuts.ts @@ -35,6 +35,7 @@ export function useKeyboardShortcuts({ toggleFileExplorer, toggleBothSidebars, toggleFocusMode, + cycleTheme, }: { enabled: boolean; isMobile: boolean; @@ -43,6 +44,7 @@ export function useKeyboardShortcuts({ toggleFileExplorer?: () => void; toggleBothSidebars?: () => void; toggleFocusMode?: () => void; + cycleTheme?: () => void; }) { const pathname = usePathname(); const hosts = useHosts(); @@ -267,6 +269,11 @@ export function useKeyboardShortcuts({ toggleFocusMode(); } return true; + case "theme.cycle": + if (cycleTheme) { + cycleTheme(); + } + return true; case "command-center.toggle": { const store = useKeyboardShortcutsStore.getState(); if (!store.commandCenterOpen) { @@ -413,6 +420,7 @@ export function useKeyboardShortcuts({ }; }, [ bindings, + cycleTheme, enabled, isMobile, openProjectPickerAction, diff --git a/packages/app/src/keyboard/actions.ts b/packages/app/src/keyboard/actions.ts index e9b8af965..dd0816712 100644 --- a/packages/app/src/keyboard/actions.ts +++ b/packages/app/src/keyboard/actions.ts @@ -43,6 +43,7 @@ export type KeyboardActionId = | "worktree.new" | "worktree.archive" | "view.toggle.focus" + | "theme.cycle" | "message-input.action"; export type KeyboardShortcutPayload = diff --git a/packages/app/src/keyboard/keyboard-shortcuts.ts b/packages/app/src/keyboard/keyboard-shortcuts.ts index bc9b65122..5d9cfcfab 100644 --- a/packages/app/src/keyboard/keyboard-shortcuts.ts +++ b/packages/app/src/keyboard/keyboard-shortcuts.ts @@ -744,6 +744,32 @@ const SHORTCUT_BINDINGS: readonly ShortcutBinding[] = [ }, }, + // --- Theme cycling --- + { + id: "theme-cycle-cmd-shift-t-mac", + action: "theme.cycle", + combo: "Cmd+Alt+T", + when: { mac: true, commandCenter: false }, + help: { + id: "cycle-theme", + section: "panels", + label: "Cycle theme", + keys: ["mod", "alt", "T"], + }, + }, + { + id: "theme-cycle-ctrl-alt-t-non-mac", + action: "theme.cycle", + combo: "Ctrl+Alt+T", + when: { mac: false, commandCenter: false, terminal: false }, + help: { + id: "cycle-theme", + section: "panels", + label: "Cycle theme", + keys: ["mod", "alt", "T"], + }, + }, + // --- Message input --- { id: "message-input-voice-toggle-cmd-shift-d-mac",