feat(desktop): rebindable keyboard shortcuts panel
Add a central keybind registry + nanostore so desktop hotkeys are discoverable and user-rebindable. A titlebar ⌨ button (and ⌘/) opens a collapsible map grouped by Composer (read-only) / Profiles / Session / Navigation / View; click any chip to capture a new combo. Overrides persist to localStorage as a delta against shipped defaults, so future default changes aren't shadowed by a stored snapshot. Migrates the previously scattered inline listeners (palette, command center, new session, sidebar, theme) into the registry, and adds profile switch/cycle/create + default-profile hotkeys.
This commit is contained in:
@@ -5,7 +5,7 @@ import { useI18n } from '@/i18n'
|
||||
import { COMPLETION_DRAWER_CLASS } from './completion-drawer'
|
||||
|
||||
const COMMON_COMMAND_KEYS = ['/help', '/clear', '/resume', '/details', '/copy', '/quit']
|
||||
const HOTKEY_KEYS = ['@', '/', '?', 'Enter', 'Cmd/Ctrl+K', 'Cmd/Ctrl+L', 'Esc', '↑ / ↓']
|
||||
const HOTKEY_KEYS = ['@', '/', '?', 'Enter', 'Cmd/Ctrl+Shift+K', 'Cmd/Ctrl+/', 'Esc', '↑ / ↓']
|
||||
|
||||
export function HelpHint() {
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -34,6 +34,7 @@ import { cn } from '@/lib/utils'
|
||||
import {
|
||||
$activeGatewayProfile,
|
||||
$profileColors,
|
||||
$profileCreateRequest,
|
||||
$profileOrder,
|
||||
$profiles,
|
||||
$profileScope,
|
||||
@@ -178,6 +179,20 @@ export function ProfileRail() {
|
||||
void refreshActiveProfile()
|
||||
}, [])
|
||||
|
||||
// Open the create dialog when the `profile.create` hotkey fires (the dialog
|
||||
// state lives here, so the global keybind bumps a request atom we watch).
|
||||
const createRequest = useStore($profileCreateRequest)
|
||||
const lastCreateRef = useRef(createRequest)
|
||||
|
||||
useEffect(() => {
|
||||
if (createRequest === lastCreateRef.current) {
|
||||
return
|
||||
}
|
||||
|
||||
lastCreateRef.current = createRequest
|
||||
setCreateOpen(true)
|
||||
}, [createRequest])
|
||||
|
||||
return (
|
||||
<div aria-label="Profiles" className="flex items-center gap-0.5" role="tablist">
|
||||
{/* One button toggles default ↔ all: home face when scoped to a profile,
|
||||
@@ -199,7 +214,12 @@ export function ProfileRail() {
|
||||
|
||||
{/* Single-profile: the active default's home icon next to the create +. */}
|
||||
{!multiProfile && defaultProfile && (
|
||||
<ProfilePill active glyph="home" label={defaultProfile.name} onSelect={() => selectProfile(defaultProfile.name)} />
|
||||
<ProfilePill
|
||||
active
|
||||
glyph="home"
|
||||
label={defaultProfile.name}
|
||||
onSelect={() => selectProfile(defaultProfile.name)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user