Shortcut keycaps: one presentation per platform everywhere (no split Ctrl / Enter caps) #710

Open
opened 2026-10-02 09:35:19 +00:00 by kayg · 7 comments
Owner

Owner question (2026-10-02)

"Why Ctrl instead of ^? Consistency where?" (search palette action pills, #499).

Finding

The shared formatter (apps/web/src/lib/shortcuts/format.ts) renders Mac glyphs (⌘ ⌥ ⇧ ⌃ ↩, joined with no separator, as in the Apple HIG) and PC words elsewhere (Ctrl/Alt/Shift/Enter joined with +, as in the Microsoft/GNOME guidelines). The Kbd variant="caps" in the search palette splits a combination into separate keycaps ("Ctrl" "Enter"), while menus/tooltips show "Ctrl+Enter" or "⌘↩" as one unit.

Expected

One keycap presentation per platform, used everywhere (menus, tooltips, the ? card, Settings → Shortcuts, palette pills): Mac shows one cap with the joined glyphs (⌘↩), Windows/Linux shows one cap with "Ctrl+Enter". Remove or align the split-caps variant. Screenshots with macOS rendering and Linux rendering at 3x.

## Owner question (2026-10-02) "Why Ctrl instead of ^? Consistency where?" (search palette action pills, #499). ## Finding The shared formatter (`apps/web/src/lib/shortcuts/format.ts`) renders Mac glyphs (⌘ ⌥ ⇧ ⌃ ↩, joined with no separator, as in the Apple HIG) and PC words elsewhere (Ctrl/Alt/Shift/Enter joined with +, as in the Microsoft/GNOME guidelines). The `Kbd variant="caps"` in the search palette splits a combination into separate keycaps ("Ctrl" "Enter"), while menus/tooltips show "Ctrl+Enter" or "⌘↩" as one unit. ## Expected One keycap presentation per platform, used everywhere (menus, tooltips, the ? card, Settings → Shortcuts, palette pills): Mac shows one cap with the joined glyphs (⌘↩), Windows/Linux shows one cap with "Ctrl+Enter". Remove or align the split-caps variant. Screenshots with macOS rendering and Linux rendering at 3x.
Author
Owner

Started work on branch job/kbdcaps-710, based on dev at c4a61e8cf0.

Started work on branch job/kbdcaps-710, based on dev at c4a61e8cf090170f35b1bed3350d9de20c83ecd5.
Author
Owner

Finding: the current Settings route has no Shortcuts section. lists Account, Apps, Maintenance, Appearance, Editor, Notifications, Calendars, Mail, AI, Photos, Files and Plugins, with no shortcut settings surface. I am updating the existing shortcut card and all current Kbd consumers; there is no Settings → Shortcuts component in this branch to convert.

Finding: the current Settings route has no Shortcuts section. lists Account, Apps, Maintenance, Appearance, Editor, Notifications, Calendars, Mail, AI, Photos, Files and Plugins, with no shortcut settings surface. I am updating the existing shortcut card and all current Kbd consumers; there is no Settings → Shortcuts component in this branch to convert.
Author
Owner

Finding: the current Settings route has no Shortcuts section. apps/web/src/routes/settings/sections.ts lists Account, Apps, Maintenance, Appearance, Editor, Notifications, Calendars, Mail, AI, Photos, Files and Plugins, with no shortcut settings surface. I am updating the existing shortcut card and all current Kbd consumers; there is no Settings to Shortcuts component in this branch to convert.

Finding: the current Settings route has no Shortcuts section. apps/web/src/routes/settings/sections.ts lists Account, Apps, Maintenance, Appearance, Editor, Notifications, Calendars, Mail, AI, Photos, Files and Plugins, with no shortcut settings surface. I am updating the existing shortcut card and all current Kbd consumers; there is no Settings to Shortcuts component in this branch to convert.
Author
Owner

Finding: the Search action pills had CSS selectors for the old inline .kbd span. I updated those selectors for the shared .kbd-caps wrapper and .kbd-cap element, including the coarse-pointer hide rule, so the joined cap keeps the pill spacing and touch behavior.

Finding: the Search action pills had CSS selectors for the old inline .kbd span. I updated those selectors for the shared .kbd-caps wrapper and .kbd-cap element, including the coarse-pointer hide rule, so the joined cap keeps the pill spacing and touch behavior.
Author
Owner

Finding: docs/DESIGN.md §50 lists Shortcuts under Look & Feel, but the current Appearance Settings page only has Theme & UI and Text. I will add the missing deep-linked Shortcuts group and reuse the shortcut registry and Kbd there. This keeps the issue's named Settings surface real without adding shortcut rebinding or changing the platform preset behavior.

Finding: `docs/DESIGN.md` §50 lists Shortcuts under Look & Feel, but the current Appearance Settings page only has Theme & UI and Text. I will add the missing deep-linked Shortcuts group and reuse the shortcut registry and `Kbd` there. This keeps the issue's named Settings surface real without adding shortcut rebinding or changing the platform preset behavior.
Author
Owner

Full web test gate finding: 1,056 tests passed and one timed out in src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening (5,000 ms timeout at line 92). The test file and Theme Picker behavior were not changed for #710, and the assertion was left intact. This run shared the host with the local 1,000-file performance profile; that may have affected timing, but I have not diagnosed the cause. I will report the one-pass gate result without retrying it.

Full web test gate finding: 1,056 tests passed and one timed out in `src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening` (5,000 ms timeout at line 92). The test file and Theme Picker behavior were not changed for #710, and the assertion was left intact. This run shared the host with the local 1,000-file performance profile; that may have affected timing, but I have not diagnosed the cause. I will report the one-pass gate result without retrying it.
Author
Owner

Built

  • One shared Kbd renders one cap for each shortcut combination. Mac joins glyphs (⌘↩); PC joins key names with plus (Ctrl+Enter).
  • Menus, tooltips, Search, the ? card, and Settings use the shared formatter and cap.
  • Shortcut rows now come from one shared component. Settings has a deep link at /settings/appearance/shortcuts.
  • Search arrow guidance has spoken screen-reader labels.
  • The production screenshot runner emulates macOS and Linux. It captures five surfaces at 390, 820, and 1440 CSS pixels, in light and dark, at 3×.

Files

  • packages/ui/src/components/Kbd.svelte
  • packages/ui/src/components/menu/MenuItem.svelte
  • packages/ui/src/components/tooltip/TooltipLayer.svelte
  • apps/web/src/lib/shortcuts/format.ts
  • apps/web/src/lib/components/KeyboardShortcutsCard.svelte
  • apps/web/src/lib/components/ShortcutList.svelte
  • apps/web/src/lib/components/ShortcutList.svelte.test.ts
  • apps/web/src/lib/components/Kbd.svelte.test.ts
  • apps/web/src/lib/components/search-dialog.svelte
  • apps/web/src/lib/menu/MenuItem.svelte.test.ts
  • apps/web/src/lib/search/SearchField.svelte
  • apps/web/src/lib/search/SearchPreview.svelte
  • apps/web/src/routes/settings/appearance/AppearanceSection.svelte
  • apps/web/src/routes/settings/sections.ts
  • apps/web/src/routes/settings/sections.test.ts
  • apps/web/e2e/kbd-motion-527.mjs
  • bench/kbd-motion-527.mjs

Screenshots

Each archive has 30 images for Help, menus, tooltips, Search, and Settings Shortcuts at all requested widths and themes.

The desktop PNGs are 4320×2700 pixels. The macOS VM was not used.

Performance

The local profile completed against 1,000 real Files and rendered 98 shortcut caps. Full output is in artifacts/kbdcaps-710/perf.json. The host load average before the run was 29.51, 35.72, 33.92; treat these as loaded-host local measurements.

  • Shortcut card, 20 open/close cycles: p50 1070.53 ms, p95 1627.54 ms, browser CPU 22.33 s (99.8%), RSS 608.7 to 646.3 MiB.
  • Shortcut card burst, 100 cycles: p50 921.58 ms, p95 2006.25 ms, max 6782.27 ms, browser CPU 107.94 s (104%), peak RSS 646.3 MiB.
  • Files selection, 20 moves: p50 32.99 ms, p95 74.91 ms, browser CPU 0.83 s (105%), RSS 585.1 to 593.4 MiB.
  • Files selection burst, 100 moves: p50 24.89 ms, p95 51.05 ms, browser CPU 3.79 s (136.9%), peak RSS 601.9 MiB.

docs/perf/baseline.json has no keyboard-motion or shortcut-cap workload, so these numbers have no comparison baseline.

UX gaps closed

  • The same joined cap appears across all requested surfaces.
  • Settings exposes the current shortcut registry through a real deep link.
  • Screen readers get spoken shortcut text and arrow-key guidance.

UX gaps left

  • Settings Shortcuts is a read-only registry list. Shortcut rebinding and preset controls are outside this presentation issue and are not in the design.

Decisions

I placed Shortcuts under Appearance at /settings/appearance/shortcuts, following DESIGN §§33 and 50. The page shows the shared registry and does not add rebinding or platform preset behavior.

Web gates

bun run check:

$ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json
User browser caches use userStorage; only documented device/public-link exceptions remain.
Text sizes and UI shape values use shared role tokens.
UI transitions and animation options use shared motion tokens or documented exceptions.
Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/kbdcaps-710/apps/web
Getting Svelte diagnostics...

svelte-check found 0 errors and 0 warnings

bun run test:

FAIL  |component| src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening
Error: Test timed out in 5000ms.

Test Files  1 failed | 154 passed (155)
      Tests  1 failed | 1056 passed (1057)
   Start at  14:23:18
   Duration  212.36s (transform 65%, environment 13%, import 11%, tests 8%, setup 2%)
error: script "test" exited with code 1

I left the existing assertion unchanged. The failing Theme Picker test is outside the files changed for #710; this run shared the host with the local performance profile, but its cause is not confirmed.

Other verification

Production motion check: PASS keyboard and pointer Tab, selection, and Search actions use the same durations; ? morphs in. Both platform screenshot-only runs passed.

cargo clean output: Removed 7237 files, 4.6GiB total. Web build output was deleted.

Head SHA: f5ade2d5ba

## Built - One shared Kbd renders one cap for each shortcut combination. Mac joins glyphs (⌘↩); PC joins key names with plus (Ctrl+Enter). - Menus, tooltips, Search, the ? card, and Settings use the shared formatter and cap. - Shortcut rows now come from one shared component. Settings has a deep link at /settings/appearance/shortcuts. - Search arrow guidance has spoken screen-reader labels. - The production screenshot runner emulates macOS and Linux. It captures five surfaces at 390, 820, and 1440 CSS pixels, in light and dark, at 3×. ## Files - packages/ui/src/components/Kbd.svelte - packages/ui/src/components/menu/MenuItem.svelte - packages/ui/src/components/tooltip/TooltipLayer.svelte - apps/web/src/lib/shortcuts/format.ts - apps/web/src/lib/components/KeyboardShortcutsCard.svelte - apps/web/src/lib/components/ShortcutList.svelte - apps/web/src/lib/components/ShortcutList.svelte.test.ts - apps/web/src/lib/components/Kbd.svelte.test.ts - apps/web/src/lib/components/search-dialog.svelte - apps/web/src/lib/menu/MenuItem.svelte.test.ts - apps/web/src/lib/search/SearchField.svelte - apps/web/src/lib/search/SearchPreview.svelte - apps/web/src/routes/settings/appearance/AppearanceSection.svelte - apps/web/src/routes/settings/sections.ts - apps/web/src/routes/settings/sections.test.ts - apps/web/e2e/kbd-motion-527.mjs - bench/kbd-motion-527.mjs ## Screenshots Each archive has 30 images for Help, menus, tooltips, Search, and Settings Shortcuts at all requested widths and themes. - [Linux 3× screenshot matrix](https://git.kayg.org/attachments/e41ad240-782e-4ef8-a600-3bad0e88ac77) - [macOS-emulated 3× screenshot matrix](https://git.kayg.org/attachments/73582513-6aa9-4ebf-b36f-a7130dba5252) - [Linux desktop light Search](https://git.kayg.org/attachments/09fa9aab-be75-42fc-85d3-8ee9ab41306b) - [Linux desktop light Settings Shortcuts](https://git.kayg.org/attachments/3b460673-9fad-4941-8854-80ee2861cce4) - [macOS-emulated desktop light Search](https://git.kayg.org/attachments/19b5a003-39b0-41db-a721-5d76d6cc9b63) - [macOS-emulated desktop light Settings Shortcuts](https://git.kayg.org/attachments/d193f351-2986-41c2-9477-53aeee1ddc65) The desktop PNGs are 4320×2700 pixels. The macOS VM was not used. ## Performance The local profile completed against 1,000 real Files and rendered 98 shortcut caps. Full output is in artifacts/kbdcaps-710/perf.json. The host load average before the run was 29.51, 35.72, 33.92; treat these as loaded-host local measurements. - Shortcut card, 20 open/close cycles: p50 1070.53 ms, p95 1627.54 ms, browser CPU 22.33 s (99.8%), RSS 608.7 to 646.3 MiB. - Shortcut card burst, 100 cycles: p50 921.58 ms, p95 2006.25 ms, max 6782.27 ms, browser CPU 107.94 s (104%), peak RSS 646.3 MiB. - Files selection, 20 moves: p50 32.99 ms, p95 74.91 ms, browser CPU 0.83 s (105%), RSS 585.1 to 593.4 MiB. - Files selection burst, 100 moves: p50 24.89 ms, p95 51.05 ms, browser CPU 3.79 s (136.9%), peak RSS 601.9 MiB. docs/perf/baseline.json has no keyboard-motion or shortcut-cap workload, so these numbers have no comparison baseline. ## UX gaps closed - The same joined cap appears across all requested surfaces. - Settings exposes the current shortcut registry through a real deep link. - Screen readers get spoken shortcut text and arrow-key guidance. ## UX gaps left - Settings Shortcuts is a read-only registry list. Shortcut rebinding and preset controls are outside this presentation issue and are not in the design. ## Decisions I placed Shortcuts under Appearance at /settings/appearance/shortcuts, following DESIGN §§33 and 50. The page shows the shared registry and does not add rebinding or platform preset behavior. ## Web gates bun run check: <pre> $ node scripts/check-user-storage.mjs && node scripts/check-type-tokens.mjs && node scripts/check-motion-tokens.mjs && svelte-kit sync && svelte-check --tsconfig ./tsconfig.json User browser caches use userStorage; only documented device/public-link exceptions remain. Text sizes and UI shape values use shared role tokens. UI transitions and animation options use shared motion tokens or documented exceptions. Loading svelte-check in workspace: /home/kayg/Developer/calternal-wt/kbdcaps-710/apps/web Getting Svelte diagnostics... svelte-check found 0 errors and 0 warnings </pre> bun run test: <pre> FAIL |component| src/lib/themePicker.svelte.test.ts > theme menu > reveals the trigger in the sheet scrollport before opening Error: Test timed out in 5000ms. Test Files 1 failed | 154 passed (155) Tests 1 failed | 1056 passed (1057) Start at 14:23:18 Duration 212.36s (transform 65%, environment 13%, import 11%, tests 8%, setup 2%) error: script "test" exited with code 1 </pre> I left the existing assertion unchanged. The failing Theme Picker test is outside the files changed for #710; this run shared the host with the local performance profile, but its cause is not confirmed. ## Other verification Production motion check: PASS keyboard and pointer Tab, selection, and Search actions use the same durations; ? morphs in. Both platform screenshot-only runs passed. cargo clean output: Removed 7237 files, 4.6GiB total. Web build output was deleted. Head SHA: f5ade2d5ba3e45db1398509d83c6f2d05d1108d5
Sign in to join this conversation.
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
kayg/calternal#710
No description provided.