All files / src/components/panels KeyboardShortcutsPanel.tsx

100% Statements 5/5
100% Branches 0/0
100% Functions 4/4
100% Lines 5/5

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107                                          3x                                                                                                               6x               36x       126x     132x                            
import type { JSX } from "react";
import styles from "./SettingsPanel.module.scss";
import shortcutStyles from "./KeyboardShortcutsPanel.module.scss";
 
/** A single keyboard shortcut definition. */
interface Shortcut {
  /** Key combination displayed as kbd badges (e.g. ["?"], ["Ctrl", "/"]). */
  keys: string[];
  /** Human-readable description of the action. */
  description: string;
}
 
/** A named group of related shortcuts. */
interface ShortcutGroup {
  /** Section heading. */
  title: string;
  /** Shortcuts in this group. */
  shortcuts: Shortcut[];
}
 
/** Static shortcut data — all shortcuts documented in the app. */
const SHORTCUT_GROUPS: ShortcutGroup[] = [
  {
    title: "Global",
    shortcuts: [
      { keys: ["?"], description: "Open keyboard shortcuts reference" },
      { keys: ["N"], description: "Create a new task" },
      { keys: ["Escape"], description: "Close dialog or cancel editing" },
    ],
  },
  {
    title: "Task Page",
    shortcuts: [
      { keys: ["1"], description: "Switch to Overview tab" },
      { keys: ["2"], description: "Switch to Stream tab" },
    ],
  },
  {
    title: "Workspace Page",
    shortcuts: [
      { keys: ["1"], description: "Switch to Graph view" },
      { keys: ["2"], description: "Switch to Board view" },
      { keys: ["3"], description: "Switch to Tasks view" },
    ],
  },
  {
    title: "Navigation Lists",
    shortcuts: [
      { keys: ["\u2190"], description: "Previous tab (horizontal nav)" },
      { keys: ["\u2192"], description: "Next tab (horizontal nav)" },
      { keys: ["\u2191"], description: "Previous item (vertical nav)" },
      { keys: ["\u2193"], description: "Next item (vertical nav)" },
      { keys: ["J"], description: "Next item (alias for arrow down/right)" },
      { keys: ["K"], description: "Previous item (alias for arrow up/left)" },
      { keys: ["Home"], description: "Jump to first item" },
      { keys: ["End"], description: "Jump to last item" },
    ],
  },
  {
    title: "Editing",
    shortcuts: [
      { keys: ["Enter"], description: "Activate / save inline edit" },
      { keys: ["Space"], description: "Activate button or start editing" },
      { keys: ["Escape"], description: "Cancel edit and discard changes" },
    ],
  },
  {
    title: "Root",
    shortcuts: [
      { keys: ["Ctrl/Cmd", "Enter"], description: "Send message (when the composer is focused)" },
      { keys: ["Enter"], description: "Insert a new line in the message composer" },
    ],
  },
];
 
/** Settings panel listing all keyboard shortcuts grouped by category. */
export function KeyboardShortcutsPanel(): JSX.Element {
  return (
    <section className={styles.section} data-testid="keyboard-shortcuts-panel">
      <h3 className={styles.sectionTitle}>Keyboard Shortcuts</h3>
      <p className={styles.sectionDescription}>
        Keyboard shortcuts for navigating and interacting with Grackle. Global shortcuts are
        suppressed while typing in text fields.
      </p>
      {SHORTCUT_GROUPS.map((group) => (
        <div key={group.title} className={shortcutStyles.group}>
          <h4 className={shortcutStyles.groupTitle}>{group.title}</h4>
          <div className={shortcutStyles.shortcutList}>
            {group.shortcuts.map((shortcut) => (
              <div key={shortcut.description} className={shortcutStyles.shortcutRow}>
                <span className={shortcutStyles.keys}>
                  {shortcut.keys.map((k) => (
                    <kbd key={k} className={shortcutStyles.kbd}>
                      {k}
                    </kbd>
                  ))}
                </span>
                <span className={shortcutStyles.description}>{shortcut.description}</span>
              </div>
            ))}
          </div>
        </div>
      ))}
    </section>
  );
}