feat(app): add keyboard shortcut to cycle themes

This commit is contained in:
Mohamed Boudra
2026-04-10 18:50:50 +07:00
parent faf85e038c
commit 01af138939
4 changed files with 46 additions and 1 deletions
+11 -1
View File
@@ -14,7 +14,7 @@ import { BottomSheetModalProvider } from "@gorhom/bottom-sheet";
import { PortalProvider } from "@gorhom/portal"; import { PortalProvider } from "@gorhom/portal";
import { VoiceProvider } from "@/contexts/voice-context"; import { VoiceProvider } from "@/contexts/voice-context";
import { useAppSettings } from "@/hooks/use-settings"; 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 { useFaviconStatus } from "@/hooks/use-favicon-status";
import { View, Text } from "react-native"; import { View, Text } from "react-native";
import { UnistylesRuntime, useUnistyles } from "react-native-unistyles"; import { UnistylesRuntime, useUnistyles } from "react-native-unistyles";
@@ -358,6 +358,8 @@ interface AppContainerProps {
chromeEnabled?: boolean; chromeEnabled?: boolean;
} }
const THEME_CYCLE_ORDER: ThemeName[] = ["dark", "zinc", "midnight", "claude", "ghostty", "light"];
function AppContainer({ function AppContainer({
children, children,
selectedAgentId, selectedAgentId,
@@ -365,6 +367,7 @@ function AppContainer({
}: AppContainerProps) { }: AppContainerProps) {
const { theme } = useUnistyles(); const { theme } = useUnistyles();
const daemons = useHosts(); const daemons = useHosts();
const { settings, updateSettings } = useAppSettings();
const toggleAgentList = usePanelStore((state) => state.toggleAgentList); const toggleAgentList = usePanelStore((state) => state.toggleAgentList);
const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer); const toggleFileExplorer = usePanelStore((state) => state.toggleFileExplorer);
const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars); const toggleBothSidebars = usePanelStore((state) => state.toggleBothSidebars);
@@ -373,6 +376,12 @@ function AppContainer({
const agentListOpen = usePanelStore((state) => state.desktop.agentListOpen); const agentListOpen = usePanelStore((state) => state.desktop.agentListOpen);
const sidebarWidth = usePanelStore((state) => state.sidebarWidth); 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 isCompactLayout = useIsCompactFormFactor();
const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0; const chromeEnabled = chromeEnabledOverride ?? daemons.length > 0;
@@ -413,6 +422,7 @@ function AppContainer({
toggleFileExplorer, toggleFileExplorer,
toggleBothSidebars, toggleBothSidebars,
toggleFocusMode, toggleFocusMode,
cycleTheme,
}); });
const containerStyle = useMemo( const containerStyle = useMemo(
@@ -35,6 +35,7 @@ export function useKeyboardShortcuts({
toggleFileExplorer, toggleFileExplorer,
toggleBothSidebars, toggleBothSidebars,
toggleFocusMode, toggleFocusMode,
cycleTheme,
}: { }: {
enabled: boolean; enabled: boolean;
isMobile: boolean; isMobile: boolean;
@@ -43,6 +44,7 @@ export function useKeyboardShortcuts({
toggleFileExplorer?: () => void; toggleFileExplorer?: () => void;
toggleBothSidebars?: () => void; toggleBothSidebars?: () => void;
toggleFocusMode?: () => void; toggleFocusMode?: () => void;
cycleTheme?: () => void;
}) { }) {
const pathname = usePathname(); const pathname = usePathname();
const hosts = useHosts(); const hosts = useHosts();
@@ -267,6 +269,11 @@ export function useKeyboardShortcuts({
toggleFocusMode(); toggleFocusMode();
} }
return true; return true;
case "theme.cycle":
if (cycleTheme) {
cycleTheme();
}
return true;
case "command-center.toggle": { case "command-center.toggle": {
const store = useKeyboardShortcutsStore.getState(); const store = useKeyboardShortcutsStore.getState();
if (!store.commandCenterOpen) { if (!store.commandCenterOpen) {
@@ -413,6 +420,7 @@ export function useKeyboardShortcuts({
}; };
}, [ }, [
bindings, bindings,
cycleTheme,
enabled, enabled,
isMobile, isMobile,
openProjectPickerAction, openProjectPickerAction,
+1
View File
@@ -43,6 +43,7 @@ export type KeyboardActionId =
| "worktree.new" | "worktree.new"
| "worktree.archive" | "worktree.archive"
| "view.toggle.focus" | "view.toggle.focus"
| "theme.cycle"
| "message-input.action"; | "message-input.action";
export type KeyboardShortcutPayload = export type KeyboardShortcutPayload =
@@ -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 --- // --- Message input ---
{ {
id: "message-input-voice-toggle-cmd-shift-d-mac", id: "message-input-voice-toggle-cmd-shift-d-mac",