27fa9ab226
Translate 4 new keys across all 33 locales: - Send - Book file is not available locally - Failed to send book - Highlight Current Sentence Also commit pending .claude/memory bug-fix notes. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
12 KiB
12 KiB
Readest Project Memory
Key Reference Documents
- Bug Fixing Patterns - Common bug categories, root causes, and fix strategies
- CSS & Style Fixes - EPUB CSS override patterns and the style.ts pipeline
- TTS Fixes - Text-to-Speech architecture and bug patterns
- Layout & UI Fixes - Safe insets, z-index, platform-specific UI issues
- Platform Compat Fixes - Android, iOS, Linux, macOS platform-specific bugs
- Annotator & Reader Fixes - Highlight, selection, accessibility bugs
Paginator Scroll Knowledge
- Issue #4112 scroll-anchoring — RESOLVED (PR #4349). Scroll-anchoring suppressed at scrollTop 0 when prepending a section in scrolled mode; fix patterns (prepend compensation, eager backward preload, no-blank nav) + test & dev-server gotchas
- Reading ruler line/column-aware — ruler snaps to real lines; multi-column band spans one column; Range.getClientRects() returns tall block boxes that must be dropped; iframe frame-offset mapping; synthetic-key throttling
- TOC expand + auto-scroll — #4059 collapse-by-default policy in
tocTree.ts; pinned-sidebar mounts before progress → dynamic expansion breaks scroll-to-current via (1) spurious onScroll clearing pending and (2) Virtuoso scrollToIndex landing short after row growth (re-assert on rAF) - BooknoteView auto-scroll (#4352) — virtualizing the annotation/bookmark list dropped auto-scroll-to-nearest; two paths (reload: OverlayScrollbars resets scrollTop → re-apply in
initializedvia ref; tab-switch: synchronous scrollToIndex on fresh-mounted list wedges Virtuoso → useinitialTopMostItemIndex+ skip-gate). Mirrors TOCView. Includes dev-server/Fast-Refresh/screenshot-vs-DOM verification gotchas - Swipe page-turn bg flash — white↔black flash on swipe+animation only;
#backgroundwas static screen-space and didn't track content during drag/snap; fix = sliding per-view full-bleed segments (computeBackgroundSegments) rebuilt on scroll + per-rAF synced to the view transform during snap - Duokan fullscreen cover hidden in scroll mode — #4379
data-duokan-page-fullscreencover pinnedposition:absolute height:100%collapses against auto-height scroll container; gate fullscreen onthis.#column+ reset stale absolute props on toggle (setImageSizein paginator.js) - Paginated texture occlusion — #4399 host
.foliate-viewer::beforetexture absent in paginated (shown in scrolled); opaque#backgroundcontainer (= fallbackBg) from the swipe-flash fix occludes it; sharedtextureAwareBackgroundhelper +hasTexture ? '' : fallbackBgcontainer - Background overflows column (#4394, PR #4429) — paginated page bg stretched into the outer
--_outer-mingutter → mixed cover/title 2-up spread shifted off-centre (~250px at 1920px). KEEP the grid (--_outer-minkeeps margins symmetric); fix = clampcomputeBackgroundSegmentsto[containerStart,containerEnd](Math.max/Math.min) so bg stays in its column. 2 wrong tries first (bleed-gating, "page shouldn't be yellow"); foliate submodule needs dev-server RESTART to pick up edits
Critical Files (Most Bug-Prone)
src/utils/style.ts- Central EPUB CSS transformation hub (14+ bug fixes)packages/foliate-js/paginator.js- Page layout, image sizing, backgroundssrc/services/tts/TTSController.ts- TTS state machine, section trackingsrc/hooks/useSafeAreaInsets.ts- Safe area inset managementsrc/app/reader/components/FoliateViewer.tsx- Reader view orchestrationsrc/app/reader/components/annotator/Annotator.tsx- Annotation lifecycle
Sync Notes
- KOSync CFI spine resolution — convert via the CFI's own spine (
getXPointerFromCFI/getCFIFromXPointer), nevernew XCFI(primaryDoc, primaryIndex); primaryIndex lags during scroll → spine-mismatch throw - Empty-start CFI sync bug —
epubcfi(/6/24!/4,,/20/1:58)(empty-start range) from the cfi-inert skip-link transitional window; jumps to wrong section end;isMalformedLocationCfi→ discard the synced value inuseProgressSync(NOT the local open path); foliate fix doesn't repair already-synced values - Custom fonts disappear on cloud sync (#4410) — CRDT remove-wins: re-import-after-delete needs a
reincarnationtoken or the pull re-applies the tombstone;addFont/addTextureminted none; fix mirrors dictionary (both cases) + OPDS token style; coverage matrix per kind
Testing
- Tauri Rust↔JS parser parity tests — #4369 native Rust EPUB/MOBI parser; how to cross-check vs foliate-js in the
.tauri.test.tsWebView suite (CWD disk path for Rust, Vite URL for JS, normalizer-based compare, cover presence-only, desc whitespace-collapse); thedcterms:modified→publisheddivergence fix
Build & Vendoring
- pdfjs vendor wasm decoders — scanned PDFs blank in CI build only (0.11.2 regression); pdfjs 5.7.x moved JBIG2 to
jbig2.wasm,copy-pdfjs-wasmallow-list dropped it;cpxno-errors on empty glob; local stalepublic/vendor(gitignored, not refreshed bytauri build) masked it; fix = copywasm/*
Platform Compat
- Window-state sanitizer (#4398) — Windows launch crash (WebView2 0x80070057) from invalid
.window-state.json(-32000minimized sentinel /0×0); our plugin already has upstream #253 fix so bad files are stale; defense-in-depthwindow-state-sanitizerplugin registered BEFORE window-state (plugin init = registration order); coord threshold-16000(~halfway to the -32000 sentinel; real desktops sit a few thousand px off origin) keeps multi-monitor negatives
Feature Notes
- Manage Cache + iOS container layout —
'Cache'base =Library/Caches/<bundle>only (not all of Caches); iOSDocuments/Inboxcleared too; WebKit cache + tmp out of reach; never touch App Support - D-pad Navigation — Android TV remote / keyboard arrow navigation design, key files, and pitfalls
- Cloudflare Workers WebSocket — use fetch() Upgrade pattern (not
wsnpm); CF delivers binary frames as Blob (must serialize async decodes) - Share-a-Book Feature (in progress) — locked decisions for the /s/{token} share-link feature; plan at ~/.claude/plans/ok-we-will-learn-cosmic-acorn.md
- readest.koplugin i18n — gettext loader at
apps/readest.koplugin/i18n.lua,.pocatalog atlocales/<i18next-code>/translation.po, extract/apply scripts inscripts/ - koplugin cover upload — #4374 uploadBook only shipped cached cloud covers; local-origin books uploaded blank. Fix =
extractLocalCoverviaFileManagerBookInfo:getCoverImage(nil, file)→writeToFile(path,"png"). KOReader checkout at/Users/chrox/dev/koreader
Patterns
- Virtuoso + OverlayScrollbars — useOverlayScrollbars hook integration for overlay scrollbars on mobile webviews
- Design system → DESIGN.md — codify recurring UI/UX rules in
apps/readest-app/DESIGN.md; neverpl/pr/ml/mr/text-left/text-right(RTL); §5 boxed list anatomy has uniformmin-h-14rows and chromeless controls
Reader UI Fixes
- Android image callout freeze — long-press
<img>fires WebView native callout that collides with app touch handlers → whole-app freeze;-webkit-touch-callout: nonedoesn't inherit so put.no-context-menuon an ancestor of the image (.no-context-menu imgrule in globals.css); seen on book covers (#4345) + image preview/zoom (#4420,ImageViewer.tsx) - ProgressBar focus-ring line (#4397) — decorative
.progressinfofooter wastabIndex={-1}→ Android long-press focused it → stray content-width focus-ring line at the bottom every page; fix = drop tabIndex (role='presentation' must not be focusable); ffmpeg-the-video debugging + live-browser:focus-visibleconfirmation - Table dark-mode tint regression (#4419) —
blockquote, table *color-mix tint ingetColorStylesmust stay gated onoverrideColor(gate added #2377, removed #4055, re-broke → #4419); safe now that #4392 light-bg rewriters handle #4028 zebra legibility; SAME rule paints vertical-TOC.space/▉ spacer cells (▉ U+2589 = blank glyph, contours=0) → "spacing changes" symptom; both fixed by the gate
Library Fixes
- Tauri menu append race (#4389) — un-awaited
Menu.append()(async IPC) inBookshelfItem.tsx→ context-menu items shuffle order every open (native only, invisible in jsdom); fix = singleawait Menu.new({ items })of orderedMenuItemOptions; order/inclusion extracted to puregetBookContextMenuItemIdsfor unit testing - TXT author recognition (#4390) — 【】-titled Chinese web-novels show author missing/garbage; they're TXT→EPUB (title==full filename is the tell, check
txt.tsnot foliate-js);extractTxtFilenameMetadataonly handled 《》 + greedy header capture grabbed metadata blobs; fix =parseLabeledAuthorfor any filename +isPlausibleAuthorNameguard
Architecture Notes
- foliate-js is a git submodule at
packages/foliate-js/ - Multiview paginator: loads adjacent sections in background, multiple View/Overlayer instances per book
- Style overrides:
getLayoutStyles()(always),getColorStyles()(when overriding color) transformStylesheet()does regex-based EPUB CSS rewriting at load time- TTS uses independent section tracking (
#ttsSectionIndex) decoupled from view - Safe area insets flow: Native plugin -> useSafeAreaInsets hook -> component styles
- Dropdown menus use
DropdownContext(not blur-based) for screen reader compat - Foliate touch-listener capture phase — to suppress reader gestures from the app, use
{capture:true}; the paginator registers bubble-phase doc listeners first (duringview.open()) - iframe cross-realm instanceof — app-bundle code (style.ts, iframeEventHandlers.ts) runs in top realm;
iframeEl instanceof Elementis ALWAYS false → guards silently drop all iframe elements (passes jsdom, dead in app). Duck-type'closest' in targetinstead. Bit PR #4391's touch routing + applyTableStyle dedupe
Workflow
- Test file filter — use
pnpm test <path>without--to run a single file - Always rebase before PR — rebase onto origin/main before creating PRs
- New branch per PR — always create a fresh branch from main for each new PR/issue
- Upgrade gstack locally — always upgrade from the project's .claude/skills/gstack, not global
- No lookbehind regex — never use
(?<=)or(?<!)in JS/TS; build check rejects them - Use worktree — never
git worktree adddirectly; alwayspnpm worktree:newbefore PR review, issue fix, or feature work - en/translation.json holds ONLY plural variants + proper nouns — non-plural strings stay out (defaultValue: key is the en source); plural strings (
_('...', { count })) need hand-added_one/_otherentries or the singular renders as "1 days" - Never push on every change — hold pushes during active bug iteration; commit locally only until user confirms or work hits a clean done-state
- No test seams in production code — production must never import or call
__reset*ForTests; cross-module test resets belong in the test file's beforeEach/afterEach