Commit Graph

81 Commits

Author SHA1 Message Date
Huang Xin 70b94d8986 fix(layout): fixed layout of progress bar in vertical mode (#3749) 2026-04-04 21:20:34 +02:00
Huang Xin 21795e5cd3 fix(tts): avoid race condition in preloadNextSSML causing wrong highlights (#3748)
preloadNextSSML() called tts.next() interleaved with await, creating async
gaps where the concurrent #speak() could dispatch marks against corrupted
#ranges state (replaced by next() for a different block). Since mark names
restart at "0" per block, marks resolved to the wrong text position, causing
accidental page turns and highlights far from the current sentence.

Fix: gather all tts.next() and tts.prev() calls synchronously (no await
between them) so no async code can see the intermediate #ranges state.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:42:06 +02:00
Huang Xin f361698e05 feat(android): add D-pad navigation for Android TV remote controller (#3745)
* feat(android): add D-pad navigation for Android TV remote controller

Add basic D-pad/arrow key navigation support for Android TV Bluetooth
remote controllers, covering the full flow: library grid browsing,
reader page turning, toolbar interaction, and TTS toggle.

Library:
- Custom spatial navigation hook for grid D-pad navigation
- Arrow keys move between BookshelfItem elements with auto column detection
- ArrowDown from header enters the bookshelf grid

Reader:
- Enter key toggles header/footer toolbar visibility
- Left/Right navigate between toolbar buttons, Up/Down moves between
  header and footer bars
- Back button dismisses toolbar (with blur) before sidebar/library
- Focus-probe technique for reliable button visibility detection
  across fixed/hidden containers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: only auto-focus toolbar buttons on keyboard activation, not mouse hover

Track pointer activity to distinguish keyboard vs mouse toolbar activation.
When the toolbar appears due to mouse hover, skip auto-focus to prevent
unwanted focus outlines on desktop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: track keyboard events instead of pointer events for auto-focus guard

Pointer events from iframes don't bubble to the main document, so
tracking pointermove/pointerdown missed hover interactions over book
content. Track keydown instead — auto-focus only when a recent keyboard
event (Enter key) triggered the toolbar, not mouse hover.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 19:50:34 +02:00
Yi-Shun Wang 45bd355981 feat(opds): support custom catalog headers with web proxy consent (#3740)
* Add custom headers support for OPDS catalogs

* Require web proxy consent for sensitive OPDS credentials

* Strengthen OPDS header forwarding tests

---------

Co-authored-by: Yi-Shun Wang <git@albertwang.dev>
2026-04-04 12:01:16 +02:00
Huang Xin 52ac74bbad fix: fixed status info layout in vertical mode, fixed Android build (#3735) 2026-04-03 21:41:49 +02:00
Huang Xin ca5c860594 fix(kosync): don't normalize xpointer for more accurate progress sync, closes #3672 and closes #3616 (#3733) 2026-04-03 16:17:20 +02:00
AK Venugopal 80cab8e56d feat: Hardcover.app Sync (#3724)
* feat(hardcover): add one-way Hardcover sync integration

- Add HardcoverClient with ISBN/title-based book lookup, progress push, and note sync
- Add HardcoverSyncMapStore for persistent local mapping of note IDs to Hardcover journal IDs
- Add GraphQL queries/mutations for Hardcover API (insert/update/recreate journal entries)
- Add DB migration for hardcover_note_mappings table (schema: hardcover-sync)
- Add HardcoverSettings dialog component (connect/disconnect/enable toggle)
- Add useHardcoverSync hook wired in Annotator for push-notes and push-progress events
- Add Hardcover Sync section in BookMenu with per-book toggle (persisted in BookConfig)
- Add HardcoverSettings type and DEFAULT_HARDCOVER_SETTINGS to system settings
- Add hardcoverSyncEnabled per-book flag to BookConfig
- Mount HardcoverSettingsWindow in Reader alongside KOSync and Readwise windows

Sync is one-way (Readest → Hardcover), manual-action only, per-book opt-in.
Supports idempotent note sync: insert new, skip unchanged, update changed, recreate on stale remote ID.

* fix(hardcover): proxy API calls server-side to fix CORS, normalize Bearer token

- Add /api/hardcover/graphql Next.js route that proxies POST requests server-side,
  bypassing CORS restrictions (Hardcover API has no Access-Control-Allow-Origin header)
- On Tauri (desktop), calls Hardcover directly; on web, routes through the proxy
- Normalize token in HardcoverClient: accept raw JWT or 'Bearer <jwt>' format
- Update helper text to point to hardcover.app → Settings → API

* fix(hardcover): surface note-sync no-ops and harden book resolution

- Show toast feedback when book data is still loading, Hardcover is not configured,
  or the current book has no annotations/excerpts to sync
- Show an explicit info toast when note sync finds no new changes
- Parse Hardcover search results in the current hits/document response shape
- Resolve note sync through ensureBookInLibrary for parity with progress sync
- Add console logging for note/progress sync failures

* debug(hardcover): add runtime instrumentation for note sync

* feat(metadata): keep identifier stable and store ISBN separately

- Add dedicated metadata.isbn field
- Expose ISBN as its own editable field in book metadata
- Preserve identifier semantics for existing source IDs and hashes
- Route metadata auto-retrieval ISBN handling through the new field
- Prefer metadata.isbn for Hardcover matching

* fix(hardcover): avoid wasm sqlite for note mappings on web

- Store Hardcover note sync mappings in localStorage on web
- Keep sqlite-backed mappings for desktop/native environments
- Remove the web-only database dependency from manual note sync

* fix(hardcover): dedupe notes by payload hash across unstable note IDs

- Add payload-hash lookup in HardcoverSyncMapStore
- Reuse existing journal mapping when payload already synced
- Prevent duplicate insertions when note IDs change or duplicate locally

* fix(hardcover): avoid duplicate quote export when annotation note exists

- Detect excerpt+annotation pairs for the same highlight
- Skip standalone excerpt export when annotation has note text
- Keep annotation export as the single source of truth

* docs(hardcover): add consolidated change summary for review

* fix(hardcover): suppress excerpt export by CFI when annotation note exists

* fix(hardcover): suppress empty-note annotation duplicates when note exists

* fix(hardcover): deduplicate notes by text and cfi base node

* refactor(hardcover): optimize sync performance, add rate limiting and clean up debug tools

* chore: remove dev-only change log from main

* test(hardcover): add unit tests for sync mapping and client logic

* chore: custom deployment and UI fixes

* fix(hardcover): use timestamptz for accurate annotation time

* fix(hardcover): use date scalar and RFC 3339 formatting for journal entries

* Revert "chore: custom deployment and UI fixes"

This reverts commit 0329aba7129d1e1ebf2c663804b8fba9a9f87b91.

* Fix hardcover progress dates and surface imported ISBNs

* Fix Hardcover currently reading sync

* fix(hardcover): avoid promoting note sync status

* style(hardcover): apply prettier formatting

* test(hardcover): fix strict TypeScript assertions

* test(hardcover): harden sync regression coverage

* test(hardcover): fix lint and formatting regressions

* fix(hardcover): narrow note dedupe range matching

* refactor(hardcover): extract note dedupe helpers

* refactor(isbn): extract metadata normalization helpers

* feat(hardcover): improve synced quote formatting
2026-04-03 09:06:43 +02:00
Mohammed Efaz 888f4afde9 fix: preserve paragraph mode reading layouts and other UI/UX fixes (#3730)
* fix: paragraph mode

* test: paragraph mode

* test: remove paragraph mode

* fix: paragraph utils

* fix: paragraph hook

* fix: paragraph overlay

* fix: paragraph bar

* fix: paragraph control

* fix: paragraph shortcuts

* test: paragraph utils

* test: paragraph hook

* test: paragraph overlay

* test: paragraph shortcuts

* fix: paragraph overlay

* test: paragraph mode

* test: shortcuts

* test: remove overlay

* test: remove hook

* test: remove utils

* fix: paragraph overlay

* fix: paragraph overlay

* feat: paragraph overlay

* fix: vertical container sizing

* test: paragraph container

* fix: paragraph animation

* fix: paragraph text animation

* fix: remove container morph
2026-04-02 20:56:38 +02:00
Lex Moulton c9647276b1 feat(rsvp): progress bar per chapter, speed selector dropdown, and UX improvements (#3723)
* fix(rsvp): rename pause setting to punctuation delay for clarity

* fix(rsvp): update chapter header as user crosses TOC sections

* fix(rsvp): stop playback at end of book instead of restarting last chapter

* feat(rsvp): convert WPM badge to speed selector dropdown

* feat(rsvp): scroll active chapter to center when chapter dropdown opens

* fix(rsvp): show correct chapter name in header instead of "Select Chapter"

* fix(rsvp): start from selected chapter when switching via dropdown

* fix(rsvp): restore saved position when resuming from a different section

* fix(rsvp): remove shrink animation from header buttons on click

* refactor(rsvp): process one spine section at a time, greadtly reducing complexity

* refactor(rsvp): remove dead state and derive progress from currentIndex

* feat(rsvp): allow pausing during countdown

* fix(rsvp): use relocate event instead of fixed 500ms delay for chapter transitions

* fix(rsvp): persist WPM and punctuation pause settings across sessions

* fix(rsvp): prefix unused bookKey field with underscore to satisfy lint

* Revert "fix(rsvp): prefix unused bookKey field with underscore to satisfy lint"

This reverts commit 7b3a34813f0c3771e9af8d00c7c7dc77c8db161c.

* fix(rsvp): remove unused bookKey field from RSVPController

* feat(rsvp): make progress bar draggable

* fix: revert settings.json changes

* fix(rsvp): restore genuinely useful comments

* i18n: update translations

---------

Co-authored-by: Huang Xin <chrox.huang@gmail.com>
2026-04-02 03:31:58 +02:00
Mohammed Efaz 9ecb9b24d2 feat: make reading ruler selection and step navigation coherent (#3722)
* refactor(reader): extract reading ruler math helpers

* fix(reader): keep text selectable inside reading ruler

* feat(reader): route taps to ruler step navigation

* feat(reader): route keyboard navigation to ruler steps

* fix(reader): animate ruler mask and frame together

* fix(reader): preserve drag anchor for ruler handles

* fix(reader): fall back to page turns at ruler edges
2026-04-01 18:59:44 +02:00
Huang Xin 74401fc1bb fix(library): always sort series books by index ascending, closes #3709 (#3717)
* fix(library): always sort series books by index ascending, closes #3709

When grouping by series, the sort direction (asc/desc) was applied to
within-series book sorting, causing books to appear in reverse series
index order when the library was sorted descending. Now series index
sort is always ascending (1, 2, 3…) regardless of the global sort
direction. Also sort series groups by name when "Sort by Series" is
selected instead of falling back to updatedAt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(library): skip merge sort when inside a series group

The allItems.sort at the end of sortedBookshelfItems was re-sorting
books using the regular bookSorter (e.g. Date Read), which overrode
the within-group sort that correctly prioritized series index. Now
when inside a group, the already-sorted books are returned directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 14:01:48 +02:00
Huang Xin 0e516f6e56 chore(test): add unit tests and enforce dash-case naming for test files (#3715)
Add ~290 new unit tests covering utils (lru, diff, css, a11y, walk,
usage, txt-worker), services (EdgeTTSClient, transformers), and
suppress noisy console output across all test files. Rename 27
camelCase test files to dash-case for consistency.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 09:14:00 +02:00
Huang Xin b71b246601 feat(settings): add TTS settings tab and highlight opacity, closes #3661 (#3712)
Add a new TTS tab in settings with media metadata update frequency control
(sentence/paragraph/chapter) to reduce Bluetooth notification spam, and move
TTS highlight settings from Color tab to the new TTS tab. Also add a highlight
opacity setting with live preview in the Color tab.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 06:35:26 +02:00
Huang Xin 94843902ac fix(annotations): fix all annotations grouped under last chapter for fragment-href TOCs, closes #3688 (#3706)
When TOC entries use fragment-suffixed hrefs (e.g. ch01.xhtml#ch01),
the sectionsMap lookup matched subitems with cfi: undefined instead of
parent sections with valid CFIs. This caused findTocItemBS to map every
annotation to the last TOC entry. Now skip subitems lacking a CFI and
fall back to the base section.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 17:56:23 +02:00
Huang Xin f67930feb1 fix(opds): fix Copyparty books showing as "Untitled" in mixed feeds, closes #3667 (#3705) 2026-03-31 17:35:14 +02:00
Huang Xin e68dedd10d fix(layout): fix primary view detection on fractional DPR devices, closes #3681 (#3701) 2026-03-31 15:04:02 +02:00
Huang Xin 956c71cd7b chore: migrate from ESLint to Biome for linting (#3694)
Replace ESLint with Biome for ~14x faster linting (~360ms vs ~5s).

- Add biome.json with rules matching ESLint parity (Next.js, a11y,
  TypeScript, unused vars/imports)
- Remove eslint, @typescript-eslint/*, eslint-config-next,
  eslint-plugin-jsx-a11y, @eslint/* from deps
- Remove eslint.config.mjs
- Update lint script to: tsgo --noEmit && biome check .
- Fix 11 real code issues caught by Biome (banned types, explicit any,
  unsafe finally, unreachable code, shadowed names)
- Disable Biome formatter (Prettier stays for Tailwind class sorting)

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 16:25:04 +02:00
Huang Xin ec26ef4f29 fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B (#3691)
* fix(shortcuts): change bookmark shortcut from Ctrl+D to Ctrl+B, closes #3675

Ctrl+D was bound to both Toggle Bookmark (General) and Dictionary
Lookup (Selection). When text was selected and Ctrl+D pressed, both
actions fired — opening the dictionary AND adding an unwanted bookmark.

Changed bookmark to Ctrl+B/Cmd+B to resolve the conflict. Added a
unit test that detects identical keybinding lists across actions to
prevent this class of bug in the future.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* i18n: mark shortcut section names for translation

Wrap SHORTCUT_SECTIONS values with stubTranslation() so i18next-scanner
picks them up. Translate the 4 new keys (General, Text to Speech, Zoom,
Window) across all 29 locales.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 15:35:40 +02:00
Huang Xin 797fe9c604 fix(layout): fixed infinite expand calls and freeze in the paginator, closes #3683 (#3690) 2026-03-30 14:50:59 +02:00
Huang Xin 966f5e2acd fix(opds): fixed image download from ODPS server on the web, closes #3649 (#3658) 2026-03-27 13:21:52 +01:00
Huang Xin 3d4d1482aa feat: add keyboard shortcuts help dialog (#3653)
Add a keyboard shortcuts help dialog toggled with '?' that displays all
shortcuts grouped by section with platform-appropriate key rendering.

Restructure DEFAULT_SHORTCUTS to include i18n descriptions and section
metadata. Translate 37 new keys across 29 locales.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 14:59:38 +08:00
Huang Xin 5f897f648f feat(tts): add shortcuts to navigate and play/pause in TTS mode, closes #3620 (#3651) 2026-03-27 06:39:17 +01:00
Huang Xin 1936136596 fix: resolve various tracked exceptions in ph (#3584)
* fix: handle synced bookmarks without cfi

* chore: clean up some exceptions in ph
2026-03-22 08:16:38 +01:00
Huang Xin e0cf7e8d9f fix: handle number input value clip in settings on mobile devices (#3582) 2026-03-22 05:26:21 +01:00
Huang Xin 76b239f382 feat(koplugin): add support for annotation sync (#3579)
Add bidirectional annotation/highlight sync between KOReader and Readest:

- Add xpointer0/xpointer1 fields to BookNote and DBBookNote types for
  KOReader XPointer positions alongside Readest's CFI format
- Extend transform layer to pass through xpointer fields to/from DB
- Convert CFI→XPointer on push and XPointer→CFI on pull in useNotesSync,
  discarding notes that fail conversion
- Support KOReader's text()[K].N indexed text node format in xcfi.ts for
  paragraphs with inline elements (e.g. <a> page anchors)
- Generate KOReader-compatible XPointers: text().N for single text nodes,
  text()[K].N only when multiple direct text nodes exist
- Skip cfi-inert elements (injected by Readest at runtime) in XPointer
  path building and resolution
- Map highlight colors between KOReader and Readest color systems
- Implement KOReader plugin annotation push/pull with deterministic IDs,
  auto-sync on document open/close, and UIManager refresh on pull
- Refactor koplugin into focused modules: syncauth, syncconfig,
  syncannotations, selfupdate

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 16:43:51 +01:00
Huang Xin 0e8605d298 feat(reader): import Foliate annotations on book open (Linux only), closes #2180 (#3574)
* feat(reader): import Foliate annotations on book open (Linux only), closes #2180

Automatically imports annotations, bookmarks, and reading progress from
Foliate's data files when opening a book on Linux. Uses foliateImportedAt
flag to prevent re-importing on subsequent opens.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(annotation): move Foliate import into annotation provider pattern

Restructure annotation import as a multi-provider service following the
translators pattern. Foliate becomes a provider under
services/annotation/providers/, making it easy to add more import sources.
Each provider controls its own availability check and skip-if-imported guard.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 05:04:46 +01:00
Huang Xin 7445d5befe feat(library): add batch refresh metadata option, closes #3294 (#3573)
Add a "Refresh Metadata" option under Advanced Settings that re-parses
book files to update metadata (series info, language, etc.) for books
imported before these fields were supported.

- Add refreshBookMetadata() in bookService that opens a book file,
  re-parses with DocumentLoader, and updates metadata/metaHash/series
  without touching updatedAt or user-edited fields
- Add menu item in SettingsMenu with progress display
- Add unit tests for single-book metadata refresh
- Translate new i18n strings across all 29 locales

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:32:09 +01:00
Huang Xin e41bcfbac9 fix(txt): fix chapter detection for bare numbered headings, closes #3570 (#3572)
Three bugs in createChapterRegexps for English txt-to-epub conversion:

1. numberPattern had a capturing group (\d+|...) that leaked single
   digits into split() results instead of chapter titles. Changed to
   non-capturing (?:\d+|...).

2. combinedPattern wrapped the heading in (?:...) so split() consumed
   the title without returning it. Changed to (...) capturing group,
   matching the Chinese regex structure.

3. The prefix (?:^|\n|\s) allowed matching Chapter/Section after any
   whitespace, causing mid-sentence false positives. Changed to
   (?:^|\n) for line-start only.

Added a second-tier regex for bare numbered headings (e.g. "1.1The
Elements of Programming", "1Building Abstractions") commonly found
in academic texts. Dotted numbers allow optional space before title;
single bare digits require immediate title to avoid footnote matches.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:00:33 +01:00
Huang Xin 91bc4ddec7 feat(library): backup to and restore from a zip file (#3571) 2026-03-20 18:27:52 +01:00
Huang Xin 1f4f5f8a6d feat(annotator): responsive layout for the loupe (#3568) 2026-03-19 17:54:24 +01:00
Huang Xin eab83c6d3f feat(annotator): show the loupe when selecting text in instant annotation, closes #3539 (#3565) 2026-03-19 15:10:33 +01:00
Huang Xin 1f7483b911 feat: scroll to the nearest item in the search results or annotation lists (#3555) 2026-03-17 16:01:56 +01:00
Huang Xin 1af55e24da feat(epub): support continuous scroll and spread layout for EPUBs, closes #3419 and closes #1745 (#3546) 2026-03-16 18:24:07 +01:00
Huang Xin f7b2a2432c fix(export): apply block quote syntax to every line in annotation export, closes #3534 (#3536)
Add formatBlockQuote utility and blockquote nunjucks filter so both
default and custom template exports prefix every line with `>`.
Document all available formatters in the custom template help panel.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 15:23:17 +01:00
Huang Xin db3dee025b feat(booshelf): dedupe books with the same meta hash (#3535) 2026-03-14 15:14:22 +01:00
Huang Xin 8274c6bc4f feat(node): refactor appService into focused service modules and add app service for Node runtime (#3530)
This also closes #3431.
2026-03-13 17:51:35 +01:00
Huang Xin f9a3559086 fix(library): improve sorting and grouping interaction, closes #3517 (#3524)
- Sort author groups by last name instead of first name when sorting by author
- Sort series groups by book author instead of series name when sorting by author
- Place ungrouped books before custom groups instead of mixing them together

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 16:59:50 +01:00
Huang Xin 7a605a357a feat(pdf): support pitch to zoom and scroll mode for PDFs, closes #3461 (#3520) 2026-03-12 16:07:55 +01:00
Huang Xin 64a71e25e4 fix(layout): make horizontal scroll bar visible in fixed-layout EPUB, closes #3506 (#3512)
And fix some text not shown in fixed-layout EPUB.
2026-03-11 15:03:05 +01:00
Huang Xin 907b672313 fix(a11y): improve TOC screen reader accessibility for NVDA, closes #3477 (#3509) 2026-03-11 14:30:01 +08:00
Huang Xin 5646e0cfb5 fix(txt): add stream() to RemoteFile to fix large TXT import on desktop, closes #3495 (#3502)
RemoteFile (used on all desktop platforms) extended File([]) with empty
data and overrode slice(), text(), arrayBuffer() but not stream(). The
large file path (>8MB) introduced in #3320 uses file.stream() to read
content incrementally, which returned empty data from the base File
class, causing "No chapters detected" for large TXT files.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 19:00:44 +01:00
Huang Xin 8850e6c00f feat(pdf): support TTS and annotation on PDFs, closes #2149 & #3462 (#3493)
* chore: bump jsdom to the latest version

* feat(pdf): support TTS and annotation on PDFs, closes #2149 & closes #3462
2026-03-09 10:28:19 +01:00
Huang Xin 54bc1514df feat(database): add platform-agnostic schema migration system (#3485) 2026-03-06 20:07:26 +08:00
Huang Xin 97cab2d70b feat(database): support turso fts in tauri apps (#3484) 2026-03-05 21:00:15 +01:00
Huang Xin 13588b4a65 chore(testing): add Tauri integration tests and E2E test infrastructure (#3483)
Set up WebDriver-based testing for the Tauri app with two tiers:
- Vitest browser-mode tests (*.tauri.test.ts) running inside the Tauri WebView
  for plugin IPC testing (libsql, smoke tests)
- WDIO E2E tests (*.e2e.ts) for UI-level interaction testing

Key changes:
- Add webdriver Cargo feature gating tauri-plugin-webdriver
- Add runtime capability for remote URLs (webdriver builds only)
- Add vitest.tauri.config.mts and wdio.conf.ts connecting to embedded
  WebDriver server on port 4445
- Add shared tauri-invoke helper for IPC from Vitest iframe context
- Add testing documentation in docs/testing.md
2026-03-05 19:14:01 +01:00
Huang Xin 1e9bd1d821 chore(database): unit testing and feature detect for fts and vector search (#3476) 2026-03-05 07:41:16 +01:00
Huang Xin 5273ef75dc feat(database): add database service abstraction with libsql/turso backend (#3472) 2026-03-05 02:38:23 +08:00
Huang Xin 35ade2c855 fix(tts): handle documents without lang attribute or XHTML namespace, closes #3291 (#3456) 2026-03-03 10:35:33 +01:00
Huang Xin 94e761f681 fix(txt): more robust chapter extractor for TXT (#3446) 2026-03-02 18:20:50 +01:00
Huang Xin c533da498d feat(annotator): add page number for annotations, closes #3082 (#3405)
* feat(annotator): add page number in annotation

* feat: add page number for annotations, closes #3082
2026-02-28 08:08:56 +01:00