Add keyboard shortcut rebinding with string-based format and sectioned settings UI

- Parse/format shortcut strings ("Cmd+Shift+O") bidirectionally via shortcut-string.ts
- Convert all 60+ bindings from structured KeyCombo objects to declarative strings
- Add keyboard shortcut overrides storage (AsyncStorage + React Query)
- Wire overrides into the keyboard shortcut resolution pipeline
- Add sectioned settings layout with sidebar on desktop, single scroll on mobile
- Add keyboard shortcuts settings section with rebind/reset UI and key capture
- Create useShortcutKeys hook so tooltip shortcut displays update on rebind
- Replace hardcoded shortcut displays in agent-input-area, left-sidebar, command center
This commit is contained in:
Mohamed Boudra
2026-03-21 23:14:59 +07:00
parent 68ab7b81a1
commit ad1cb4c200
10 changed files with 1607 additions and 612 deletions
@@ -1,4 +1,4 @@
import { useEffect } from "react";
import { useEffect, useMemo } from "react";
import { Platform } from "react-native";
import { usePathname } from "expo-router";
import { getIsDesktop } from "@/constants/layout";
@@ -17,10 +17,11 @@ import {
} from "@/keyboard/actions";
import { canToggleFileExplorerShortcut } from "@/keyboard/keyboard-shortcut-routing";
import { keyboardActionDispatcher } from "@/keyboard/keyboard-action-dispatcher";
import { resolveKeyboardShortcut } from "@/keyboard/keyboard-shortcuts";
import { resolveKeyboardShortcut, buildEffectiveBindings } from "@/keyboard/keyboard-shortcuts";
import { resolveKeyboardFocusScope } from "@/keyboard/focus-scope";
import { getShortcutOs } from "@/utils/shortcut-platform";
import { useOpenProjectPicker } from "@/hooks/use-open-project-picker";
import { useKeyboardShortcutOverrides } from "@/hooks/use-keyboard-shortcut-overrides";
export function useKeyboardShortcuts({
enabled,
@@ -38,6 +39,8 @@ export function useKeyboardShortcuts({
const pathname = usePathname();
const hosts = useHosts();
const resetModifiers = useKeyboardShortcutsStore((s) => s.resetModifiers);
const { overrides } = useKeyboardShortcutOverrides();
const bindings = useMemo(() => buildEffectiveBindings(overrides), [overrides]);
const activeServerIdFromPath = parseServerIdFromPathname(pathname);
const activeServerId =
hosts.find((host) => host.serverId === activeServerIdFromPath)?.serverId ??
@@ -285,6 +288,7 @@ export function useKeyboardShortcuts({
toggleFileExplorer,
}),
},
bindings,
});
if (!match) {
return;
@@ -332,6 +336,7 @@ export function useKeyboardShortcuts({
document.removeEventListener("visibilitychange", handleBlurOrHide);
};
}, [
bindings,
enabled,
isMobile,
openProjectPickerAction,