diff --git a/apps/readest-app/public/locales/de/translation.json b/apps/readest-app/public/locales/de/translation.json index ee3cb0ae..6c153cf9 100644 --- a/apps/readest-app/public/locales/de/translation.json +++ b/apps/readest-app/public/locales/de/translation.json @@ -98,6 +98,7 @@ "Sky": "Himmelblau", "Solarized": "Solarisiert", "Subjects:": "Themen:", + "System Fonts": "System-Schriftarten", "Theme Color": "Themenfarbe", "Theme Mode": "Themenmodus", "Unknown": "Unbekannt", diff --git a/apps/readest-app/public/locales/es/translation.json b/apps/readest-app/public/locales/es/translation.json index 26a3f63d..eb734a6d 100644 --- a/apps/readest-app/public/locales/es/translation.json +++ b/apps/readest-app/public/locales/es/translation.json @@ -98,6 +98,7 @@ "Sky": "Cielo", "Solarized": "Solarizado", "Subjects:": "Temas:", + "System Fonts": "Fuentes del sistema", "Theme Color": "Color del tema", "Theme Mode": "Modo del tema", "Unknown": "Desconocido", diff --git a/apps/readest-app/public/locales/fr/translation.json b/apps/readest-app/public/locales/fr/translation.json index 65fa6f6b..89308f5c 100644 --- a/apps/readest-app/public/locales/fr/translation.json +++ b/apps/readest-app/public/locales/fr/translation.json @@ -98,6 +98,7 @@ "Sky": "Ciel", "Solarized": "Solarisé", "Subjects:": "Sujets :", + "System Fonts": "Polices système", "Theme Color": "Couleur du thème", "Theme Mode": "Mode du thème", "Unknown": "Inconnu", diff --git a/apps/readest-app/public/locales/id/translation.json b/apps/readest-app/public/locales/id/translation.json index 7099897d..f025d404 100644 --- a/apps/readest-app/public/locales/id/translation.json +++ b/apps/readest-app/public/locales/id/translation.json @@ -98,6 +98,7 @@ "Sky": "Langit", "Solarized": "Solarized", "Subjects:": "Subjek:", + "System Fonts": "Font Sistem", "Theme Color": "Warna Tema", "Theme Mode": "Mode Tema", "Unknown": "Tidak Diketahui", diff --git a/apps/readest-app/public/locales/it/translation.json b/apps/readest-app/public/locales/it/translation.json index 3f8b8ae2..5f939580 100644 --- a/apps/readest-app/public/locales/it/translation.json +++ b/apps/readest-app/public/locales/it/translation.json @@ -98,6 +98,7 @@ "Sky": "Cielo", "Solarized": "Solarizzato", "Subjects:": "Argomenti:", + "System Fonts": "Font di sistema", "Theme Color": "Colore tema", "Theme Mode": "Modalità tema", "Unknown": "Sconosciuto", diff --git a/apps/readest-app/public/locales/ja/translation.json b/apps/readest-app/public/locales/ja/translation.json index 45868d71..3a6f80de 100644 --- a/apps/readest-app/public/locales/ja/translation.json +++ b/apps/readest-app/public/locales/ja/translation.json @@ -98,6 +98,7 @@ "Sky": "スカイ", "Solarized": "ソーラライズド", "Subjects:": "主題:", + "System Fonts": "システムフォント", "Theme Color": "テーマカラー", "Theme Mode": "テーマモード", "Unknown": "不明", diff --git a/apps/readest-app/public/locales/ko/translation.json b/apps/readest-app/public/locales/ko/translation.json index 0bfff495..d1df943a 100644 --- a/apps/readest-app/public/locales/ko/translation.json +++ b/apps/readest-app/public/locales/ko/translation.json @@ -98,6 +98,7 @@ "Sky": "하늘색", "Solarized": "솔라라이즈드", "Subjects:": "주제:", + "System Fonts": "시스템 글꼴", "Theme Color": "테마 색상", "Theme Mode": "테마 모드", "Unknown": "알 수 없음", diff --git a/apps/readest-app/public/locales/pt/translation.json b/apps/readest-app/public/locales/pt/translation.json index 84d76c36..bde29128 100644 --- a/apps/readest-app/public/locales/pt/translation.json +++ b/apps/readest-app/public/locales/pt/translation.json @@ -98,6 +98,7 @@ "Sky": "Céu", "Solarized": "Solarizado", "Subjects:": "Assuntos:", + "System Fonts": "Fontes do Sistema", "Theme Color": "Cor do Tema", "Theme Mode": "Modo do Tema", "Unknown": "Desconhecido", diff --git a/apps/readest-app/public/locales/ru/translation.json b/apps/readest-app/public/locales/ru/translation.json index 5b10e6c2..48194e2c 100644 --- a/apps/readest-app/public/locales/ru/translation.json +++ b/apps/readest-app/public/locales/ru/translation.json @@ -98,6 +98,7 @@ "Sky": "Небесный", "Solarized": "Солнечный", "Subjects:": "Темы:", + "System Fonts": "Системные шрифты", "Theme Color": "Цвет темы", "Theme Mode": "Режим темы", "Unknown": "Неизвестно", diff --git a/apps/readest-app/public/locales/tr/translation.json b/apps/readest-app/public/locales/tr/translation.json index 1543611c..bd2257db 100644 --- a/apps/readest-app/public/locales/tr/translation.json +++ b/apps/readest-app/public/locales/tr/translation.json @@ -98,6 +98,7 @@ "Sky": "Gökyüzü", "Solarized": "Solarized", "Subjects:": "Konular:", + "System Fonts": "Sistem Yazı Tipleri", "Theme Color": "Tema Rengi", "Theme Mode": "Tema Modu", "Unknown": "Bilinmiyor", diff --git a/apps/readest-app/public/locales/vi/translation.json b/apps/readest-app/public/locales/vi/translation.json index a34fe374..291d61a2 100644 --- a/apps/readest-app/public/locales/vi/translation.json +++ b/apps/readest-app/public/locales/vi/translation.json @@ -98,6 +98,7 @@ "Sky": "Xanh trời", "Solarized": "Solarized", "Subjects:": "Chủ đề:", + "System Fonts": "Phông chữ hệ thống", "Theme Color": "Màu chủ đề", "Theme Mode": "Chế độ chủ đề", "Unknown": "Không xác định", diff --git a/apps/readest-app/public/locales/zh-CN/translation.json b/apps/readest-app/public/locales/zh-CN/translation.json index 4d31276e..53f33ff2 100644 --- a/apps/readest-app/public/locales/zh-CN/translation.json +++ b/apps/readest-app/public/locales/zh-CN/translation.json @@ -98,6 +98,7 @@ "Sky": "天青", "Solarized": "日晖", "Subjects:": "主题", + "System Fonts": "系统字体", "Theme Color": "主题颜色", "Theme Mode": "主题模式", "Unknown": "未知", diff --git a/apps/readest-app/public/locales/zh-TW/translation.json b/apps/readest-app/public/locales/zh-TW/translation.json index 6a20058f..6a6fc97c 100644 --- a/apps/readest-app/public/locales/zh-TW/translation.json +++ b/apps/readest-app/public/locales/zh-TW/translation.json @@ -98,6 +98,7 @@ "Sky": "天青", "Solarized": "日暉", "Subjects:": "主題", + "System Fonts": "系統字體", "Theme Color": "主題顏色", "Theme Mode": "主題模式", "Unknown": "未知", diff --git a/apps/readest-app/src/app/reader/components/ReaderContent.tsx b/apps/readest-app/src/app/reader/components/ReaderContent.tsx index 64b2783d..3250794f 100644 --- a/apps/readest-app/src/app/reader/components/ReaderContent.tsx +++ b/apps/readest-app/src/app/reader/components/ReaderContent.tsx @@ -9,21 +9,23 @@ import { useSettingsStore } from '@/store/settingsStore'; import { useBookDataStore } from '@/store/bookDataStore'; import { useReaderStore } from '@/store/readerStore'; import { useSidebarStore } from '@/store/sidebarStore'; +import { Book } from '@/types/book'; import { SystemSettings } from '@/types/settings'; import { parseOpenWithFiles } from '@/helpers/cli'; import { tauriHandleClose, tauriHandleOnCloseWindow } from '@/utils/window'; import { isTauriAppPlatform } from '@/services/environment'; import { uniqueId } from '@/utils/misc'; +import { eventDispatcher } from '@/utils/event'; import { navigateToLibrary } from '@/utils/nav'; import { BOOK_IDS_SEPARATOR } from '@/services/constants'; import useBooksManager from '../hooks/useBooksManager'; import useBookShortcuts from '../hooks/useBookShortcuts'; +import BookDetailModal from '@/components/BookDetailModal'; import Spinner from '@/components/Spinner'; import SideBar from './sidebar/SideBar'; import Notebook from './notebook/Notebook'; import BooksGrid from './BooksGrid'; -import { eventDispatcher } from '@/utils/event'; const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ ids, settings }) => { const router = useRouter(); @@ -35,6 +37,7 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i const { getConfig, getBookData, saveConfig } = useBookDataStore(); const { getView, setBookKeys } = useReaderStore(); const { initViewState, getViewState, clearViewState } = useReaderStore(); + const [showDetailsBook, setShowDetailsBook] = useState(null); const isInitiating = useRef(false); const [loading, setLoading] = useState(false); @@ -59,6 +62,13 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i if (index === 0) setSideBarBookKey(key); } }); + + const handleShowBookDetails = (event: CustomEvent) => { + const book = event.detail as Book; + setShowDetailsBook(book); + return true; + }; + eventDispatcher.onSync('show-book-details', handleShowBookDetails); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -139,6 +149,13 @@ const ReaderContent: React.FC<{ ids?: string; settings: SystemSettings }> = ({ i + {showDetailsBook && ( + setShowDetailsBook(null)} + /> + )} ); }; diff --git a/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx b/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx index bf4fbf1b..7c2e0501 100644 --- a/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx +++ b/apps/readest-app/src/app/reader/components/notebook/NoteEditor.tsx @@ -57,7 +57,7 @@ const NoteEditor: React.FC = ({ onSave, onEdit }) => { className={clsx( 'note-editor textarea textarea-ghost min-h-[1em] resize-none !outline-none', 'inset-0 w-full rounded-none border-0 bg-transparent p-0 leading-normal', - 'text-base', + 'text-sm', )} ref={editorRef} value={note} @@ -70,7 +70,7 @@ const NoteEditor: React.FC = ({ onSave, onEdit }) => { + {_('Delete')} + diff --git a/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx b/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx index bc393e09..62f0e63c 100644 --- a/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx +++ b/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx @@ -1,11 +1,14 @@ +import clsx from 'clsx'; import React from 'react'; -import { FiChevronDown } from 'react-icons/fi'; +import { FiChevronUp, FiChevronLeft } from 'react-icons/fi'; import { MdCheck } from 'react-icons/md'; +import { useTranslation } from '@/hooks/useTranslation'; interface DropdownProps { family?: string; selected: string; options: string[]; + moreOptions?: string[]; onSelect: (option: string) => void; onGetFontFamily: (option: string, family: string) => string; } @@ -14,21 +17,23 @@ const FontDropdown: React.FC = ({ family, selected, options, + moreOptions, onSelect, onGetFontFamily, }) => { + const _ = useTranslation(); return ( -
+
    {options.map((option) => (
  • onSelect(option)}> @@ -40,6 +45,36 @@ const FontDropdown: React.FC = ({
))} + {moreOptions && moreOptions.length > 0 && ( +
  • +
    + + + + {_('System Fonts')} +
    +
      + {moreOptions.map((option) => ( +
    • onSelect(option)}> +
      + + {selected === option && } + + + {option} + +
      +
    • + ))} +
    +
  • + )}
    ); diff --git a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx b/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx index 00485f88..ea6ac01f 100644 --- a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx +++ b/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx @@ -3,18 +3,27 @@ import React, { useEffect, useState } from 'react'; import NumberInput from './NumberInput'; import FontDropdown from './FontDropDown'; -import { MONOSPACE_FONTS, SANS_SERIF_FONTS, SERIF_FONTS } from '@/services/constants'; +import { + LINUX_FONTS, + MACOS_FONTS, + MONOSPACE_FONTS, + SANS_SERIF_FONTS, + SERIF_FONTS, + WINDOWS_FONTS, +} from '@/services/constants'; import { useReaderStore } from '@/store/readerStore'; import { useSettingsStore } from '@/store/settingsStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useTheme } from '@/hooks/useTheme'; import { getStyles } from '@/utils/style'; +import { getOSPlatform } from '@/utils/misc'; interface FontFaceProps { className?: string; family: string; label: string; options: string[]; + moreOptions?: string[]; selected: string; onSelect: (option: string) => void; } @@ -25,12 +34,21 @@ const handleFontFaceFont = (option: string, family: string) => { return `'${option}', ${family}`; }; -const FontFace = ({ className, family, label, options, selected, onSelect }: FontFaceProps) => ( +const FontFace = ({ + className, + family, + label, + options, + moreOptions, + selected, + onSelect, +}: FontFaceProps) => (
    {label} = ({ bookKey }) => { const viewSettings = getViewSettings(bookKey)!; const { themeCode } = useTheme(); + const osPlatform = getOSPlatform(); + let moreFonts: string[] = []; + switch (osPlatform) { + case 'macos': + moreFonts = MACOS_FONTS; + break; + case 'windows': + moreFonts = WINDOWS_FONTS; + break; + case 'linux': + moreFonts = LINUX_FONTS; + break; + default: + break; + } const [defaultFontSize, setDefaultFontSize] = useState(viewSettings.defaultFontSize!); const [minFontSize, setMinFontSize] = useState(viewSettings.minimumFontSize!); const [overrideFont, setOverrideFont] = useState(viewSettings.overrideFont!); @@ -206,6 +239,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { family='serif' label={_('Serif Font')} options={SERIF_FONTS} + moreOptions={moreFonts} selected={serifFont} onSelect={setSerifFont} /> @@ -213,6 +247,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { family='sans-serif' label={_('Sans-Serif Font')} options={SANS_SERIF_FONTS} + moreOptions={moreFonts} selected={sansSerifFont} onSelect={setSansSerifFont} /> @@ -221,6 +256,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { family='monospace' label={_('Monospace Font')} options={MONOSPACE_FONTS} + moreOptions={moreFonts} selected={monospaceFont} onSelect={setMonospaceFont} /> diff --git a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx index 45665df5..28367559 100644 --- a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx +++ b/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx @@ -39,7 +39,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo return ( -
    +
    ); diff --git a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx index 97222e3d..37f6aa85 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SearchBar.tsx @@ -10,7 +10,8 @@ import { BookSearchConfig, BookSearchResult } from '@/types/book'; import Dropdown from '@/components/Dropdown'; import SearchOptions from './SearchOptions'; -const MINIMUM_SEARCH_TERM_LENGTH = 2; +const MINIMUM_SEARCH_TERM_LENGTH_DEFAULT = 2; +const MINIMUM_SEARCH_TERM_LENGTH_CJK = 1; interface SearchBarProps { isVisible: boolean; @@ -97,8 +98,15 @@ const SearchBar: React.FC = ({ handleSearchTermChange(searchTerm); }; + const exceedMinSearchTermLength = (searchTerm: string) => { + const isCJK = /[\u4e00-\u9fa5\u3040-\u30ff\uac00-\ud7af]/.test(searchTerm); + const minLength = isCJK ? MINIMUM_SEARCH_TERM_LENGTH_CJK : MINIMUM_SEARCH_TERM_LENGTH_DEFAULT; + + return searchTerm.length >= minLength; + }; + const handleSearchTermChange = (term: string) => { - if (term.length >= MINIMUM_SEARCH_TERM_LENGTH) { + if (exceedMinSearchTermLength(term)) { handleSearch(term); } else { resetSearch(); @@ -118,7 +126,10 @@ const SearchBar: React.FC = ({ onSearchResultChange([...results]); isSearchPending.current = false; console.log('search done'); - if (queuedSearchTerm.current !== term && queuedSearchTerm.current.length > 2) { + if ( + queuedSearchTerm.current !== term && + exceedMinSearchTermLength(queuedSearchTerm.current) + ) { handleSearch(queuedSearchTerm.current); } } diff --git a/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx b/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx index c4d60f57..92ac6ccd 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/SideBar.tsx @@ -125,7 +125,7 @@ const SideBar: React.FC<{ />
    - +
    {isSearchBarVisible && searchResults ? ( diff --git a/apps/readest-app/src/services/constants.ts b/apps/readest-app/src/services/constants.ts index adb1e472..b87c2d48 100644 --- a/apps/readest-app/src/services/constants.ts +++ b/apps/readest-app/src/services/constants.ts @@ -82,6 +82,162 @@ export const SANS_SERIF_FONTS = ['Roboto', 'Noto Sans', 'Open Sans', 'Helvetica' export const MONOSPACE_FONTS = ['Fira Code', 'Lucida Console', 'Consolas', 'Courier New']; +export const WINDOWS_FONTS = [ + 'Arial', + 'Arial Black', + 'Bahnschrift', + 'Calibri', + 'Cambria', + 'Cambria Math', + 'Candara', + 'Comic Sans MS', + 'Consolas', + 'Constantia', + 'Corbel', + 'Courier New', + 'Ebrima', + 'Franklin Gothic Medium', + 'Gabriola', + 'Gadugi', + 'Georgia', + 'HoloLens MDL2 Assets', + 'Impact', + 'Ink Free', + 'Javanese Text', + 'Leelawadee UI', + 'Lucida Console', + 'Lucida Sans Unicode', + '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-ExtB', + 'Mongolian Baiti', + 'MS Gothic', + 'MV Boli', + 'Myanmar Text', + 'Nirmala UI', + 'Palatino Linotype', + 'Segoe MDL2 Assets', + 'Segoe Print', + 'Segoe Script', + 'Segoe UI', + 'Segoe UI Historic', + 'Segoe UI Emoji', + 'Segoe UI Symbol', + 'SimSun', + 'Sitka', + 'Sylfaen', + 'Symbol', + 'Tahoma', + 'Times New Roman', + 'Trebuchet MS', + 'Verdana', + 'Webdings', + 'Wingdings', + 'Yu Gothic', +]; + +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', + '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', + 'Futura', + 'Geneva', + 'Georgia', + 'Gill Sans', + 'Helvetica', + 'Helvetica Neue', + 'Herculanum', + 'Hoefler Text', + 'Impact', + 'Lucida Grande', + 'Luminari', + 'Marker Felt', + 'Menlo', + 'Microsoft Sans Serif', + 'Monaco', + 'Noteworthy', + 'Optima', + 'Palatino', + 'Papyrus', + 'Phosphate', + 'Rockwell', + 'Savoye LET', + 'SignPainter', + 'Skia', + 'Snell Roundhand', + 'Tahoma', + 'Times', + 'Times New Roman', + 'Trattatello', + 'Trebuchet MS', + 'Verdana', + 'Zapfino', +]; + +export const LINUX_FONTS = [ + 'Arial', + 'Cantarell', + 'Comic Sans MS', + 'Courier New', + 'DejaVu Sans', + 'DejaVu Sans Mono', + 'DejaVu Serif', + 'Droid Sans', + 'Droid Sans Mono', + 'FreeMono', + 'FreeSans', + 'FreeSerif', + 'Georgia', + 'Impact', + 'Liberation Mono', + 'Liberation Sans', + 'Liberation Serif', + 'Noto Mono', + 'Noto Sans', + 'Noto Serif', + 'Open Sans', + 'Poppins', + 'Symbola', + 'Times New Roman', + 'Ubuntu', + 'Ubuntu Mono', + 'Wingdings', +]; + export const ONE_COLUMN_MAX_INLINE_SIZE = 9999; export const BOOK_IDS_SEPARATOR = '+';