5bbc5ceccc
* feat(ai): add dependencies * chore: bump zod version to default version * feat(ai): define types and model constants * feat(ai): ollama provider for local LLM * feat(ai): implement openrouter provider for cloud models * feat(settings): register ai settings panel in global dialog * refactor(ai): expose provider factory and service layer entry point * test(ai): add unit tests for the providers * test(ai): add unit tests for the providers * feat(ai): settings panel for ai configurations * refactor(ai): rewrite aipanel with autosave and greyed out disabled state * fix: remove unused onClose prop from aipanel * test(ai): update mock data * refactor(ai): remove models * refactor: use centralised defaults in system defaults * chore(ai): remove comments * fix(ai): merge default ai settings on load to prevent undefined values * refactor(ai): rewrite settings panel with autosave and model input * feat(ai): add ai tab with simplified highlighting * feat(sidebar): render AIAssistant for ai tab * feat(ai): add chat UI * feat(ai); add chat service with RAG context * feat(ai): temp debug logger * feat(ai): add RAG service * feat(ai): add text chunking utility * feat(ai): add structured method * feat(ai): add chatstructured method * feat(ai): add rag types nd structured output schema * feat(ai): add aistore, indexdb, bm25 * fix: update lock file * feat(ai): update types for AI SDK v5 * feat(ai): add placeholder gateway model constants * refactor(ai): update OllamaProvider for AI SDK * feat(ai): add native gateway provider * refactor(ai): update provider exports * refactor(ai): use streamText from AI SDK * refactor(ai): use embed from AI sdk * refactor(ai): update provider factory exports * feat(ai): add AI Elements and shadcn components * config: add shadcn component config * deps: add AI SDK and AI Elements dependencies * config: add ai packages to transpilePackages * refactor(ai): remove OpenRouterProvider and old tests * feat(ai):add assistant-ui components * feat(ai): add TauriChatAdapter for assistant-ui runtime * refactor(ai): remove ai-elements components * dep(ai): install assistant-ui and update next config * chore(ai): export adapters from service index * feat(ui): enhance ui components for assistant integration * feat(settings): migrate ai settings to gateway * feat(sidebar): integrate assistant-ui * feat: add ai settings toggle to sidebar content * feat: conditionally show ai tab in sidebar navigation * feat: update ai model constants for cheaper options * feat: add gateway provider with proxied embedding * feat: add timeouts to ollama provider health checks * feat: add retry logic to rag service embeddings * feat: add error recovery to ai store * feat: add ai feature tests * feat: add ai api endpoints * feat: add proxied gateway embedding provider * feat: add ai runtime utilities * feat: add ai retry utilities * feat: add tauri env example template * feat: add web env example template * chore: add env * feat(ai): update models and pricing, remove GLM-4.7-FlashX * feat(ai): improve system prompt with official headings and no numeric citations * feat(ai): optimize system prompt for tauri chat * feat(ui): refine ai chat UI and relocate sources * feat(ui): update ai settings panel with model pricing and custom model support * feat(ai): add custom model support to ai settings * test(ai): update constants tests for removed model * feat(api): implement ai chat proxy route * feat(api): implement ai embedding proxy route * feat(ai): implement ai gateway health check and proxy logic * feat(ai): simplify proxied embedding provider * feat(ui): improve markdown text rendering * feat(ui): add input group component * test(ai): update ai provider tests * feat(ai): add pageNumber to text chunk schema * feat(ai): implement page-based chunking with 1500 char formula * feat(ai): bump db to v2 and add store reset migration * feat(ai): transition rag pipeline to page level spoiler filtering * feat(ai): overhaul readest persona and antijailbreak prompt * feat(ai): update tauri adapter for page tracking and persona * chore(ai): export aiStore and logger from core index * feat(reader): integrate page tracking and manual index reset * feat(ui): add re-index action and reset logic to chat * chore: sync pnpm lockfile with ai dependencies * feat(utils): add browser-safe file utilities for web builds * refactor(utils): use dynamic tauri fs import to prevent web crashes * refactor(services): defer osType call to init() for web compatibility * refactor(services): import RemoteFile from file.web * refactor(services): import ClosableFile from file.web * fix(libs): cast Entry to any for getData access * fix(annotator): cast Overlayer to any for bubble access * refactor(ai): replace SparklesIcon with BookOpenIcon for index prompt * test(ai): add pageNumber to TextChunk mocks * test(ai): fix chunkSection signature in tests * chore: update files * fix(ai): prevent useLocalRuntime crash when adapter is null * refactor: optimize annotator overlay drawing * feat: stabilize AI assistant runtime and adapter * refactor: improve document zip loader type safety * feat: update tauri chat adapter for dynamic options * fix: restore architecture comments and refine platform properties * build: update lockfile with assistant-ui patch * fix(library): patch @assistant-ui/react for runtime initialization * build: update dependencies in readest-app * build: update root dependencies and patch configuration * fix(ai): patch @assistant-ui/react for thread deletion and runtime init * fix(ai): update assistant-ui patch with dist guards and deletion fallback * build: sync lockfile with assistant-ui patch updates * chore(env): update .gitignore by removing .env files from it * chore(env): update .gitignore by adding .env.local * chore(env): update .gitignore by adding .env*.local * fix: restore static osType import * chore: sync submodules with upstream/main * refactor: remove redundant file.web module and revert import * chore: update pnpm-lock.yaml * refactor: revert guards * refactor; remove deprecated codes and extract prompts.ts * refactor(ai): remove unused ragservice exports * refactor: remove unused ollama and embedding models * refactor: remove unused type * test: remove test for the now deleted constants * refactor: remove unused export * style: fix ui component formatting * style: fix core and style file formatting * test: fix broken ai provider import * fix: typescript error * fix: add eslint disable command * fix(deps): remove unused ai sdk provider util after v6 ai sdk migration * fix(patch): add lookbehind regex patch * feat(dep): upgrade vercel ai sdk to v6 and ai-sdk-ollama to v3 * chore: update lockfile for vercel ai sdk v6 * refactor(ai): remove EmbeddingModel generic for ai sdk v6 * refactor(ai): remove EmbeddingModel generic for ai sdk v6 * test(ai): update mock to use embeddingModel * fix(patch): add lookbehind regex patch for email autolinks in markdown * refactor(ai): use ai sdk v6 syntax * fix: prettier formatting * chore: revert cargo.lock * fix(ai): update proxied embedding model to v3 spec * feat(ai): add aiconversation types for chat persistence * feat(ai): add conversation/message indexeddb and crud operations * feat(ai): create aiChatStore zustand store for chat state management * feat(notebook): add notebookactivetab state for Notes/AI * refactor(ai): refine conversation and message types for persistence * feat(types): add notebookActiveTab to ReadSettings type * chore: update deps * feat: add notebookactive tab default value * feat: add hook for ai chat * feat: update left side panel with history/chat icon * feat: integrate ChatHistoryView into sidebar content * feat: create UI for managing AI chat history * feat: implement persistent history with assistant-ui adapter * feat: create tab navigation component for notes and AI * feat: add tab navigation and AI assistant view * feat: update header to display active tab title * fix: formatting * feat: remove title and update new chat button * fix: formatting * fix: revert tooltip and styling * feat: implement cross-platform ask dialog bridge * feat(ai): preserve history during ui clear & use native dialogs * fix: align notebook navigation height with sidebar tabs * fix(ai): add missing dependency to handleDeleteConversation hook * docs: update PROJECT.md with session highlights * chore: delete projectmd * chore: update package.json and lock file * chore: update package.json * chore: remove patch * chore: upgrade react types to 19 and show ai features only in development mode for now --------- Co-authored-by: Huang Xin <chrox.huang@gmail.com>
791 lines
16 KiB
TypeScript
791 lines
16 KiB
TypeScript
import {
|
|
AnnotatorConfig,
|
|
BookFont,
|
|
BookLanguage,
|
|
BookLayout,
|
|
BookSearchConfig,
|
|
BookStyle,
|
|
HighlightColor,
|
|
NoteExportConfig,
|
|
ScreenConfig,
|
|
TranslatorConfig,
|
|
TTSConfig,
|
|
ViewConfig,
|
|
ViewSettings,
|
|
} from '@/types/book';
|
|
import { KOSyncSettings, ReadSettings, SystemSettings } from '@/types/settings';
|
|
import { UserStorageQuota, UserDailyTranslationQuota } from '@/types/quota';
|
|
import { getDefaultMaxBlockSize, getDefaultMaxInlineSize } from '@/utils/config';
|
|
import { stubTranslation as _ } from '@/utils/misc';
|
|
import { DEFAULT_AI_SETTINGS } from './ai/constants';
|
|
|
|
export const DATA_SUBDIR = 'Readest';
|
|
export const LOCAL_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`;
|
|
export const CLOUD_BOOKS_SUBDIR = `${DATA_SUBDIR}/Books`;
|
|
export const LOCAL_FONTS_SUBDIR = `${DATA_SUBDIR}/Fonts`;
|
|
export const LOCAL_IMAGES_SUBDIR = `${DATA_SUBDIR}/Images`;
|
|
|
|
export const SETTINGS_FILENAME = 'settings.json';
|
|
|
|
export const SUPPORTED_BOOK_EXTS = [
|
|
'epub',
|
|
'mobi',
|
|
'azw',
|
|
'azw3',
|
|
'fb2',
|
|
'zip',
|
|
'cbz',
|
|
'pdf',
|
|
'txt',
|
|
];
|
|
export const BOOK_ACCEPT_FORMATS = SUPPORTED_BOOK_EXTS.map((ext) => `.${ext}`).join(', ');
|
|
export const BOOK_UNGROUPED_NAME = '';
|
|
export const BOOK_UNGROUPED_ID = '';
|
|
|
|
export const SUPPORTED_IMAGE_EXTS = ['png', 'jpg', 'jpeg'];
|
|
export const IMAGE_ACCEPT_FORMATS = SUPPORTED_IMAGE_EXTS.map((ext) => `.${ext}`).join(', ');
|
|
|
|
export const DEFAULT_KOSYNC_SETTINGS = {
|
|
serverUrl: 'https://sync.koreader.rocks/', // https://kosync.ak-team.com:3042/
|
|
username: '',
|
|
userkey: '',
|
|
deviceId: '',
|
|
deviceName: '',
|
|
checksumMethod: 'binary',
|
|
strategy: 'prompt',
|
|
enabled: false,
|
|
} as KOSyncSettings;
|
|
|
|
export const DEFAULT_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
|
keepLogin: false,
|
|
autoUpload: true,
|
|
alwaysOnTop: false,
|
|
openBookInNewWindow: true,
|
|
alwaysShowStatusBar: false,
|
|
alwaysInForeground: false,
|
|
autoCheckUpdates: true,
|
|
screenWakeLock: false,
|
|
screenBrightness: -1, // -1~100, -1 for system default
|
|
autoScreenBrightness: true,
|
|
openLastBooks: false,
|
|
lastOpenBooks: [],
|
|
autoImportBooksOnOpen: false,
|
|
telemetryEnabled: true,
|
|
discordRichPresenceEnabled: false,
|
|
libraryViewMode: 'grid',
|
|
librarySortBy: 'updated',
|
|
librarySortAscending: false,
|
|
libraryCoverFit: 'crop',
|
|
libraryAutoColumns: true,
|
|
libraryColumns: 6,
|
|
|
|
kosync: DEFAULT_KOSYNC_SETTINGS,
|
|
aiSettings: DEFAULT_AI_SETTINGS,
|
|
|
|
lastSyncedAtBooks: 0,
|
|
lastSyncedAtConfigs: 0,
|
|
lastSyncedAtNotes: 0,
|
|
};
|
|
|
|
export const DEFAULT_MOBILE_SYSTEM_SETTINGS: Partial<SystemSettings> = {
|
|
libraryColumns: 3,
|
|
};
|
|
|
|
export const HIGHLIGHT_COLOR_HEX: Record<HighlightColor, string> = {
|
|
red: '#f87171', // red-400
|
|
yellow: '#facc15', // yellow-400
|
|
green: '#4ade80', // green-400
|
|
blue: '#60a5fa', // blue-400
|
|
violet: '#a78bfa', // violet-400
|
|
};
|
|
|
|
export const DEFAULT_READSETTINGS: ReadSettings = {
|
|
sideBarWidth: '15%',
|
|
isSideBarPinned: true,
|
|
notebookWidth: '25%',
|
|
isNotebookPinned: false,
|
|
notebookActiveTab: 'notes',
|
|
autohideCursor: true,
|
|
translationProvider: 'deepl',
|
|
translateTargetLang: 'EN',
|
|
|
|
customThemes: [],
|
|
highlightStyle: 'highlight',
|
|
highlightStyles: {
|
|
highlight: 'yellow',
|
|
underline: 'green',
|
|
squiggly: 'blue',
|
|
},
|
|
customHighlightColors: HIGHLIGHT_COLOR_HEX,
|
|
customTtsHighlightColors: [],
|
|
};
|
|
|
|
export const DEFAULT_MOBILE_READSETTINGS: Partial<ReadSettings> = {
|
|
sideBarWidth: '25%',
|
|
isSideBarPinned: false,
|
|
};
|
|
|
|
export const DEFAULT_BOOK_FONT: BookFont = {
|
|
serifFont: 'Bitter',
|
|
sansSerifFont: 'Roboto',
|
|
monospaceFont: 'Consolas',
|
|
defaultFont: 'Serif',
|
|
defaultCJKFont: 'LXGW WenKai GB Screen',
|
|
defaultFontSize: 16,
|
|
minimumFontSize: 8,
|
|
fontWeight: 400,
|
|
};
|
|
|
|
export const DEFAULT_BOOK_LAYOUT: BookLayout = {
|
|
marginTopPx: 44,
|
|
marginBottomPx: 44,
|
|
marginLeftPx: 16,
|
|
marginRightPx: 16,
|
|
compactMarginTopPx: 16,
|
|
compactMarginBottomPx: 16,
|
|
compactMarginLeftPx: 16,
|
|
compactMarginRightPx: 16,
|
|
gapPercent: 5,
|
|
scrolled: false,
|
|
disableClick: false,
|
|
fullscreenClickArea: false,
|
|
swapClickArea: false,
|
|
disableDoubleClick: false,
|
|
volumeKeysToFlip: false,
|
|
continuousScroll: false,
|
|
maxColumnCount: 2,
|
|
maxInlineSize: getDefaultMaxInlineSize(),
|
|
maxBlockSize: getDefaultMaxBlockSize(),
|
|
animated: false,
|
|
isEink: false,
|
|
writingMode: 'auto',
|
|
vertical: false,
|
|
rtl: false,
|
|
scrollingOverlap: 0,
|
|
allowScript: false,
|
|
};
|
|
|
|
export const DEFAULT_BOOK_LANGUAGE: BookLanguage = {
|
|
replaceQuotationMarks: true,
|
|
convertChineseVariant: 'none',
|
|
};
|
|
|
|
export const DEFAULT_BOOK_STYLE: BookStyle = {
|
|
zoomLevel: 100,
|
|
paragraphMargin: 0.6,
|
|
lineHeight: 1.4,
|
|
wordSpacing: 0,
|
|
letterSpacing: 0,
|
|
textIndent: 0,
|
|
fullJustification: true,
|
|
hyphenation: true,
|
|
invertImgColorInDark: false,
|
|
theme: 'light',
|
|
overrideFont: false,
|
|
overrideLayout: false,
|
|
overrideColor: false,
|
|
backgroundTextureId: 'none',
|
|
backgroundOpacity: 0.6,
|
|
backgroundSize: 'cover',
|
|
codeHighlighting: false,
|
|
codeLanguage: 'auto-detect',
|
|
userStylesheet: '',
|
|
userUIStylesheet: '',
|
|
|
|
zoomMode: 'fit-page',
|
|
spreadMode: 'auto',
|
|
keepCoverSpread: true,
|
|
};
|
|
|
|
export const DEFAULT_MOBILE_VIEW_SETTINGS: Partial<ViewSettings> = {
|
|
fullJustification: false,
|
|
animated: true,
|
|
defaultFont: 'Sans-serif',
|
|
marginBottomPx: 16,
|
|
disableDoubleClick: true,
|
|
spreadMode: 'none',
|
|
};
|
|
|
|
export const DEFAULT_CJK_VIEW_SETTINGS: Partial<ViewSettings> = {
|
|
fullJustification: true,
|
|
textIndent: 2,
|
|
paragraphMargin: 1,
|
|
lineHeight: 1.6,
|
|
};
|
|
|
|
export const DEFAULT_FIXED_LAYOUT_VIEW_SETTINGS: Partial<ViewSettings> = {
|
|
overrideColor: false,
|
|
};
|
|
|
|
export const DEFAULT_EINK_VIEW_SETTINGS: Partial<ViewSettings> = {
|
|
isEink: true,
|
|
animated: false,
|
|
volumeKeysToFlip: true,
|
|
};
|
|
|
|
export const DEFAULT_VIEW_CONFIG: ViewConfig = {
|
|
sideBarTab: 'toc',
|
|
uiLanguage: '',
|
|
sortedTOC: false,
|
|
|
|
doubleBorder: false,
|
|
borderColor: 'red',
|
|
|
|
showHeader: true,
|
|
showFooter: true,
|
|
showBarsOnScroll: false,
|
|
showRemainingTime: false,
|
|
showRemainingPages: false,
|
|
showProgressInfo: true,
|
|
tapToToggleFooter: false,
|
|
showMarginsOnScroll: false,
|
|
progressStyle: 'fraction',
|
|
progressInfoMode: 'all',
|
|
};
|
|
|
|
export const DEFAULT_TTS_CONFIG: TTSConfig = {
|
|
ttsRate: 1.3,
|
|
ttsVoice: '',
|
|
ttsLocation: '',
|
|
showTTSBar: false,
|
|
ttsHighlightOptions: { style: 'highlight', color: '#808080' },
|
|
};
|
|
|
|
export const DEFAULT_TRANSLATOR_CONFIG: TranslatorConfig = {
|
|
translationEnabled: false,
|
|
translationProvider: 'deepl',
|
|
translateTargetLang: '',
|
|
showTranslateSource: true,
|
|
ttsReadAloudText: 'both',
|
|
};
|
|
|
|
export const DEFAULT_NOTE_EXPORT_CONFIG: NoteExportConfig = {
|
|
includeTitle: true,
|
|
includeAuthor: true,
|
|
includeDate: true,
|
|
includeChapterTitles: true,
|
|
includeQuotes: true,
|
|
includeNotes: true,
|
|
includeTimestamp: false,
|
|
includeChapterSeparator: false,
|
|
noteSeparator: '\n\n',
|
|
useCustomTemplate: false,
|
|
customTemplate: '',
|
|
};
|
|
|
|
export const DEFAULT_ANNOTATOR_CONFIG: AnnotatorConfig = {
|
|
enableAnnotationQuickActions: true,
|
|
annotationQuickAction: null,
|
|
copyToNotebook: false,
|
|
noteExportConfig: DEFAULT_NOTE_EXPORT_CONFIG,
|
|
};
|
|
|
|
export const DEFAULT_SCREEN_CONFIG: ScreenConfig = {
|
|
screenOrientation: 'auto',
|
|
};
|
|
|
|
export const DEFAULT_BOOK_SEARCH_CONFIG: BookSearchConfig = {
|
|
scope: 'book',
|
|
matchCase: false,
|
|
matchWholeWords: false,
|
|
matchDiacritics: false,
|
|
};
|
|
|
|
export const SYSTEM_SETTINGS_VERSION = 1;
|
|
|
|
export const SERIF_FONTS = [
|
|
'Bitter',
|
|
'Literata',
|
|
'Merriweather',
|
|
'Roboto Slab',
|
|
'Vollkorn',
|
|
'PT Serif',
|
|
'Georgia',
|
|
'Times New Roman',
|
|
];
|
|
|
|
export const NON_FREE_FONTS = ['Georgia', 'Times New Roman'];
|
|
|
|
export const CJK_SERIF_FONTS = [
|
|
_('LXGW WenKai GB Screen'),
|
|
_('LXGW WenKai TC'),
|
|
_('GuanKiapTsingKhai-T'),
|
|
_('Source Han Serif CN'),
|
|
_('Huiwen-MinchoGBK'),
|
|
_('KingHwa_OldSong'),
|
|
];
|
|
|
|
export const CJK_SANS_SERIF_FONTS = ['Noto Sans SC', 'Noto Sans TC'];
|
|
|
|
export const SANS_SERIF_FONTS = ['Roboto', 'Noto Sans', 'Open Sans', 'PT Sans', 'Helvetica'];
|
|
|
|
export const MONOSPACE_FONTS = [
|
|
'Fira Code',
|
|
'Consolas',
|
|
'Courier New',
|
|
'Lucida Console',
|
|
'PT Mono',
|
|
];
|
|
|
|
export const FALLBACK_FONTS = ['MiSans L3'];
|
|
|
|
export const WINDOWS_FONTS = [
|
|
'Arial',
|
|
'Arial Black',
|
|
'Bahnschrift',
|
|
'Calibri',
|
|
'Cambria',
|
|
'Cambria Math',
|
|
'Candara',
|
|
'Comic Sans MS',
|
|
'Consolas',
|
|
'Constantia',
|
|
'Corbel',
|
|
'Courier New',
|
|
'Ebrima',
|
|
'FangSong',
|
|
'Franklin Gothic Medium',
|
|
'Gabriola',
|
|
'Gadugi',
|
|
'Georgia',
|
|
'Heiti',
|
|
'HoloLens MDL2 Assets',
|
|
'Impact',
|
|
'Ink Free',
|
|
'Javanese Text',
|
|
'KaiTi',
|
|
'Leelawadee UI',
|
|
'Lucida Console',
|
|
'Lucida Sans Unicode',
|
|
'LXGW WenKai GB Screen',
|
|
'LXGW WenKai TC',
|
|
'Malgun Gothic',
|
|
'Marlett',
|
|
'Microsoft Himalaya',
|
|
'Microsoft JhengHei',
|
|
'Microsoft New Tai Lue',
|
|
'Microsoft PhagsPa',
|
|
'Microsoft Sans Serif',
|
|
'Microsoft Tai Le',
|
|
'Microsoft YaHei',
|
|
'Microsoft Yi Baiti',
|
|
'MingLiU',
|
|
'MingLiU-ExtB',
|
|
'Mongolian Baiti',
|
|
'MS Gothic',
|
|
'MS Mincho',
|
|
'MV Boli',
|
|
'Myanmar Text',
|
|
'Nirmala UI',
|
|
'Noto Serif JP',
|
|
'NSimSun',
|
|
'Palatino Linotype',
|
|
'PMingLiU',
|
|
'Segoe MDL2 Assets',
|
|
'Segoe Print',
|
|
'Segoe Script',
|
|
'Segoe UI',
|
|
'Segoe UI Historic',
|
|
'Segoe UI Emoji',
|
|
'Segoe UI Symbol',
|
|
'SimHei',
|
|
'SimSun',
|
|
'SimSun-ExtB',
|
|
'Sitka',
|
|
'Sylfaen',
|
|
'Tahoma',
|
|
'Times New Roman',
|
|
'Trebuchet MS',
|
|
'Verdana',
|
|
'XiHeiti',
|
|
'Yu Gothic',
|
|
'Yu Mincho',
|
|
];
|
|
|
|
export const MACOS_FONTS = [
|
|
'American Typewriter',
|
|
'Andale Mono',
|
|
'Arial',
|
|
'Arial Black',
|
|
'Arial Narrow',
|
|
'Arial Rounded MT Bold',
|
|
'Arial Unicode MS',
|
|
'Avenir',
|
|
'Avenir Next',
|
|
'Avenir Next Condensed',
|
|
'Baskerville',
|
|
'BiauKai',
|
|
'Big Caslon',
|
|
'Bodoni 72',
|
|
'Bodoni 72 Oldstyle',
|
|
'Bodoni 72 Smallcaps',
|
|
'Bradley Hand',
|
|
'Brush Script MT',
|
|
'Chalkboard',
|
|
'Chalkboard SE',
|
|
'Chalkduster',
|
|
'Charter',
|
|
'Cochin',
|
|
'Comic Sans MS',
|
|
'Copperplate',
|
|
'Courier',
|
|
'Courier New',
|
|
'Didot',
|
|
'DIN Alternate',
|
|
'DIN Condensed',
|
|
'FangSong',
|
|
'Futura',
|
|
'Geneva',
|
|
'Georgia',
|
|
'Gill Sans',
|
|
'Heiti SC',
|
|
'Heiti TC',
|
|
'Helvetica',
|
|
'Helvetica Neue',
|
|
'Herculanum',
|
|
'Hiragino Sans',
|
|
'Hiragino Mincho',
|
|
'Hoefler Text',
|
|
'Impact',
|
|
'Kaiti SC',
|
|
'Kaiti TC',
|
|
'Kozuka Gothic Pro',
|
|
'Kozuka Mincho Pro',
|
|
'Lucida Grande',
|
|
'Luminari',
|
|
'LXGW WenKai GB Screen',
|
|
'LXGW WenKai TC',
|
|
'Marker Felt',
|
|
'Menlo',
|
|
'Microsoft Sans Serif',
|
|
'Monaco',
|
|
'Noteworthy',
|
|
'Noto Serif JP',
|
|
'Optima',
|
|
'Palatino',
|
|
'Papyrus',
|
|
'PingFang HK',
|
|
'PingFang SC',
|
|
'PingFang TC',
|
|
'Phosphate',
|
|
'Rockwell',
|
|
'Savoye LET',
|
|
'SignPainter',
|
|
'Skia',
|
|
'Snell Roundhand',
|
|
'Songti SC',
|
|
'Songti TC',
|
|
'STFangsong',
|
|
'STKaiti',
|
|
'STSong',
|
|
'STXihei',
|
|
'Tahoma',
|
|
'Times',
|
|
'Times New Roman',
|
|
'Trattatello',
|
|
'Trebuchet MS',
|
|
'Verdana',
|
|
'XiHeiti',
|
|
'Yu Mincho',
|
|
'Zapfino',
|
|
];
|
|
|
|
export const LINUX_FONTS = [
|
|
'Arial',
|
|
'Cantarell',
|
|
'Comic Sans MS',
|
|
'Courier New',
|
|
'DejaVu Sans',
|
|
'DejaVu Sans Mono',
|
|
'DejaVu Serif',
|
|
'Droid Sans',
|
|
'Droid Sans Mono',
|
|
'FangSong',
|
|
'FreeMono',
|
|
'FreeSans',
|
|
'FreeSerif',
|
|
'Georgia',
|
|
'Heiti',
|
|
'Impact',
|
|
'Kaiti',
|
|
'Liberation Mono',
|
|
'Liberation Sans',
|
|
'Liberation Serif',
|
|
'LXGW WenKai GB Screen',
|
|
'LXGW WenKai TC',
|
|
'Noto Mono',
|
|
'Noto Sans',
|
|
'Noto Sans JP',
|
|
'Noto Sans CJK SC',
|
|
'Noto Sans CJK TC',
|
|
'Noto Serif',
|
|
'Noto Serif JP',
|
|
'Noto Serif CJK SC',
|
|
'Noto Serif CJK TC',
|
|
'Open Sans',
|
|
'Poppins',
|
|
'Sazanami Gothic',
|
|
'Sazanami Mincho',
|
|
'Source Han Sans',
|
|
'Source Han Serif',
|
|
'Times New Roman',
|
|
'Ubuntu',
|
|
'Ubuntu Mono',
|
|
'WenQuanYi Micro Hei',
|
|
'WenQuanYi Zen Hei',
|
|
'XiHeiti',
|
|
];
|
|
|
|
export const IOS_FONTS = [
|
|
'Avenir',
|
|
'Avenir Next',
|
|
'Courier',
|
|
'Courier New',
|
|
'FangSong',
|
|
'Georgia',
|
|
'Heiti',
|
|
'Helvetica',
|
|
'Helvetica Neue',
|
|
'Hiragino Mincho',
|
|
'Hiragino Sans',
|
|
'Kaiti',
|
|
'LXGW WenKai GB Screen',
|
|
'LXGW WenKai TC',
|
|
'Palatino',
|
|
'PingFang SC',
|
|
'PingFang TC',
|
|
'San Francisco',
|
|
'SF Pro Display',
|
|
'SF Pro Rounded',
|
|
'SF Pro Text',
|
|
'Songti',
|
|
'Times New Roman',
|
|
'Verdana',
|
|
'XiHeiti',
|
|
];
|
|
|
|
export const ANDROID_FONTS = [
|
|
'Arial',
|
|
'Droid Sans',
|
|
'Droid Serif',
|
|
'FangSong',
|
|
'FZLanTingHei',
|
|
'Georgia',
|
|
'Heiti',
|
|
'Kaiti',
|
|
'LXGW WenKai GB Screen',
|
|
'LXGW WenKai TC',
|
|
'Noto Sans',
|
|
'Noto Sans CJK',
|
|
'Noto Sans JP',
|
|
'Noto Serif',
|
|
'Noto Serif CJK',
|
|
'Noto Serif JP',
|
|
'PingFang SC',
|
|
'Roboto',
|
|
'Source Han Sans',
|
|
'Source Han Serif',
|
|
'STHeiti',
|
|
'STSong',
|
|
'Tahoma',
|
|
'Verdana',
|
|
'XiHeiti',
|
|
];
|
|
|
|
export const CJK_EXCLUDE_PATTENS = new RegExp(
|
|
['AlBayan', 'STIX', 'Kailasa', 'ITCTT', 'Luminari', 'Myanmar'].join('|'),
|
|
'i',
|
|
);
|
|
export const CJK_FONTS_PATTENS = new RegExp(
|
|
[
|
|
'CJK',
|
|
'TC$',
|
|
'SC$',
|
|
'HK',
|
|
'JP',
|
|
'TW',
|
|
'Sim',
|
|
'Kai',
|
|
'Hei',
|
|
'Yan',
|
|
'Min',
|
|
'Khai',
|
|
'Yuan',
|
|
'Song',
|
|
'Ming',
|
|
'FZ',
|
|
'Huiwen',
|
|
'KingHwa',
|
|
'FangZheng',
|
|
'WenQuanYi',
|
|
'PingFang',
|
|
'Hiragino',
|
|
'Meiryo',
|
|
'Source\\s?Han',
|
|
'Yu\\s?Gothic',
|
|
'Yu\\s?Mincho',
|
|
'Mincho',
|
|
'Nanum',
|
|
'Malgun',
|
|
'Gulim',
|
|
'Dotum',
|
|
'Batang',
|
|
'Gungsuh',
|
|
'OPPO sans',
|
|
'MiSans',
|
|
'Fallback',
|
|
].join('|'),
|
|
'i',
|
|
);
|
|
|
|
export const BOOK_IDS_SEPARATOR = '+';
|
|
|
|
export const DOWNLOAD_READEST_URL = 'https://readest.com?utm_source=readest_web';
|
|
|
|
export const READEST_WEB_BASE_URL = 'https://web.readest.com';
|
|
export const READEST_NODE_BASE_URL = 'https://node.readest.com';
|
|
|
|
const LATEST_DOWNLOAD_BASE_URL = 'https://download.readest.com/releases';
|
|
|
|
export const READEST_UPDATER_FILE = `${LATEST_DOWNLOAD_BASE_URL}/latest.json`;
|
|
|
|
export const READEST_CHANGELOG_FILE = `${LATEST_DOWNLOAD_BASE_URL}/release-notes.json`;
|
|
|
|
export const READEST_PUBLIC_STORAGE_BASE_URL = 'https://storage.readest.com';
|
|
|
|
export const READEST_OPDS_USER_AGENT = 'Readest/1.0 (OPDS Browser)';
|
|
|
|
export const SYNC_PROGRESS_INTERVAL_SEC = 3;
|
|
export const SYNC_NOTES_INTERVAL_SEC = 5;
|
|
export const SYNC_BOOKS_INTERVAL_SEC = 5;
|
|
export const CHECK_UPDATE_INTERVAL_SEC = 24 * 60 * 60;
|
|
|
|
export const MAX_ZOOM_LEVEL = 500;
|
|
export const MIN_ZOOM_LEVEL = 50;
|
|
export const ZOOM_STEP = 10;
|
|
|
|
export const DEFAULT_STORAGE_QUOTA: UserStorageQuota = {
|
|
free: 500 * 1024 * 1024,
|
|
plus: 5 * 1024 * 1024 * 1024,
|
|
pro: 20 * 1024 * 1024 * 1024,
|
|
purchase: 0,
|
|
};
|
|
|
|
export const DEFAULT_DAILY_TRANSLATION_QUOTA: UserDailyTranslationQuota = {
|
|
free: 10 * 1024,
|
|
plus: 100 * 1024,
|
|
pro: 500 * 1024,
|
|
purchase: 0,
|
|
};
|
|
|
|
export const DOUBLE_CLICK_INTERVAL_THRESHOLD_MS = 250;
|
|
export const DISABLE_DOUBLE_CLICK_ON_MOBILE = true;
|
|
export const LONG_HOLD_THRESHOLD = 500;
|
|
|
|
export const CUSTOM_THEME_TEMPLATES = [
|
|
{
|
|
light: {
|
|
fg: '#2b2b2b',
|
|
bg: '#f3f3f3',
|
|
primary: '#3c5a72',
|
|
},
|
|
dark: {
|
|
fg: '#d0d0d0',
|
|
bg: '#1a1c1f',
|
|
primary: '#486e8a',
|
|
},
|
|
},
|
|
{
|
|
light: {
|
|
fg: '#3f2f3c',
|
|
bg: '#f5ecf8',
|
|
primary: '#7b5291',
|
|
},
|
|
dark: {
|
|
fg: '#d6cadd',
|
|
bg: '#3a2c3d',
|
|
primary: '#bda0cc',
|
|
},
|
|
},
|
|
{
|
|
light: {
|
|
fg: '#2b2b2b',
|
|
bg: '#defcd9',
|
|
primary: '#00796b',
|
|
},
|
|
dark: {
|
|
fg: '#c8e6c9',
|
|
bg: '#273c33',
|
|
primary: '#26a69a',
|
|
},
|
|
},
|
|
];
|
|
|
|
export const MIGHT_BE_RTL_LANGS = [
|
|
'zh',
|
|
'ja',
|
|
'ko',
|
|
'ar',
|
|
'he',
|
|
'fa',
|
|
'ur',
|
|
'dv',
|
|
'ps',
|
|
'sd',
|
|
'yi',
|
|
'',
|
|
];
|
|
|
|
export const TRANSLATED_LANGS = {
|
|
en: 'English',
|
|
fr: 'Français',
|
|
de: 'Deutsch',
|
|
nl: 'Nederlands',
|
|
it: 'Italiano',
|
|
ja: '日本語',
|
|
ko: '한국어',
|
|
es: 'Español',
|
|
pt: 'Português',
|
|
ru: 'Русский',
|
|
ar: 'العربية',
|
|
fa: 'فارسی',
|
|
el: 'Ελληνικά',
|
|
uk: 'Українська',
|
|
pl: 'Polski',
|
|
tr: 'Türkçe',
|
|
hi: 'हिन्दी',
|
|
id: 'Indonesia',
|
|
vi: 'Tiếng Việt',
|
|
th: 'ภาษาไทย',
|
|
ms: 'Melayu',
|
|
bo: 'བོད་སྐད་',
|
|
bn: 'বাংলা',
|
|
ta: 'தமிழ்',
|
|
si: 'සිංහල',
|
|
'zh-CN': '简体中文',
|
|
'zh-TW': '正體中文',
|
|
};
|
|
|
|
export const TRANSLATOR_LANGS: Record<string, string> = {
|
|
...TRANSLATED_LANGS,
|
|
nb: 'Bokmål',
|
|
sv: 'Svenska',
|
|
fi: 'Suomi',
|
|
da: 'Dansk',
|
|
cs: 'Čeština',
|
|
hu: 'Magyar',
|
|
ro: 'Română',
|
|
bg: 'Български',
|
|
hr: 'Hrvatski',
|
|
lt: 'Lietuvių',
|
|
sl: 'Slovenščina',
|
|
sk: 'Slovenčina',
|
|
fa: 'فارسی',
|
|
};
|
|
|
|
export const SUPPORTED_LANGS: Record<string, string> = { ...TRANSLATED_LANGS, zh: '中文' };
|
|
|
|
export const SUPPORTED_LANGNAMES: Record<string, string> = Object.fromEntries(
|
|
Object.entries(SUPPORTED_LANGS).map(([code, name]) => [name, code]),
|
|
);
|