feat(ui): keyboard shortcuts overlay - '?' opens a cheat-sheet (LC-252) #304

Merged
longjacksonle merged 1 commit from feat/lc-252-shortcuts-overlay into main 2026-06-14 02:07:18 +02:00

What

Adds a discoverable keyboard-shortcuts cheat-sheet (LC-252). Pressing ? anywhere outside a text field opens a modal listing every existing shortcut, grouped by area. A "Keyboard shortcuts" link in the sidebar footer opens the same modal.

The app had accumulated shortcuts (Arrow-Up edit-last from LC-248, Alt+Shift+Up/Down jump-to-unread, Enter/Shift+Enter, @ mention, / slash, Esc cancel) with no way to discover them. This surfaces them.

How

  • New server/templates/shortcuts_modal.html, included once in the persistent shell (layout.html) next to poll_modal.html. Mirrors that convention exactly: .modal-backdrop/.modal-panel, role="dialog" aria-modal="true", Escape + backdrop-mousedown close, opener focus restore, shared window.__lcDialogTrap focus trap.
  • Global ? keydown handler exposes window.__lcOpenShortcuts(). It is suppressed while typing in input/textarea/select/[contenteditable], during IME composition, with any modifier held, or when another dialog/popover is already open (so ? types normally in the composer).
  • Sidebar footer gains a "Keyboard shortcuts" button calling the same opener.
  • Strings localized in en + es (shortcuts-* in common.ftl, sidebar-link-shortcuts in partials.ftl).

Pure front-end: no server route, no DB, no new env var. Not operator-visible.

Shortcuts listed (real only, nothing invented)

Messaging: Enter send, Shift+Enter newline, Up edit last, Esc cancel/close, @ mention, / slash command. Navigation: Alt+Shift+Down / Alt+Shift+Up next/prev unread room. General: ? show help.

Tests

routes_drafts::room_page_ships_shortcuts_overlay asserts the room page ships the modal markup, the ? open handler, and the dialog label. just test and just test-saas pass.

QA note

The ? keybind, open/close, and focus trap are JS-driven, so they want a quick manual click-through before merge (open via ? and via the sidebar link; confirm ? types normally inside the composer; Esc/backdrop/close all dismiss and return focus).

## What Adds a discoverable keyboard-shortcuts cheat-sheet (LC-252). Pressing `?` anywhere outside a text field opens a modal listing every existing shortcut, grouped by area. A "Keyboard shortcuts" link in the sidebar footer opens the same modal. The app had accumulated shortcuts (Arrow-Up edit-last from LC-248, Alt+Shift+Up/Down jump-to-unread, Enter/Shift+Enter, @ mention, / slash, Esc cancel) with no way to discover them. This surfaces them. ## How - New `server/templates/shortcuts_modal.html`, included once in the persistent shell (`layout.html`) next to `poll_modal.html`. Mirrors that convention exactly: `.modal-backdrop`/`.modal-panel`, `role="dialog" aria-modal="true"`, Escape + backdrop-mousedown close, opener focus restore, shared `window.__lcDialogTrap` focus trap. - Global `?` keydown handler exposes `window.__lcOpenShortcuts()`. It is suppressed while typing in `input`/`textarea`/`select`/`[contenteditable]`, during IME composition, with any modifier held, or when another dialog/popover is already open (so `?` types normally in the composer). - Sidebar footer gains a "Keyboard shortcuts" button calling the same opener. - Strings localized in `en` + `es` (`shortcuts-*` in common.ftl, `sidebar-link-shortcuts` in partials.ftl). Pure front-end: no server route, no DB, no new env var. Not operator-visible. ## Shortcuts listed (real only, nothing invented) Messaging: Enter send, Shift+Enter newline, Up edit last, Esc cancel/close, @ mention, / slash command. Navigation: Alt+Shift+Down / Alt+Shift+Up next/prev unread room. General: ? show help. ## Tests `routes_drafts::room_page_ships_shortcuts_overlay` asserts the room page ships the modal markup, the `?` open handler, and the dialog label. `just test` and `just test-saas` pass. ## QA note The `?` keybind, open/close, and focus trap are JS-driven, so they want a quick manual click-through before merge (open via `?` and via the sidebar link; confirm `?` types normally inside the composer; Esc/backdrop/close all dismiss and return focus).
feat(ui): keyboard shortcuts overlay - '?' opens a cheat-sheet (LC-252)
All checks were successful
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / Kingfisher (push) Successful in 5s
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Nosey parker (pull_request) Successful in 5s
check-secrets / Kingfisher (pull_request) Successful in 6s
Create release / Create release from merged PR (pull_request) Has been skipped
Check / clippy + fmt + tests (pull_request) Successful in 4m47s
c83de4e9bc
Adds a discoverable keyboard-shortcuts cheat-sheet. Pressing ? anywhere outside a text field opens a singleton modal listing every existing shortcut grouped by area (Messaging, Navigation, General); a "Keyboard shortcuts" link in the sidebar footer opens the same modal.

The modal mirrors the poll_modal.html convention: lives once in the persistent shell (layout.html), uses .modal-backdrop/.modal-panel, role=dialog, Escape + backdrop-mousedown close, opener focus restore, and the shared window.__lcDialogTrap focus trap. The ? handler ignores keystrokes while typing in input/textarea/select/contenteditable, during IME composition, with modifiers, or when another dialog/popover is open. Pure front-end: no server route, no DB, no new env var.

Strings localized in en + es. Test asserts the room page ships the modal markup, the open handler, and the dialog label.

#LC-252
#LC-253

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-252-shortcuts-overlay 2026-06-14 02:07:18 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!304
No description provided.