ShortcutBadge.tsx 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { Fragment } from 'react'
  2. import { cn, KeyboardShortcut } from 'ui'
  3. import { hotkeyToKeys } from '@/state/shortcuts/formatShortcut'
  4. import { SHORTCUT_DEFINITIONS, type ShortcutId } from '@/state/shortcuts/registry'
  5. interface ShortcutBadgeProps {
  6. shortcutId: ShortcutId
  7. className?: string
  8. /** `'inline'` (default) is flat text; `'pill'` is a boxed badge. */
  9. variant?: 'inline' | 'pill'
  10. }
  11. /**
  12. * Inline display of the keybind for a registered shortcut. Useful inside
  13. * menu items, buttons, or rows where the label already exists elsewhere and
  14. * you just want to surface the keybind itself (no tooltip / hover).
  15. *
  16. * For multi-step sequences (e.g. `['G', 'T']`), each step is separated by the
  17. * word "then".
  18. *
  19. * @example
  20. * <DropdownMenuItem>
  21. * <p>Copy as CSV</p>
  22. * <ShortcutBadge shortcutId={SHORTCUT_IDS.RESULTS_COPY_CSV} className="ml-auto" />
  23. * </DropdownMenuItem>
  24. */
  25. export const ShortcutBadge = ({
  26. shortcutId,
  27. className,
  28. variant = 'inline',
  29. }: ShortcutBadgeProps) => {
  30. const def = SHORTCUT_DEFINITIONS[shortcutId]
  31. return (
  32. <span className={cn('flex items-center gap-1', className)}>
  33. {def.sequence.map((step, i) => (
  34. <Fragment key={i}>
  35. {i > 0 && <span className="text-foreground-lighter text-[11px]">then</span>}
  36. <KeyboardShortcut keys={hotkeyToKeys(step)} variant={variant} />
  37. </Fragment>
  38. ))}
  39. </span>
  40. )
  41. }