Commit Graph

5 Commits

Author SHA1 Message Date
Huang Xin 67c22c770b feat(reader): Share intent + customizable annotation toolbar (#4014) (#4570)
* docs(spec): annotation Share tool + customizable toolbar (#4014)

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

* docs(plan): implementation plan for Share tool + customizable toolbar (#4014)

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

* feat(annotator): add 'share' annotation tool type and button (#4014)

* feat(annotator): add pure toolbar order/visibility helpers (#4014)

* feat(annotator): add annotationToolbarItems view setting (#4014)

* feat(annotator): add shareSelectedText ladder helper (#4014)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(annotator): render Share tool and honor toolbar order in selection popup (#4014)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(settings): add drag-and-drop annotation toolbar customizer (#4014)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(settings): open the toolbar customizer from the Behavior panel (#4014)

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

* chore(i18n): extract and translate annotation share/toolbar strings (#4014)

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

* refactor(annotator): extract canShareText helper, preserve hidden Share on cross-platform edit (#4014)

Addresses final-review findings: de-duplicate the triplicated canShare
definition into share.ts::canShareText, trim ShareCapableService to the
fields actually read, and stop the toolbar customizer from dropping a
synced 'share' tool when edited on a non-share-capable device.

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

* feat(settings): WYSIWYG drag-and-drop toolbar customizer (#4014)

Rework the customizer per live testing:
- Render 'In toolbar' as a faithful, content-width, start-aligned preview of
  the real selection popup (gray bar, icon-only buttons); 'Available' tools
  show as labeled chips.
- Multi-container dnd-kit pattern: in-place dragging (no DragOverlay, which a
  transformed modal offsets), pointerWithin collision so empty zones accept
  drops, live onDragOver reparent, itemsRef to dodge dnd-kit's drag-start
  handler-capture stale closure.
- Add 'Add all' (canonical predefined order) and 'Clear all' shortcuts.
- Align zone labels with the SubPageHeader breadcrumb.
- Empty toolbar now suppresses the selection popup entirely (no empty bar),
  while still allowing highlight-edit/notes popups.

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

* chore(i18n): translate Add all / Clear all toolbar shortcuts (#4014)

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

* fix(annotator): size selection popup to visible tool count (#4014)

With the customizable toolbar a fixed-width popup looked sparse for a 2-3
tool toolbar (buttons spread to the corners). Size the popup to the number
of visible tools (responsive) capped at the previous max; annotated
selections keep the max width since they show highlight options / notes.

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

* fix(settings): reword empty-toolbar hint to 'No tools, drag one here' (#4014)

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

* test(annotator): render default tools (not Share) in popup layout screenshot (#4014)

The visual regression test rendered every annotationToolButtons entry, so
adding the Share tool shifted the toolbar to 9 buttons and broke the
baselines. Share is hidden by default (added via Customize Toolbar), so the
popup screenshot should mirror the default-enabled set — filter to
DEFAULT_ANNOTATION_TOOLBAR_ITEMS, keeping the existing baselines valid.

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

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 14:11:59 +02:00
Huang Xin 5a0a70a30a feat(reader): custom dictionaries (StarDict + MDict) (#4012)
* feat(reader): custom dictionaries (StarDict + MDict)

Adds a pluggable dictionary provider system. Built-in Wiktionary +
Wikipedia (extracted from the legacy single-popup model into a tabbed
shell) plus user-importable StarDict (.ifo/.idx/.dict.dz/.syn) and MDict
(.mdx/.mdd) bundles.

Settings → Language → Dictionaries: import / enable / drag-reorder /
delete (delete-mode toggle mirrors CustomFonts). Drag uses @dnd-kit with
pointer/touch/keyboard sensors. Reader popup: tabbed UI, per-tab lookup
history, scroll-aware back button, last-active tab persists. Tabs grow
to natural width up to a cap, truncate with ellipsis when crowded; phantom
bold layer prevents layout shift on focus.

StarDict reader is self-contained (replaces unused foliate-js/dict.js),
with lazy random-access binary search on .idx + .syn (~420 KB Int32Array
of byte offsets vs ~10 MB of parsed JS objects), lazy DictZip chunk
decompression via fflate streaming Inflate (cmudict/eng-nld both
chunked), and an optional .idx.offsets sidecar generated at import to
skip the init scan. Cmudict 105K-entry init drops from ~10 MB heap and
2 MB IO to ~1.7 MB heap and ~500 KB IO.

MDict uses the readest/js-mdict fork (added as a submodule, consumed via
tsconfig paths so deps stay out of readest's pnpm-lock) which adds a
browser-friendly BlobScanner reading via blob.slice(...).arrayBuffer()
— slices are lazy when the Blob is Readest's NativeFile / RemoteFile.
encrypt=2 (key-info-only) MDX is fully supported via ripemd128-based
mdxDecrypt; encrypt=1 (record-block, needs user passcode) surfaces as
unsupported.

Wikipedia annotation tool removed (Wikipedia is now a tab inside the
unified popup); legacy WiktionaryPopup / WikipediaPopup deleted. Stale
annotationQuickAction === 'wikipedia' coerced to 'dictionary' on settings
load. iOS-friendly external links: skip target="_blank" on Tauri to
avoid the WebView's "open externally" path triggering the shell scope
error; the popup's container click handler routes through openUrl.

i18n: 939 strings translated across 31 locales (30 base keys + CLDR
plural forms for ar/he/sl/pl/ru/uk/ro/it/pt/fr/es).

Test fixtures bundled: cmudict (StarDict, 105K entries), eng-nld
(StarDict, smaller), and a Longman Phrasal Verbs MDX (encrypt=2).
3396 unit tests pass.

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

* fix(stardict): resolve fflate from js-mdict source for vitest + Next

js-mdict is consumed as TypeScript source via tsconfig paths from
packages/js-mdict/src/. Its sources `import 'fflate'` directly, but
fflate is only installed under apps/readest-app/node_modules — so
vite's import-analysis (and Next/Turbopack's resolver) can't find
fflate when it walks up from the redirected js-mdict source location.
CI's fresh checkout exposes this; locally a leftover
packages/js-mdict/node_modules/fflate from the old workspace setup
masked it.

Pin fflate resolution to apps/readest-app/node_modules/fflate in:
- vitest.config.mts (Vite alias)
- next.config.mjs (webpack alias + Turbopack resolveAlias — Turbopack
  rejects absolute paths so use a project-relative form)
- tsconfig.json (paths entry so tsgo / Biome see it)

Verified by deleting packages/js-mdict/node_modules locally and
re-running pnpm test (3396 pass), pnpm lint (clean), and both
pnpm build-web and a tauri-platform Next build (clean).

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

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:16:36 +02:00
Huang Xin 41b5e92563 feat(annotator): support instant copy operation for selected text, closes #3828 (#3854) 2026-04-13 06:00:05 +02:00
Huang Xin a5e09e8454 feat(search): add search results navigation bar, closes #1183 (#2842)
Add a floating navigation component that appears when search results exist.
The component includes:
   - Top bar: displays search term and current section with TOC and close buttons
   - Bottom bar: search results, previous, and next navigation buttons
   - Page-based navigation using isCfiInLocation to skip between pages with results
2026-01-03 08:10:23 +01:00
Huang Xin a42897ec5c feat(annotator): support quick actions for text selection, closes #2505 (#2813) 2025-12-30 10:32:01 +01:00