feat(reader): shortcuts help modal + desktop edge page-turn zones

Help menu (the reader had a growing shortcut/gesture vocabulary with
no discoverability): a ? topbar button, the '?' key, and F1 open a
glass modal listing navigation, zoom/pan, highlight, and touch
gesture reference — format-aware (fixed-layout/PDF rows appear only
where they apply), Esc closes it first in the dismiss chain.

Desktop edge zones: clickable page-turn strips on the left/right
viewport edges (8% width, 44-72px), desktop only (hover+fine-pointer
media query — touch devices use tap zones, avoiding double paging).
Hovering reveals a chevron arrow and a subtle edge gradient. Zones
disable (pointer-events pass-through) while a fixed-layout page is
zoomed so edge clicks belong to content: panning, selection,
highlight editing. fxZoomed tracks zoom state via the renderer zoom
event, reset/fit actions, and init.
This commit is contained in:
2026-08-18 07:59:26 -04:00
parent 1a07635605
commit 94be6edceb
5 changed files with 254 additions and 13 deletions
+138
View File
@@ -1074,6 +1074,144 @@
color: #ffffff;
}
/* Desktop edge page-turn zones: only on hover-capable fine-pointer
devices (touch uses tap zones instead). Arrow + subtle edge gradient
appear on hover. */
.reader-edge-zone {
position: absolute;
top: 0;
bottom: 0;
width: 8%;
max-width: 72px;
min-width: 44px;
z-index: 10;
display: none;
align-items: center;
cursor: pointer;
}
.reader-edge-zone.left {
left: 0;
justify-content: flex-start;
padding-left: 0.75rem;
}
.reader-edge-zone.right {
right: 0;
justify-content: flex-end;
padding-right: 0.75rem;
}
.reader-edge-zone::before {
content: "";
position: absolute;
inset: 0;
opacity: 0;
transition: opacity 0.15s ease;
}
.reader-edge-zone.left::before {
background: linear-gradient(to right, rgba(255, 255, 255, 0.08), transparent);
}
.reader-edge-zone.right::before {
background: linear-gradient(to left, rgba(255, 255, 255, 0.08), transparent);
}
.reader-edge-zone .reader-icon {
color: #ffffff;
filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.6));
opacity: 0;
transition: opacity 0.15s ease;
}
.reader-edge-zone:hover::before {
opacity: 1;
}
.reader-edge-zone:hover .reader-icon {
opacity: 0.85;
}
@media (hover: hover) and (pointer: fine) {
.reader-edge-zone {
display: flex;
}
}
/* Shortcuts help modal */
.reader-help-backdrop {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 70;
}
.reader-help {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: min(34rem, calc(100vw - 2rem));
max-height: min(38rem, calc(100vh - 4rem));
display: flex;
flex-direction: column;
background-color: color-mix(in srgb, var(--bg-primary) 90%, transparent);
-webkit-backdrop-filter: blur(20px) saturate(1.3);
backdrop-filter: blur(20px) saturate(1.3);
border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
border-radius: 0.875rem;
box-shadow: 0 16px 48px rgba(0, 0, 0, 0.45);
z-index: 71;
}
.reader-help-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.875rem 1.25rem;
border-bottom: 1px solid var(--border);
flex-shrink: 0;
}
.reader-help-body {
overflow-y: auto;
padding: 1rem 1.25rem;
}
.reader-help-section {
font-size: 0.7rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-secondary);
margin: 1.1rem 0 0.4rem;
}
.reader-help-body .reader-help-section:first-child {
margin-top: 0;
}
.help-row {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: 1rem;
padding: 0.3rem 0;
font-size: 0.85rem;
}
.help-row > span:first-child {
color: var(--text-primary);
}
.help-keys {
text-align: right;
color: var(--text-secondary);
font-size: 0.8rem;
white-space: nowrap;
}
.help-note {
color: var(--text-secondary);
font-size: 0.75rem;
}
.kbd {
display: inline-block;
min-width: 1.4rem;
text-align: center;
padding: 0.05rem 0.4rem;
margin: 0 0.1rem;
border-radius: 0.3rem;
border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
border-bottom-width: 2px;
background-color: color-mix(in srgb, currentColor 8%, transparent);
font-family: ui-monospace, monospace;
font-size: 0.72rem;
line-height: 1.2rem;
}
/* In-book search */
.reader-search-bar {
display: flex;
+1 -1
View File
File diff suppressed because one or more lines are too long