({
vimMode,
overrides,
onSetBinding,
onResetAll
}: {
vimMode: boolean
overrides: KeymapOverrides
onSetBinding: (id: KeymapId, binding: string | null) => void
onResetAll: () => void
})
| 3497 | } |
| 3498 | |
| 3499 | function KeymapSettings({ |
| 3500 | vimMode, |
| 3501 | overrides, |
| 3502 | onSetBinding, |
| 3503 | onResetAll |
| 3504 | }: { |
| 3505 | vimMode: boolean |
| 3506 | overrides: KeymapOverrides |
| 3507 | onSetBinding: (id: KeymapId, binding: string | null) => void |
| 3508 | onResetAll: () => void |
| 3509 | }): JSX.Element { |
| 3510 | const [query, setQuery] = useState('') |
| 3511 | const [recording, setRecording] = useState<KeymapDefinition | null>(null) |
| 3512 | |
| 3513 | const groups = useMemo(() => { |
| 3514 | const q = query.trim().toLowerCase() |
| 3515 | return getKeymapDefinitionsByGroup() |
| 3516 | .map((group) => { |
| 3517 | const items = group.items.filter((definition) => { |
| 3518 | if (definition.vimOnly && !vimMode && definition.id !== 'global.searchNotesNonVim') { |
| 3519 | // Keep Vim-only bindings visible so users can prep their layout |
| 3520 | // before turning Vim mode back on, but still let the filter work. |
| 3521 | } |
| 3522 | if (!q) return true |
| 3523 | return ( |
| 3524 | definition.title.toLowerCase().includes(q) || |
| 3525 | definition.description.toLowerCase().includes(q) || |
| 3526 | getKeymapDisplay(overrides, definition.id).toLowerCase().includes(q) |
| 3527 | ) |
| 3528 | }) |
| 3529 | return items.length > 0 ? { ...group, items } : null |
| 3530 | }) |
| 3531 | .filter((group): group is ReturnType<typeof getKeymapDefinitionsByGroup>[number] => !!group) |
| 3532 | }, [overrides, query, vimMode]) |
| 3533 | |
| 3534 | const hasOverrides = Object.keys(overrides).length > 0 |
| 3535 | |
| 3536 | return ( |
| 3537 | <div className="flex h-full min-h-0 flex-col"> |
| 3538 | <div className="flex min-h-0 flex-1 flex-col rounded-3xl border border-paper-300/60 bg-paper-50/45 shadow-[0_14px_36px_rgba(15,23,42,0.04)]"> |
| 3539 | <div className="sticky top-0 z-10 rounded-t-[22px] border-b border-paper-300/55 bg-paper-50/95 px-5 py-4 backdrop-blur"> |
| 3540 | <div className="flex flex-wrap items-center justify-between gap-3"> |
| 3541 | <div className="min-w-0"> |
| 3542 | <div className="text-sm font-medium text-ink-900">Shortcut editor</div> |
| 3543 | <div className="mt-1 text-xs leading-5 text-ink-500"> |
| 3544 | Record a new key or sequence for the app’s keyboard-first actions. Standard |
| 3545 | accessibility fallbacks like arrows, Enter, and Escape still work. |
| 3546 | </div> |
| 3547 | </div> |
| 3548 | <div className="flex items-center gap-2"> |
| 3549 | <input |
| 3550 | value={query} |
| 3551 | onChange={(e) => setQuery(e.target.value)} |
| 3552 | placeholder="Filter keymaps…" |
| 3553 | className="w-72 rounded-xl border border-paper-300/70 bg-paper-100/80 px-4 py-2.5 text-sm text-ink-900 outline-none placeholder:text-ink-400 focus:border-accent/45" |
| 3554 | /> |
| 3555 | <button |
| 3556 | type="button" |
nothing calls this directly
no test coverage detected