5a0a70a30a
* 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>
46 lines
1.5 KiB
TypeScript
46 lines
1.5 KiB
TypeScript
import path from 'path';
|
|
import { defineConfig } from 'vitest/config';
|
|
import react from '@vitejs/plugin-react';
|
|
import tsconfigPaths from 'vite-tsconfig-paths';
|
|
|
|
export default defineConfig({
|
|
plugins: [tsconfigPaths(), react()],
|
|
resolve: {
|
|
alias: {
|
|
// The @pdfjs alias from tsconfig only resolves within the app's own
|
|
// source files. foliate-js/pdf.js lives outside that scope, so Vite
|
|
// needs an explicit alias to find the vendored pdfjs build.
|
|
'@pdfjs': path.resolve(__dirname, 'public/vendor/pdfjs'),
|
|
// `js-mdict` is consumed via tsconfig paths from `packages/js-mdict/src/`.
|
|
// Its sources `import 'fflate'` directly — without an alias, vite's
|
|
// import-analysis walks up from the redirected file location and fails
|
|
// to find fflate (it's installed only in this app's node_modules).
|
|
// Pin all `fflate` resolutions to the app's copy to keep js-mdict
|
|
// self-contained at the source-tree level.
|
|
fflate: path.resolve(__dirname, 'node_modules/fflate'),
|
|
},
|
|
},
|
|
test: {
|
|
environment: 'jsdom',
|
|
setupFiles: ['./vitest.setup.ts'],
|
|
exclude: [
|
|
'**/node_modules/**',
|
|
'**/dist/**',
|
|
'**/.claude/**',
|
|
'**/*.browser.test.ts',
|
|
'**/*.browser.test.tsx',
|
|
'**/*.tauri.test.ts',
|
|
],
|
|
coverage: {
|
|
provider: 'v8',
|
|
reporter: ['text', 'text-summary'],
|
|
include: ['src/**/*.{ts,tsx}'],
|
|
exclude: [
|
|
'src/**/*.d.ts',
|
|
'src/**/__tests__/**',
|
|
'src/**/test/**',
|
|
],
|
|
},
|
|
},
|
|
});
|