// Every key the app answers to, generated from src/keys/bindings.ts rather than written out here. // That is the point of the table over there: a binding that exists is a binding this sheet shows, // so the two cannot drift and there is no list to remember to update. import { useEffect, useState } from "react"; import { useEscapeLayer } from "../escape"; import { BINDINGS, GROUPS, bindingLabel, keyLabel } from "../keys/bindings"; import { commandLabel, onCommand } from "../keys/commands"; import { useKeyContext } from "../keys/keymap"; import { Icon } from "./Icon"; export function Shortcuts() { const [open, setOpen] = useState(false); useEffect(() => onCommand("shortcuts", () => setOpen((v) => !v)), []); useEscapeLayer(open, () => setOpen(false)); useKeyContext("overlay", open); if (!open) return null; return (
setOpen(false)}>
e.stopPropagation()} >

Keyboard shortcuts

{GROUPS.map((group) => { const rows = BINDINGS.filter((binding) => binding.group === group); if (!rows.length) return null; return (
{group}
    {rows.map((binding) => (
  • {bindingLabel(binding, commandLabel)} {binding.keys.map((combo) => ( {keyLabel(combo)} ))}
  • ))}
); })}
); }