@@ -53,102 +65,24 @@ const Section: React.FC<{ title: string; children: React.ReactNode }> = ({ title
);
-/* ─── Platform-aware key names ─── */
-
-const enter = isMac ? '⏎' : '↵';
-
-/* ─── Shortcut data ─── */
-
-interface Shortcut {
- keys: string[];
- desc: string;
- hint?: string;
-}
-
-interface ShortcutSection {
- title: string;
- shortcuts: Shortcut[];
-}
-
-const planShortcuts: ShortcutSection[] = [
- {
- title: 'Actions',
- shortcuts: [
- { keys: [modKey, enter], desc: 'Submit / Approve' },
- { keys: [modKey, 'S'], desc: 'Save to notes app' },
- { keys: ['Esc'], desc: 'Close dialog' },
- ],
- },
- {
- title: 'Input Method',
- shortcuts: [
- { keys: [altKey, 'hold'], desc: 'Temporarily switch mode', hint: 'Hold to switch between Select and Pinpoint, release to revert' },
- { keys: [altKey, altKey], desc: 'Toggle mode', hint: 'Double-tap to permanently switch between Select and Pinpoint' },
- ],
- },
- {
- title: 'Annotations',
- shortcuts: [
- { keys: ['a-z'], desc: 'Start typing comment', hint: 'When the annotation toolbar is open, any letter key opens the comment editor with that character' },
- { keys: [altKey, '1-0'], desc: 'Apply quick label', hint: 'Instantly applies the Nth preset label (0 = 10th). When the label picker is open, bare digits also work.' },
- { keys: [modKey, enter], desc: 'Submit comment' },
- { keys: [modKey, 'C'], desc: 'Copy selected text' },
- { keys: ['Esc'], desc: 'Close toolbar / Cancel' },
- ],
- },
- {
- title: 'Image Annotator',
- shortcuts: [
- { keys: ['1'], desc: 'Pen tool' },
- { keys: ['2'], desc: 'Arrow tool' },
- { keys: ['3'], desc: 'Circle tool' },
- { keys: [modKey, 'Z'], desc: 'Undo' },
- { keys: [enter], desc: 'Finish' },
- { keys: ['Esc'], desc: 'Cancel' },
- ],
- },
-];
-
-const reviewShortcuts: ShortcutSection[] = [
- {
- title: 'Actions',
- shortcuts: [
- { keys: [modKey, enter], desc: 'Approve / Send feedback' },
- { keys: [altKey, altKey], desc: 'Toggle destination', hint: 'Double-tap to switch between GitHub and Agent in PR review mode' },
- { keys: [modKey, '⇧', 'C'], desc: 'Toggle comment mode' },
- { keys: ['Esc'], desc: 'Collapse sidebar' },
- ],
- },
- {
- title: 'File Navigation',
- shortcuts: [
- { keys: ['J'], desc: 'Next file' },
- { keys: ['K'], desc: 'Previous file' },
- { keys: ['Home'], desc: 'First file' },
- { keys: ['End'], desc: 'Last file' },
- ],
- },
- {
- title: 'Annotations',
- shortcuts: [
- { keys: [modKey, enter], desc: 'Submit comment' },
- { keys: ['Tab'], desc: 'Indent in editor' },
- { keys: ['Esc'], desc: 'Close toolbar / Cancel' },
- ],
- },
-];
-
-/* ─── Exported panel ─── */
+export const KeyboardShortcuts: React.FC<{ shortcutRegistry: ShortcutRegistry }> = ({ shortcutRegistry }) => {
+ const sections = listRegistryShortcutSections(shortcutRegistry);
-export const KeyboardShortcuts: React.FC<{ mode: 'plan' | 'review' }> = ({ mode }) => {
- const sections = mode === 'review' ? reviewShortcuts : planShortcuts;
+ if (sections.length === 0) {
+ return
No shortcuts are available in this view.
;
+ }
return (
{sections.map((section) => (
- {section.shortcuts.map((s, i) => (
-
+ {section.shortcuts.map((shortcut) => (
+
))}
))}
diff --git a/packages/ui/components/Settings.tsx b/packages/ui/components/Settings.tsx
index f123d79b..761891ad 100644
--- a/packages/ui/components/Settings.tsx
+++ b/packages/ui/components/Settings.tsx
@@ -53,10 +53,10 @@ import {
} from '../utils/defaultNotesApp';
import { useAgents } from '../hooks/useAgents';
import { KeyboardShortcuts } from './KeyboardShortcuts';
+import { annotationToolbarShortcuts, formatShortcutBindingText, getShortcutPlatform, type ShortcutRegistry } from '../shortcuts';
import { type QuickLabel, getQuickLabels, saveQuickLabels, resetQuickLabels, DEFAULT_QUICK_LABELS, getLabelColors, LABEL_COLOR_MAP } from '../utils/quickLabels';
import { hasNewSettings, markNewSettingsSeen } from '../utils/newSettingsHint';
import { ThemeTab } from './ThemeTab';
-import { isMac, modKey, altKey } from '../utils/platform';
import { getAIProviderSettings } from '../utils/aiProvider';
import { AISettingsTab } from './AISettingsTab';
import {
@@ -72,6 +72,7 @@ interface SettingsProps {
onTaterModeChange: (enabled: boolean) => void;
onIdentityChange?: (oldIdentity: string, newIdentity: string) => void;
origin?: 'claude-code' | 'opencode' | 'pi' | 'codex' | null;
+ shortcutRegistry: ShortcutRegistry;
/** Mode determines which settings are shown. 'plan' shows all, 'review' shows only identity + agent switching */
mode?: 'plan' | 'review';
onUIPreferencesChange?: (prefs: UIPreferences) => void;
@@ -82,7 +83,7 @@ interface SettingsProps {
aiProviders?: Array<{ id: string; name: string; capabilities: Record
}>;
}
-export const Settings: React.FC = ({ taterMode, onTaterModeChange, onIdentityChange, origin, mode = 'plan', onUIPreferencesChange, externalOpen, onExternalClose, aiProviders = [] }) => {
+export const Settings: React.FC = ({ taterMode, onTaterModeChange, onIdentityChange, origin, shortcutRegistry, mode = 'plan', onUIPreferencesChange, externalOpen, onExternalClose, aiProviders = [] }) => {
const [showDialog, setShowDialog] = useState(false);
const [activeTab, setActiveTab] = useState('general');
const [identity, setIdentity] = useState('');
@@ -109,6 +110,8 @@ export const Settings: React.FC = ({ taterMode, onTaterModeChange
const [aiProvider, setAiProvider] = useState(null);
const [fileBrowserSettings, setFileBrowserSettings] = useState({ enabled: false, directories: [] });
const [newDirPath, setNewDirPath] = useState('');
+ const shortcutPlatform = getShortcutPlatform();
+
// Fetch available agents for OpenCode
const { agents: availableAgents, validateAgent, getAgentWarning } = useAgents(origin ?? null);
@@ -794,7 +797,7 @@ export const Settings: React.FC = ({ taterMode, onTaterModeChange
Default Save Action
- Used for keyboard shortcut ({modKey}+S)
+ Used for keyboard shortcut ({formatShortcutBindingText('Mod+S', shortcutPlatform)})
= ({ taterMode, onTaterModeChange
{defaultNotesApp === 'ask'
? 'Opens Export dialog with Notes tab'
: defaultNotesApp === 'download'
- ? `${modKey}+S downloads the annotations file`
- : `${modKey}+S saves directly to ${{ obsidian: 'Obsidian', bear: 'Bear', octarine: 'Octarine' }[defaultNotesApp] ?? defaultNotesApp}`}
+ ? `${formatShortcutBindingText('Mod+S', shortcutPlatform)} downloads the annotations file`
+ : `${formatShortcutBindingText('Mod+S', shortcutPlatform)} saves directly to ${{ obsidian: 'Obsidian', bear: 'Bear', octarine: 'Octarine' }[defaultNotesApp] ?? defaultNotesApp}`}
@@ -960,8 +963,8 @@ export const Settings: React.FC