import clsx from 'clsx'; import React, { useEffect, useState } from 'react'; import NumberInput from './NumberInput'; import FontDropdown from './FontDropDown'; import { ANDROID_FONTS, IOS_FONTS, 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'; import { FONT_ENUM_SUPPORTED_OS_PLATFORMS, getSysFontsList } from '@/utils/font'; import { isTauriAppPlatform } from '@/services/environment'; interface FontFaceProps { className?: string; family: string; label: string; options: string[]; moreOptions?: string[]; selected: string; onSelect: (option: string) => void; } const handleFontFaceFont = (option: string, family: string) => { return `'${option}', ${family}`; }; const FontFace = ({ className, family, label, options, moreOptions, selected, onSelect, }: FontFaceProps) => (
{label} ({ option, label: option }))} moreOptions={moreOptions} selected={selected} onSelect={onSelect} onGetFontFamily={handleFontFaceFont} />
); const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => { const _ = useTranslation(); const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore(); const { getView, getViewSettings, setViewSettings } = useReaderStore(); const view = getView(bookKey); const viewSettings = getViewSettings(bookKey)!; const { themeCode } = useTheme(); const fontFamilyOptions = [ { option: 'Serif', label: _('Serif Font'), }, { option: 'Sans-serif', label: _('Sans-Serif Font'), }, ]; const osPlatform = getOSPlatform(); let defaultSysFonts: string[] = []; switch (osPlatform) { case 'macos': defaultSysFonts = MACOS_FONTS; break; case 'windows': defaultSysFonts = WINDOWS_FONTS; break; case 'linux': defaultSysFonts = LINUX_FONTS; break; case 'ios': defaultSysFonts = IOS_FONTS; break; case 'android': defaultSysFonts = ANDROID_FONTS; break; default: break; } const [sysFonts, setSysFonts] = useState(defaultSysFonts); const [defaultFontSize, setDefaultFontSize] = useState(viewSettings.defaultFontSize!); const [minFontSize, setMinFontSize] = useState(viewSettings.minimumFontSize!); const [overrideFont, setOverrideFont] = useState(viewSettings.overrideFont!); const [defaultFont, setDefaultFont] = useState(viewSettings.defaultFont!); const [serifFont, setSerifFont] = useState(viewSettings.serifFont!); const [sansSerifFont, setSansSerifFont] = useState(viewSettings.sansSerifFont!); const [monospaceFont, setMonospaceFont] = useState(viewSettings.monospaceFont!); useEffect(() => { if (isTauriAppPlatform() && FONT_ENUM_SUPPORTED_OS_PLATFORMS.includes(osPlatform)) { getSysFontsList().then((fonts) => { setSysFonts(fonts); }); } // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { viewSettings.defaultFont = defaultFont; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.defaultFont = defaultFont; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [defaultFont]); useEffect(() => { viewSettings.defaultFontSize = defaultFontSize; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.defaultFontSize = defaultFontSize; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [defaultFontSize]); useEffect(() => { viewSettings.minimumFontSize = minFontSize; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.minimumFontSize = minFontSize; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [minFontSize]); useEffect(() => { viewSettings.serifFont = serifFont; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.serifFont = serifFont; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [serifFont]); useEffect(() => { viewSettings.sansSerifFont = sansSerifFont; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.sansSerifFont = sansSerifFont; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [sansSerifFont]); useEffect(() => { viewSettings.monospaceFont = monospaceFont; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.monospaceFont = monospaceFont; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [monospaceFont]); useEffect(() => { viewSettings.overrideFont = overrideFont; setViewSettings(bookKey, viewSettings); if (isFontLayoutSettingsGlobal) { settings.globalViewSettings.overrideFont = overrideFont; setSettings(settings); } view?.renderer.setStyles?.(getStyles(viewSettings, themeCode)); // eslint-disable-next-line react-hooks/exhaustive-deps }, [overrideFont]); const handleFontFamilyFont = (option: string) => { switch (option) { case 'Serif': return `'${serifFont}', serif`; case 'Sans-serif': return `'${sansSerifFont}', sans-serif`; case 'Monospace': return `'${monospaceFont}', monospace`; default: return ''; } }; return (

{_('Font Size')}

{_('Font Family')}

{_('Default Font')}
{_('Override Book Font')} setOverrideFont(!overrideFont)} />

{_('Font Face')}

); }; export default FontPanel;