diff --git a/apps/readest-app/src/app/library/components/SettingsMenu.tsx b/apps/readest-app/src/app/library/components/SettingsMenu.tsx index 7e78084e..03048aa0 100644 --- a/apps/readest-app/src/app/library/components/SettingsMenu.tsx +++ b/apps/readest-app/src/app/library/components/SettingsMenu.tsx @@ -1,10 +1,9 @@ import clsx from 'clsx'; import React, { useState } from 'react'; import { useRouter } from 'next/navigation'; -import { PiUserCircle } from 'react-icons/pi'; -import { PiUserCircleCheck } from 'react-icons/pi'; +import { PiUserCircle, PiUserCircleCheck, PiGear } from 'react-icons/pi'; +import { PiSun, PiMoon } from 'react-icons/pi'; import { TbSunMoon } from 'react-icons/tb'; -import { BiMoon, BiSun } from 'react-icons/bi'; import { invoke, PermissionState } from '@tauri-apps/api/core'; import { isTauriAppPlatform, isWebAppPlatform } from '@/services/environment'; @@ -42,6 +41,7 @@ const SettingsMenu: React.FC = ({ setIsDropdownOpen }) => { const { userPlan, quotas } = useQuotaStats(true); const { themeMode, setThemeMode } = useThemeStore(); const { settings, setSettings, saveSettings } = useSettingsStore(); + const { setFontLayoutSettingsDialogOpen } = useSettingsStore(); const [isAutoUpload, setIsAutoUpload] = useState(settings.autoUpload); const [isAutoCheckUpdates, setIsAutoCheckUpdates] = useState(settings.autoCheckUpdates); const [isAlwaysOnTop, setIsAlwaysOnTop] = useState(settings.alwaysOnTop); @@ -174,6 +174,11 @@ const SettingsMenu: React.FC = ({ setIsDropdownOpen }) => { setIsDropdownOpen?.(false); }; + const openSettingsDialog = () => { + setIsDropdownOpen?.(false); + setFontLayoutSettingsDialogOpen(true); + }; + const toggleAlwaysInForeground = async () => { const requestAlwaysInForeground = !settings.alwaysInForeground; @@ -297,9 +302,10 @@ const SettingsMenu: React.FC = ({ setIsDropdownOpen }) => { + {appService?.canCustomizeRootDir && ( <> diff --git a/apps/readest-app/src/app/library/page.tsx b/apps/readest-app/src/app/library/page.tsx index 904b83e3..834fb0a2 100644 --- a/apps/readest-app/src/app/library/page.tsx +++ b/apps/readest-app/src/app/library/page.tsx @@ -54,6 +54,7 @@ import LibraryHeader from './components/LibraryHeader'; import Bookshelf from './components/Bookshelf'; import useShortcuts from '@/hooks/useShortcuts'; import DropIndicator from '@/components/DropIndicator'; +import SettingsDialog from '@/components/settings/SettingsDialog'; const LibraryPageWithSearchParams = () => { const searchParams = useSearchParams(); @@ -77,6 +78,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP const { selectFiles } = useFileSelector(appService, _); const { safeAreaInsets: insets, isRoundedWindow } = useThemeStore(); const { settings, setSettings, saveSettings } = useSettingsStore(); + const { isFontLayoutSettingsDialogOpen } = useSettingsStore(); const [loading, setLoading] = useState(false); const isInitiating = useRef(false); const [libraryLoaded, setLibraryLoaded] = useState(false); @@ -89,6 +91,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP }>({}); const [pendingNavigationBookIds, setPendingNavigationBookIds] = useState(null); const [isDragging, setIsDragging] = useState(false); + const demoBooks = useDemoBooks(); const osRef = useRef(null); const containerRef: React.MutableRefObject = useRef(null); @@ -730,6 +733,7 @@ const LibraryPageContent = ({ searchParams }: { searchParams: ReadonlyURLSearchP + {isFontLayoutSettingsDialogOpen && } ); diff --git a/apps/readest-app/src/app/reader/components/BooksGrid.tsx b/apps/readest-app/src/app/reader/components/BooksGrid.tsx index e9d87f80..87185bed 100644 --- a/apps/readest-app/src/app/reader/components/BooksGrid.tsx +++ b/apps/readest-app/src/app/reader/components/BooksGrid.tsx @@ -10,13 +10,13 @@ import { useBookDataStore } from '@/store/bookDataStore'; import { useTranslation } from '@/hooks/useTranslation'; import { getGridTemplate, getInsetEdges } from '@/utils/grid'; import { getViewInsets } from '@/utils/insets'; +import SettingsDialog from '@/components/settings/SettingsDialog'; import FoliateViewer from './FoliateViewer'; import SectionInfo from './SectionInfo'; import HeaderBar from './HeaderBar'; import FooterBar from './FooterBar'; import ProgressInfoView from './ProgressInfo'; import Ribbon from './Ribbon'; -import SettingsDialog from './settings/SettingsDialog'; import Annotator from './annotator/Annotator'; import FootnotePopup from './FootnotePopup'; import HintInfo from './HintInfo'; @@ -34,7 +34,7 @@ const BooksGrid: React.FC = ({ bookKeys, onCloseBook }) => { const { getProgress, getViewState, getViewSettings } = useReaderStore(); const { setGridInsets, hoveredBookKey } = useReaderStore(); const { sideBarBookKey } = useSidebarStore(); - const { isFontLayoutSettingsDialogOpen, setFontLayoutSettingsDialogOpen } = useSettingsStore(); + const { isFontLayoutSettingsDialogOpen } = useSettingsStore(); const { safeAreaInsets: screenInsets } = useThemeStore(); const aspectRatio = window.innerWidth / window.innerHeight; @@ -120,7 +120,6 @@ const BooksGrid: React.FC = ({ bookKeys, onCloseBook }) => { isTopLeft={index === 0} isHoveredAnim={bookKeys.length > 2} onCloseBook={onCloseBook} - onSetSettingsDialogOpen={setFontLayoutSettingsDialogOpen} gridInsets={gridInsets} /> = ({ bookKeys, onCloseBook }) => { isHoveredAnim={false} gridInsets={gridInsets} /> - {isFontLayoutSettingsDialogOpen && } + {isFontLayoutSettingsDialogOpen && } ); })} diff --git a/apps/readest-app/src/app/reader/components/FooterBar.tsx b/apps/readest-app/src/app/reader/components/FooterBar.tsx index cbdc62f6..dce6b184 100644 --- a/apps/readest-app/src/app/reader/components/FooterBar.tsx +++ b/apps/readest-app/src/app/reader/components/FooterBar.tsx @@ -18,9 +18,9 @@ import { useSidebarStore } from '@/store/sidebarStore'; import { useBookDataStore } from '@/store/bookDataStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { eventDispatcher } from '@/utils/event'; import { viewPagination } from '../hooks/usePagination'; -import { saveViewSettings } from '../utils/viewSettingsHelper'; import { PageInfo } from '@/types/book'; import { Insets } from '@/types/misc'; import Button from '@/components/Button'; diff --git a/apps/readest-app/src/app/reader/components/HeaderBar.tsx b/apps/readest-app/src/app/reader/components/HeaderBar.tsx index 5a6d54f7..96668016 100644 --- a/apps/readest-app/src/app/reader/components/HeaderBar.tsx +++ b/apps/readest-app/src/app/reader/components/HeaderBar.tsx @@ -26,7 +26,6 @@ interface HeaderBarProps { isHoveredAnim: boolean; gridInsets: Insets; onCloseBook: (bookKey: string) => void; - onSetSettingsDialogOpen: (open: boolean) => void; } const HeaderBar: React.FC = ({ @@ -36,7 +35,6 @@ const HeaderBar: React.FC = ({ isHoveredAnim, gridInsets, onCloseBook, - onSetSettingsDialogOpen, }) => { const _ = useTranslation(); const { appService } = useEnv(); @@ -185,7 +183,7 @@ const HeaderBar: React.FC = ({ toggleButton={} onToggle={handleToggleDropdown} > - + void; - onSetSettingsDialogOpen: (open: boolean) => void; } -const ViewMenu: React.FC = ({ - bookKey, - setIsDropdownOpen, - onSetSettingsDialogOpen, -}) => { +const ViewMenu: React.FC = ({ bookKey, setIsDropdownOpen }) => { const _ = useTranslation(); const router = useRouter(); const { user } = useAuth(); const { envConfig, appService } = useEnv(); const { getConfig, getBookData } = useBookDataStore(); + const { setFontLayoutSettingsDialogOpen } = useSettingsStore(); const { getView, getViewSettings, getViewState, setViewSettings } = useReaderStore(); const config = getConfig(bookKey)!; const bookData = getBookData(bookKey)!; @@ -65,7 +62,7 @@ const ViewMenu: React.FC = ({ const openFontLayoutMenu = () => { setIsDropdownOpen?.(false); - onSetSettingsDialogOpen(true); + setFontLayoutSettingsDialogOpen(true); }; const cycleThemeMode = () => { diff --git a/apps/readest-app/src/components/AboutWindow.tsx b/apps/readest-app/src/components/AboutWindow.tsx index 9099a085..3db74b2a 100644 --- a/apps/readest-app/src/components/AboutWindow.tsx +++ b/apps/readest-app/src/components/AboutWindow.tsx @@ -87,7 +87,7 @@ export const AboutWindow = () => { boxClassName='sm:!w-[480px] sm:!max-w-screen-sm sm:h-auto' > {isOpen && ( -
+
App Logo diff --git a/apps/readest-app/src/components/UpdaterWindow.tsx b/apps/readest-app/src/components/UpdaterWindow.tsx index 5a900b47..f6a5198c 100644 --- a/apps/readest-app/src/components/UpdaterWindow.tsx +++ b/apps/readest-app/src/components/UpdaterWindow.tsx @@ -402,7 +402,7 @@ export const UpdaterContent = ({

{_('Changelog')}

-
+
{changelogs.length > 0 ? ( changelogs.map((entry: Changelog) => (
diff --git a/apps/readest-app/src/app/reader/components/settings/ColorInput.tsx b/apps/readest-app/src/components/settings/ColorInput.tsx similarity index 100% rename from apps/readest-app/src/app/reader/components/settings/ColorInput.tsx rename to apps/readest-app/src/components/settings/ColorInput.tsx diff --git a/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx b/apps/readest-app/src/components/settings/ColorPanel.tsx similarity index 97% rename from apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx rename to apps/readest-app/src/components/settings/ColorPanel.tsx index bdd86087..19b3ceca 100644 --- a/apps/readest-app/src/app/reader/components/settings/ColorPanel.tsx +++ b/apps/readest-app/src/components/settings/ColorPanel.tsx @@ -18,8 +18,8 @@ import { useReaderStore } from '@/store/readerStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useSettingsStore } from '@/store/settingsStore'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { CODE_LANGUAGES, CodeLanguage, manageSyntaxHighlighting } from '@/utils/highlightjs'; import { SettingsPanelPanelProp } from './SettingsDialog'; import Select from '@/components/Select'; @@ -32,7 +32,7 @@ const ColorPanel: React.FC = ({ bookKey, onRegisterReset const { envConfig } = useEnv(); const { settings, setSettings } = useSettingsStore(); const { getView, getViewSettings } = useReaderStore(); - const viewSettings = getViewSettings(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; const [invertImgColorInDark, setInvertImgColorInDark] = useState( viewSettings.invertImgColorInDark, ); @@ -42,9 +42,9 @@ const ColorPanel: React.FC = ({ bookKey, onRegisterReset const [editTheme, setEditTheme] = useState(null); const [customThemes, setCustomThemes] = useState([]); const [showCustomThemeEditor, setShowCustomThemeEditor] = useState(false); - const [overrideColor, setOverrideColor] = useState(viewSettings.overrideColor!); - const [codeHighlighting, setcodeHighlighting] = useState(viewSettings.codeHighlighting!); - const [codeLanguage, setCodeLanguage] = useState(viewSettings.codeLanguage!); + const [overrideColor, setOverrideColor] = useState(viewSettings.overrideColor); + const [codeHighlighting, setcodeHighlighting] = useState(viewSettings.codeHighlighting); + const [codeLanguage, setCodeLanguage] = useState(viewSettings.codeLanguage); const resetToDefaults = useResetViewSettings(); diff --git a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx b/apps/readest-app/src/components/settings/ControlPanel.tsx similarity index 93% rename from apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx rename to apps/readest-app/src/components/settings/ControlPanel.tsx index e817858f..af894cd3 100644 --- a/apps/readest-app/src/app/reader/components/settings/ControlPanel.tsx +++ b/apps/readest-app/src/components/settings/ControlPanel.tsx @@ -4,11 +4,12 @@ import { useReaderStore } from '@/store/readerStore'; import { useDeviceControlStore } from '@/store/deviceStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useBookDataStore } from '@/store/bookDataStore'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; +import { useSettingsStore } from '@/store/settingsStore'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; import { getStyles } from '@/utils/style'; import { saveAndReload } from '@/utils/reload'; import { getMaxInlineSize } from '@/utils/config'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { SettingsPanelPanelProp } from './SettingsDialog'; import NumberInput from './NumberInput'; @@ -17,21 +18,20 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes const { envConfig, appService } = useEnv(); const { getView, getViewSettings } = useReaderStore(); const { getBookData } = useBookDataStore(); + const { settings } = useSettingsStore(); const { acquireVolumeKeyInterception, releaseVolumeKeyInterception } = useDeviceControlStore(); - const bookData = getBookData(bookKey)!; - const viewSettings = getViewSettings(bookKey)!; + const bookData = getBookData(bookKey); + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; - const [isScrolledMode, setScrolledMode] = useState(viewSettings.scrolled!); - const [isContinuousScroll, setIsContinuousScroll] = useState(viewSettings.continuousScroll!); - const [scrollingOverlap, setScrollingOverlap] = useState(viewSettings.scrollingOverlap!); - const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip!); - const [isDisableClick, setIsDisableClick] = useState(viewSettings.disableClick!); - const [swapClickArea, setSwapClickArea] = useState(viewSettings.swapClickArea!); - const [isDisableDoubleClick, setIsDisableDoubleClick] = useState( - viewSettings.disableDoubleClick!, - ); - const [animated, setAnimated] = useState(viewSettings.animated!); - const [allowScript, setAllowScript] = useState(viewSettings.allowScript!); + const [isScrolledMode, setScrolledMode] = useState(viewSettings.scrolled); + const [isContinuousScroll, setIsContinuousScroll] = useState(viewSettings.continuousScroll); + const [scrollingOverlap, setScrollingOverlap] = useState(viewSettings.scrollingOverlap); + const [volumeKeysToFlip, setVolumeKeysToFlip] = useState(viewSettings.volumeKeysToFlip); + const [isDisableClick, setIsDisableClick] = useState(viewSettings.disableClick); + const [swapClickArea, setSwapClickArea] = useState(viewSettings.swapClickArea); + const [isDisableDoubleClick, setIsDisableDoubleClick] = useState(viewSettings.disableDoubleClick); + const [animated, setAnimated] = useState(viewSettings.animated); + const [allowScript, setAllowScript] = useState(viewSettings.allowScript); const resetToDefaults = useResetViewSettings(); @@ -234,7 +234,7 @@ const ControlPanel: React.FC = ({ bookKey, onRegisterRes type='checkbox' className='toggle' checked={allowScript} - disabled={bookData.book?.format !== 'EPUB'} + disabled={bookData?.book?.format !== 'EPUB'} onChange={() => setAllowScript(!allowScript)} />
diff --git a/apps/readest-app/src/app/reader/components/settings/CustomFonts.tsx b/apps/readest-app/src/components/settings/CustomFonts.tsx similarity index 96% rename from apps/readest-app/src/app/reader/components/settings/CustomFonts.tsx rename to apps/readest-app/src/components/settings/CustomFonts.tsx index d4144c40..b2cf3e16 100644 --- a/apps/readest-app/src/app/reader/components/settings/CustomFonts.tsx +++ b/apps/readest-app/src/components/settings/CustomFonts.tsx @@ -5,10 +5,11 @@ import { IoMdCloseCircleOutline } from 'react-icons/io'; import { useEnv } from '@/context/EnvContext'; import { useReaderStore } from '@/store/readerStore'; import { useTranslation } from '@/hooks/useTranslation'; +import { useSettingsStore } from '@/store/settingsStore'; import { useCustomFontStore } from '@/store/customFontStore'; import { useFileSelector } from '@/hooks/useFileSelector'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { CustomFont, mountCustomFont } from '@/styles/fonts'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; interface CustomFontsProps { bookKey: string; @@ -23,6 +24,7 @@ type FontFamily = { const CustomFonts: React.FC = ({ bookKey, onBack }) => { const _ = useTranslation(); const { appService, envConfig } = useEnv(); + const { settings } = useSettingsStore(); const { fonts: customFonts, addFont, @@ -32,7 +34,7 @@ const CustomFonts: React.FC = ({ bookKey, onBack }) => { saveCustomFonts, } = useCustomFontStore(); const { getViewSettings } = useReaderStore(); - const viewSettings = getViewSettings(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; const [isDeleteMode, setIsDeleteMode] = useState(false); const { selectFiles } = useFileSelector(appService, _); diff --git a/apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx b/apps/readest-app/src/components/settings/DialogMenu.tsx similarity index 100% rename from apps/readest-app/src/app/reader/components/settings/DialogMenu.tsx rename to apps/readest-app/src/components/settings/DialogMenu.tsx diff --git a/apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx b/apps/readest-app/src/components/settings/FontDropDown.tsx similarity index 100% rename from apps/readest-app/src/app/reader/components/settings/FontDropDown.tsx rename to apps/readest-app/src/components/settings/FontDropDown.tsx diff --git a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx b/apps/readest-app/src/components/settings/FontPanel.tsx similarity index 96% rename from apps/readest-app/src/app/reader/components/settings/FontPanel.tsx rename to apps/readest-app/src/components/settings/FontPanel.tsx index c8ee792b..be6c10e6 100644 --- a/apps/readest-app/src/app/reader/components/settings/FontPanel.tsx +++ b/apps/readest-app/src/components/settings/FontPanel.tsx @@ -27,8 +27,8 @@ import { getOSPlatform, isCJKEnv } from '@/utils/misc'; import { getSysFontsList } from '@/utils/bridge'; import { isCJKStr } from '@/utils/lang'; import { isTauriAppPlatform } from '@/services/environment'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { SettingsPanelPanelProp } from './SettingsDialog'; import NumberInput from './NumberInput'; import FontDropdown from './FontDropDown'; @@ -91,7 +91,7 @@ const FontPanel: React.FC = ({ bookKey, onRegisterReset const _ = useTranslation(); const { envConfig, appService } = useEnv(); const { getView, getViewSettings } = useReaderStore(); - const { fontPanelView, setFontPanelView } = useSettingsStore(); + const { settings, fontPanelView, setFontPanelView } = useSettingsStore(); const { fonts: allCustomFonts, getAllFonts, @@ -99,8 +99,8 @@ const FontPanel: React.FC = ({ bookKey, onRegisterReset removeFont, saveCustomFonts, } = useCustomFontStore(); - const viewSettings = getViewSettings(bookKey)!; - const view = getView(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; + const view = getView(bookKey); const iconSize18 = useResponsiveSize(18); const fontFamilyOptions = [ @@ -136,15 +136,15 @@ const FontPanel: React.FC = ({ bookKey, onRegisterReset break; } const [sysFonts, setSysFonts] = useState(defaultSysFonts); - const [defaultFont, setDefaultFont] = useState(viewSettings.defaultFont!); - const [defaultFontSize, setDefaultFontSize] = useState(viewSettings.defaultFontSize!); - const [minFontSize, setMinFontSize] = useState(viewSettings.minimumFontSize!); - const [overrideFont, setOverrideFont] = useState(viewSettings.overrideFont!); - const [defaultCJKFont, setDefaultCJKFont] = useState(viewSettings.defaultCJKFont!); - const [serifFont, setSerifFont] = useState(viewSettings.serifFont!); - const [sansSerifFont, setSansSerifFont] = useState(viewSettings.sansSerifFont!); - const [monospaceFont, setMonospaceFont] = useState(viewSettings.monospaceFont!); - const [fontWeight, setFontWeight] = useState(viewSettings.fontWeight!); + const [defaultFont, setDefaultFont] = useState(viewSettings.defaultFont); + const [defaultFontSize, setDefaultFontSize] = useState(viewSettings.defaultFontSize); + const [minFontSize, setMinFontSize] = useState(viewSettings.minimumFontSize); + const [overrideFont, setOverrideFont] = useState(viewSettings.overrideFont); + const [defaultCJKFont, setDefaultCJKFont] = useState(viewSettings.defaultCJKFont); + const [serifFont, setSerifFont] = useState(viewSettings.serifFont); + const [sansSerifFont, setSansSerifFont] = useState(viewSettings.sansSerifFont); + const [monospaceFont, setMonospaceFont] = useState(viewSettings.monospaceFont); + const [fontWeight, setFontWeight] = useState(viewSettings.fontWeight); const [customFonts, setCustomFonts] = useState(getFontFamilies()); const [CJKFonts, setCJKFonts] = useState(() => { diff --git a/apps/readest-app/src/app/reader/components/settings/LangPanel.tsx b/apps/readest-app/src/components/settings/LangPanel.tsx similarity index 94% rename from apps/readest-app/src/app/reader/components/settings/LangPanel.tsx rename to apps/readest-app/src/components/settings/LangPanel.tsx index 648d2555..d5ecd53e 100644 --- a/apps/readest-app/src/app/reader/components/settings/LangPanel.tsx +++ b/apps/readest-app/src/components/settings/LangPanel.tsx @@ -5,11 +5,11 @@ import { useAuth } from '@/context/AuthContext'; import { useReaderStore } from '@/store/readerStore'; import { useTranslation } from '@/hooks/useTranslation'; import { useSettingsStore } from '@/store/settingsStore'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { getTranslators } from '@/services/translators'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; import { TRANSLATED_LANGS, TRANSLATOR_LANGS } from '@/services/constants'; import { SettingsPanelPanelProp } from './SettingsDialog'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; import { saveAndReload } from '@/utils/reload'; import Select from '@/components/Select'; @@ -17,15 +17,15 @@ const LangPanel: React.FC = ({ bookKey, onRegisterReset const _ = useTranslation(); const { token } = useAuth(); const { envConfig } = useEnv(); - const { applyUILanguage } = useSettingsStore(); + const { settings, applyUILanguage } = useSettingsStore(); const { getViewSettings, setViewSettings } = useReaderStore(); - const viewSettings = getViewSettings(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; - const [uiLanguage, setUILanguage] = useState(viewSettings.uiLanguage!); - const [translationEnabled, setTranslationEnabled] = useState(viewSettings.translationEnabled!); - const [translationProvider, setTranslationProvider] = useState(viewSettings.translationProvider!); - const [translateTargetLang, setTranslateTargetLang] = useState(viewSettings.translateTargetLang!); - const [showTranslateSource, setShowTranslateSource] = useState(viewSettings.showTranslateSource!); + const [uiLanguage, setUILanguage] = useState(viewSettings.uiLanguage); + const [translationEnabled, setTranslationEnabled] = useState(viewSettings.translationEnabled); + const [translationProvider, setTranslationProvider] = useState(viewSettings.translationProvider); + const [translateTargetLang, setTranslateTargetLang] = useState(viewSettings.translateTargetLang); + const [showTranslateSource, setShowTranslateSource] = useState(viewSettings.showTranslateSource); const resetToDefaults = useResetViewSettings(); diff --git a/apps/readest-app/src/app/reader/components/settings/LayoutPanel.tsx b/apps/readest-app/src/components/settings/LayoutPanel.tsx similarity index 96% rename from apps/readest-app/src/app/reader/components/settings/LayoutPanel.tsx rename to apps/readest-app/src/components/settings/LayoutPanel.tsx index 8c8b5f68..25694fee 100644 --- a/apps/readest-app/src/app/reader/components/settings/LayoutPanel.tsx +++ b/apps/readest-app/src/components/settings/LayoutPanel.tsx @@ -7,14 +7,15 @@ import { TbTextDirectionRtl } from 'react-icons/tb'; import { useEnv } from '@/context/EnvContext'; import { useReaderStore } from '@/store/readerStore'; import { useBookDataStore } from '@/store/bookDataStore'; +import { useSettingsStore } from '@/store/settingsStore'; import { useTranslation } from '@/hooks/useTranslation'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; import { isCJKEnv } from '@/utils/misc'; import { getStyles } from '@/utils/style'; import { saveAndReload } from '@/utils/reload'; import { getMaxInlineSize } from '@/utils/config'; import { lockScreenOrientation } from '@/utils/bridge'; -import { saveViewSettings } from '../../utils/viewSettingsHelper'; +import { saveViewSettings } from '@/helpers/viewSettings'; import { getBookDirFromWritingMode, getBookLangCode } from '@/utils/book'; import { MIGHT_BE_RTL_LANGS } from '@/services/constants'; import { SettingsPanelPanelProp } from './SettingsDialog'; @@ -24,52 +25,52 @@ import NumberInput from './NumberInput'; const LayoutPanel: React.FC = ({ bookKey, onRegisterReset }) => { const _ = useTranslation(); const { envConfig, appService } = useEnv(); + const { settings } = useSettingsStore(); const { getView, getViewSettings, getGridInsets, setViewSettings } = useReaderStore(); const { getBookData } = useBookDataStore(); - const view = getView(bookKey); - const bookData = getBookData(bookKey)!; - const viewSettings = getViewSettings(bookKey)!; - const gridInsets = getGridInsets(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; - const [paragraphMargin, setParagraphMargin] = useState(viewSettings.paragraphMargin!); - const [lineHeight, setLineHeight] = useState(viewSettings.lineHeight!); - const [wordSpacing, setWordSpacing] = useState(viewSettings.wordSpacing!); - const [letterSpacing, setLetterSpacing] = useState(viewSettings.letterSpacing!); + const view = getView(bookKey); + const bookData = getBookData(bookKey); + const gridInsets = getGridInsets(bookKey) || { top: 0, bottom: 0, left: 0, right: 0 }; + + const [paragraphMargin, setParagraphMargin] = useState(viewSettings.paragraphMargin); + const [lineHeight, setLineHeight] = useState(viewSettings.lineHeight); + const [wordSpacing, setWordSpacing] = useState(viewSettings.wordSpacing); + const [letterSpacing, setLetterSpacing] = useState(viewSettings.letterSpacing); const [textIndent, setTextIndent] = useState(viewSettings.textIndent!); - const [fullJustification, setFullJustification] = useState(viewSettings.fullJustification!); - const [hyphenation, setHyphenation] = useState(viewSettings.hyphenation!); - const [marginTopPx, setMarginTopPx] = useState( - viewSettings.marginPx || viewSettings.marginTopPx!, - ); - const [marginBottomPx, setMarginBottomPx] = useState(viewSettings.marginBottomPx!); - const [marginLeftPx, setMarginLeftPx] = useState(viewSettings.marginLeftPx!); - const [marginRightPx, setMarginRightPx] = useState(viewSettings.marginRightPx!); + const [fullJustification, setFullJustification] = useState(viewSettings.fullJustification); + const [hyphenation, setHyphenation] = useState(viewSettings.hyphenation); + const [marginTopPx, setMarginTopPx] = useState(viewSettings.marginPx || viewSettings.marginTopPx); + const [marginBottomPx, setMarginBottomPx] = useState(viewSettings.marginBottomPx); + const [marginLeftPx, setMarginLeftPx] = useState(viewSettings.marginLeftPx); + const [marginRightPx, setMarginRightPx] = useState(viewSettings.marginRightPx); const [compactMarginTopPx, setCompactMarginTopPx] = useState( - viewSettings.compactMarginPx || viewSettings.compactMarginTopPx!, + viewSettings.compactMarginPx || viewSettings.compactMarginTopPx, ); const [compactMarginBottomPx, setCompactMarginBottomPx] = useState( - viewSettings.compactMarginBottomPx!, + viewSettings.compactMarginBottomPx, ); - const [gapPercent, setGapPercent] = useState(viewSettings.gapPercent!); - const [compactMarginLeftPx, setCompactMarginLeftPx] = useState(viewSettings.compactMarginLeftPx!); + const [gapPercent, setGapPercent] = useState(viewSettings.gapPercent); + const [compactMarginLeftPx, setCompactMarginLeftPx] = useState(viewSettings.compactMarginLeftPx); const [compactMarginRightPx, setCompactMarginRightPx] = useState( - viewSettings.compactMarginRightPx!, + viewSettings.compactMarginRightPx, ); - const [maxColumnCount, setMaxColumnCount] = useState(viewSettings.maxColumnCount!); - const [maxInlineSize, setMaxInlineSize] = useState(viewSettings.maxInlineSize!); - const [maxBlockSize, setMaxBlockSize] = useState(viewSettings.maxBlockSize!); - const [writingMode, setWritingMode] = useState(viewSettings.writingMode!); - const [overrideLayout, setOverrideLayout] = useState(viewSettings.overrideLayout!); - const [doubleBorder, setDoubleBorder] = useState(viewSettings.doubleBorder!); - const [borderColor, setBorderColor] = useState(viewSettings.borderColor!); - const [showHeader, setShowHeader] = useState(viewSettings.showHeader!); - const [showFooter, setShowFooter] = useState(viewSettings.showFooter!); - const [showBarsOnScroll, setShowBarsOnScroll] = useState(viewSettings.showBarsOnScroll!); - const [showRemainingTime, setShowRemainingTime] = useState(viewSettings.showRemainingTime!); - const [showRemainingPages, setShowRemainingPages] = useState(viewSettings.showRemainingPages!); - const [showProgressInfo, setShowProgressInfo] = useState(viewSettings.showProgressInfo!); + const [maxColumnCount, setMaxColumnCount] = useState(viewSettings.maxColumnCount); + const [maxInlineSize, setMaxInlineSize] = useState(viewSettings.maxInlineSize); + const [maxBlockSize, setMaxBlockSize] = useState(viewSettings.maxBlockSize); + const [writingMode, setWritingMode] = useState(viewSettings.writingMode); + const [overrideLayout, setOverrideLayout] = useState(viewSettings.overrideLayout); + const [doubleBorder, setDoubleBorder] = useState(viewSettings.doubleBorder); + const [borderColor, setBorderColor] = useState(viewSettings.borderColor); + const [showHeader, setShowHeader] = useState(viewSettings.showHeader); + const [showFooter, setShowFooter] = useState(viewSettings.showFooter); + const [showBarsOnScroll, setShowBarsOnScroll] = useState(viewSettings.showBarsOnScroll); + const [showRemainingTime, setShowRemainingTime] = useState(viewSettings.showRemainingTime); + const [showRemainingPages, setShowRemainingPages] = useState(viewSettings.showRemainingPages); + const [showProgressInfo, setShowProgressInfo] = useState(viewSettings.showProgressInfo); const [progressStyle, setProgressStyle] = useState(viewSettings.progressStyle); - const [screenOrientation, setScreenOrientation] = useState(viewSettings.screenOrientation!); + const [screenOrientation, setScreenOrientation] = useState(viewSettings.screenOrientation); const resetToDefaults = useResetViewSettings(); const handleReset = () => { @@ -363,7 +364,7 @@ const LayoutPanel: React.FC = ({ bookKey, onRegisterRese // eslint-disable-next-line react-hooks/exhaustive-deps }, [screenOrientation]); - const langCode = getBookLangCode(bookData.bookDoc?.metadata?.language); + const langCode = getBookLangCode(bookData?.bookDoc?.metadata?.language); const mightBeRTLBook = MIGHT_BE_RTL_LANGS.includes(langCode) || isCJKEnv(); const isVertical = viewSettings.vertical || writingMode.includes('vertical'); diff --git a/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx b/apps/readest-app/src/components/settings/MiscPanel.tsx similarity index 97% rename from apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx rename to apps/readest-app/src/components/settings/MiscPanel.tsx index ef272c84..02ecbaa7 100644 --- a/apps/readest-app/src/app/reader/components/settings/MiscPanel.tsx +++ b/apps/readest-app/src/components/settings/MiscPanel.tsx @@ -6,7 +6,7 @@ import { useEnv } from '@/context/EnvContext'; import { useReaderStore } from '@/store/readerStore'; import { useSettingsStore } from '@/store/settingsStore'; import { useTranslation } from '@/hooks/useTranslation'; -import { useResetViewSettings } from '../../hooks/useResetSettings'; +import { useResetViewSettings } from '@/hooks/useResetSettings'; import { SettingsPanelPanelProp } from './SettingsDialog'; import { getStyles } from '@/utils/style'; import cssValidate from '@/utils/css'; @@ -18,7 +18,7 @@ const MiscPanel: React.FC = ({ bookKey, onRegisterReset const { appService } = useEnv(); const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore(); const { getView, getViewSettings, setViewSettings } = useReaderStore(); - const viewSettings = getViewSettings(bookKey)!; + const viewSettings = getViewSettings(bookKey) || settings.globalViewSettings; const [draftContentStylesheet, setDraftContentStylesheet] = useState(viewSettings.userStylesheet); const [draftContentStylesheetSaved, setDraftContentStylesheetSaved] = useState(true); diff --git a/apps/readest-app/src/app/reader/components/settings/NumberInput.tsx b/apps/readest-app/src/components/settings/NumberInput.tsx similarity index 100% rename from apps/readest-app/src/app/reader/components/settings/NumberInput.tsx rename to apps/readest-app/src/components/settings/NumberInput.tsx diff --git a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx b/apps/readest-app/src/components/settings/SettingsDialog.tsx similarity index 98% rename from apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx rename to apps/readest-app/src/components/settings/SettingsDialog.tsx index e2ab6c7e..727d8df2 100644 --- a/apps/readest-app/src/app/reader/components/settings/SettingsDialog.tsx +++ b/apps/readest-app/src/components/settings/SettingsDialog.tsx @@ -1,6 +1,5 @@ import clsx from 'clsx'; import React, { useEffect, useRef, useState } from 'react'; -import { BookConfig } from '@/types/book'; import { useEnv } from '@/context/EnvContext'; import { useSettingsStore } from '@/store/settingsStore'; import { useResponsiveSize } from '@/hooks/useResponsiveSize'; @@ -35,7 +34,7 @@ type TabConfig = { label: string; }; -const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ bookKey }) => { +const SettingsDialog: React.FC<{ bookKey: string }> = ({ bookKey }) => { const _ = useTranslation(); const { appService } = useEnv(); const closeIconSize = useResponsiveSize(16); @@ -168,7 +167,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo isOpen={true} onClose={handleClose} className='modal-open' - bgClassName='sm:!bg-black/20' + bgClassName={bookKey ? 'sm:!bg-black/20' : 'sm:!bg-black/50'} boxClassName={clsx('sm:min-w-[520px]', appService?.isMobile && 'sm:max-w-[90%] sm:w-3/4')} snapHeight={appService?.isMobile ? 0.7 : undefined} header={ diff --git a/apps/readest-app/src/app/reader/components/settings/ThemeEditor.tsx b/apps/readest-app/src/components/settings/ThemeEditor.tsx similarity index 100% rename from apps/readest-app/src/app/reader/components/settings/ThemeEditor.tsx rename to apps/readest-app/src/components/settings/ThemeEditor.tsx diff --git a/apps/readest-app/src/app/reader/utils/viewSettingsHelper.ts b/apps/readest-app/src/helpers/viewSettings.ts similarity index 75% rename from apps/readest-app/src/app/reader/utils/viewSettingsHelper.ts rename to apps/readest-app/src/helpers/viewSettings.ts index 041c9ef2..32937cbf 100644 --- a/apps/readest-app/src/app/reader/utils/viewSettingsHelper.ts +++ b/apps/readest-app/src/helpers/viewSettings.ts @@ -17,21 +17,24 @@ export const saveViewSettings = async ( useSettingsStore.getState(); const { getView, getViewSettings, setViewSettings } = useReaderStore.getState(); const { getConfig, saveConfig } = useBookDataStore.getState(); - const viewSettings = getViewSettings(bookKey)!; - const config = getConfig(bookKey)!; - if (viewSettings[key] !== value) { + const viewSettings = getViewSettings(bookKey); + const config = getConfig(bookKey); + if (bookKey && viewSettings && viewSettings[key] !== value) { viewSettings[key] = value; if (applyStyles) { const view = getView(bookKey); view?.renderer.setStyles?.(getStyles(viewSettings)); } } - setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal && !skipGlobal) { settings.globalViewSettings[key] = value; setSettings(settings); + await saveSettings(envConfig, settings); + } + + if (bookKey && config && viewSettings) { + setViewSettings(bookKey, viewSettings); + await saveConfig(envConfig, bookKey, config, settings); } - await saveConfig(envConfig, bookKey, config, settings); - await saveSettings(envConfig, settings); }; diff --git a/apps/readest-app/src/app/reader/hooks/useResetSettings.ts b/apps/readest-app/src/hooks/useResetSettings.ts similarity index 100% rename from apps/readest-app/src/app/reader/hooks/useResetSettings.ts rename to apps/readest-app/src/hooks/useResetSettings.ts diff --git a/apps/readest-app/src/store/readerStore.ts b/apps/readest-app/src/store/readerStore.ts index abd8943d..ce1896f8 100644 --- a/apps/readest-app/src/store/readerStore.ts +++ b/apps/readest-app/src/store/readerStore.ts @@ -222,6 +222,7 @@ export const useReaderStore = create((set, get) => ({ }, getViewSettings: (key: string) => get().viewStates[key]?.viewSettings || null, setViewSettings: (key: string, viewSettings: ViewSettings) => { + if (!key) return; const id = key.split('-')[0]!; const bookData = useBookDataStore.getState().booksData[id]; const viewState = get().viewStates[key];