Add a "Highlight Current Sentence" keyboard action (default Shift+M, in the
Text to Speech shortcut section) that persists the sentence TTS is reading
aloud as a normal highlight using the user's default style/color — no text
selection, eyes-off, silent, and idempotent (a repeat press on the same
sentence is a no-op rather than a duplicate).
Flow: the shortcut handler in useBookShortcuts dispatches tts-highlight-sentence
→ useTTSControl (which owns the TTSController) resolves the current sentence via
the new TTSController.getSpokenSentence() and relays create-tts-highlight
→ Annotator builds the BookNote with the pure, unit-tested buildTTSSentenceHighlight
helper and persists/renders it like any other highlight.
Closes#4085
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Snap the reading ruler to real rendered text lines instead of stepping by a
fixed arithmetic height, so the band always frames whole lines.
- Snap to actual line geometry from the relocate range; the band is sized
dynamically to the text block plus symmetric padding (round(fontSize *
lineHeight * 0.3)), capped at (lines + 1) line heights so a tall image inside
a block can't expand it to cover the whole figure.
- Drop block/container rects (Range.getClientRects aggregates multi-line element
borders) so paragraphs aren't merged into one giant line and skipped.
- Column-aware in multi-column layouts: the band spans one column at a time and
advances column by column.
- Confine the band to lines at least half visible within the viewport.
- Scrolled mode: snap to lines, and at a view edge scroll the view and realign
the band to the start/end of the new view (works for vertical-rl too, which
scrolls horizontally); paging snaps the view edge between lines so text isn't
cut or repeated.
- Vertical writing mode: correct band centering and drag direction; Up/Down keys
move the ruler while Left/Right turn pages (taps always move the ruler).
- Page turns keep the first/last line: forward lands on the first line of the new
page, backward on the last line; the relayout re-snap anchors on the band's
leading edge so it never skips a line.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: design spec for gesture-based brightness control (#3021)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* docs: revise brightness-gesture spec per /autoplan review (#3021)
CEO+Design+Eng dual-voice review. Key fixes: capture-phase listener
(bubble-phase could not suppress foliate paginator), opt-out toggle,
18px threshold, selection guard, brightness seed race, rAF teardown,
e-ink stepped overlay, contrast capsule, perceptual curve reuse,
listener-level test harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(reader): swipe-to-adjust brightness gesture on mobile (#3021)
Left-edge vertical swipe adjusts screen brightness on iOS/Android, with a
Sun-icon progress overlay. Capture-phase non-passive listener suppresses the
foliate paginator / page-flip / UI-toggle handlers; selection guard, strip
reservation in scrolled mode, eager brightness seed, rAF throttle + teardown.
Opt-out toggle in Settings > Behavior > Device (default on). Perceptual curve
shared with the menu slider. Pure-helper + listener-level tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(reader): detect brightness-swipe edge by screenX; i18n + shorter label (#3021)
On-device fix: paginated mode lays the iframe doc out as wide side-by-side
columns, so clientX/documentElement.clientWidth are document coordinates and a
left-edge touch on a later page never fell inside the strip (armed stayed false).
Detect with screenX against the parent window width, matching usePagination.
Also: translate the two new setting strings across all locales and shorten the
toggle description to 'Slide along the left edge'.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>