feat(reader): add a keyboard-shortcut help overlay

Press `?` in the reader to open a Sheet documenting the existing bindings
(arrows/J/K paging, Home/End, chapter nav, Esc); Esc or the close button
dismisses it. While open, the reader swallows navigation keys so paging
can't happen behind the overlay. e2e covers open-on-? and close-on-Esc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-04 21:18:47 +02:00
parent f5692ea109
commit c212deb7b0
6 changed files with 126 additions and 5 deletions

View File

@@ -110,6 +110,7 @@
// mode, or per-image timer in continuous mode) opens an action
// sheet that funnels into the same modals. Unauthenticated users
// see neither — there's nothing for them to act on.
let shortcutsOpen = $state(false);
let contextMenuOpen = $state(false);
let contextMenuAnchor = $state<{ x: number; y: number }>({ x: 0, y: 0 });
let activePageId = $state<string | null>(null);
@@ -657,6 +658,15 @@
// Don't hijack keys while the user is typing in an input.
const target = e.target as HTMLElement | null;
if (target && (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA')) return;
// `?` opens the keyboard-shortcut help overlay. While it's open,
// swallow every key here so paging can't happen behind it — the
// Sheet owns its own Escape/close.
if (e.key === '?') {
e.preventDefault();
shortcutsOpen = true;
return;
}
if (shortcutsOpen) return;
// Esc always exits fullscreen if active — applies in both
// modes, including when the bars are hidden. Handled before
// the per-mode switches so it doesn't get shadowed.
@@ -1419,6 +1429,23 @@
</ul>
</Sheet>
<Sheet
open={shortcutsOpen}
title="Keyboard shortcuts"
onClose={() => (shortcutsOpen = false)}
testid="reader-shortcuts"
>
<dl class="shortcut-list">
<div class="shortcut"><dt><kbd></kbd> / <kbd>J</kbd></dt><dd>Next page</dd></div>
<div class="shortcut"><dt><kbd></kbd> / <kbd>K</kbd></dt><dd>Previous page</dd></div>
<div class="shortcut"><dt><kbd>Home</kbd></dt><dd>First page</dd></div>
<div class="shortcut"><dt><kbd>End</kbd></dt><dd>Last page</dd></div>
<div class="shortcut"><dt><kbd></kbd> / <kbd></kbd></dt><dd>Next / previous chapter (continuous mode)</dd></div>
<div class="shortcut"><dt><kbd>Esc</kbd></dt><dd>Exit full-screen / close this overlay</dd></div>
<div class="shortcut"><dt><kbd>?</kbd></dt><dd>Show this help</dd></div>
</dl>
</Sheet>
<Sheet
open={settingsOpen}
title="Reader settings"
@@ -2080,6 +2107,39 @@
-webkit-overflow-scrolling: touch;
}
.shortcut-list {
margin: 0;
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.shortcut {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--space-3);
}
.shortcut dt {
flex-shrink: 0;
}
.shortcut dd {
margin: 0;
color: var(--text-muted);
text-align: right;
}
.shortcut kbd {
font-family: var(--font-mono, monospace);
font-size: var(--font-xs);
padding: 1px 6px;
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
background: var(--surface);
}
.chapter-jump-item {
display: flex;
align-items: center;