This commit is contained in:
@@ -81,18 +81,24 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
/>
|
||||
<FoliateViewer bookKey={bookKey} bookDoc={bookDoc} config={config} />
|
||||
<FootnotePopup bookKey={bookKey} bookDoc={bookDoc} />
|
||||
<div
|
||||
className='bg-base-100 absolute left-0 top-0 h-full'
|
||||
style={{
|
||||
width: `${horizontalGapPercent}%`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className='bg-base-100 absolute right-0 top-0 h-full'
|
||||
style={{
|
||||
width: `${horizontalGapPercent}%`,
|
||||
}}
|
||||
/>
|
||||
{viewSettings.vertical && (
|
||||
<>
|
||||
<div
|
||||
className='bg-base-100 absolute left-0 top-0 h-full'
|
||||
style={{
|
||||
width: `calc(${horizontalGapPercent}%)`,
|
||||
height: `calc(100% - ${verticalMarginPixels}px)`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className='bg-base-100 absolute right-0 top-0 h-full'
|
||||
style={{
|
||||
width: `calc(${horizontalGapPercent}%)`,
|
||||
height: `calc(100% - ${verticalMarginPixels}px)`,
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{viewSettings.vertical && viewSettings.doubleBorder && (
|
||||
<DoubleBorder
|
||||
showHeader={viewSettings.showHeader}
|
||||
@@ -105,6 +111,7 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
{viewSettings.showHeader && (
|
||||
<SectionInfo
|
||||
section={sectionLabel}
|
||||
showDoubleBorder={viewSettings.vertical && viewSettings.doubleBorder}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
@@ -112,6 +119,7 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
)}
|
||||
<HintInfo
|
||||
bookKey={bookKey}
|
||||
showDoubleBorder={viewSettings.vertical && viewSettings.doubleBorder}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
@@ -121,6 +129,7 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
bookFormat={book.format}
|
||||
section={section}
|
||||
pageinfo={pageinfo}
|
||||
showDoubleBorder={viewSettings.vertical && viewSettings.doubleBorder}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { eventDispatcher } from '@/utils/event';
|
||||
|
||||
interface SectionInfoProps {
|
||||
bookKey: string;
|
||||
showDoubleBorder: boolean;
|
||||
isVertical: boolean;
|
||||
horizontalGap: number;
|
||||
verticalMargin: number;
|
||||
@@ -11,6 +12,7 @@ interface SectionInfoProps {
|
||||
|
||||
const HintInfo: React.FC<SectionInfoProps> = ({
|
||||
bookKey,
|
||||
showDoubleBorder,
|
||||
isVertical,
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
@@ -47,15 +49,16 @@ const HintInfo: React.FC<SectionInfoProps> = ({
|
||||
className={clsx(
|
||||
'hintinfo absolute flex items-center justify-end overflow-hidden',
|
||||
hintMessage ? 'bg-base-100' : 'bg-transparent',
|
||||
isVertical ? 'writing-vertical-rl max-h-[50%] w-[30px]' : 'top-0 h-[44px] max-w-[50%]',
|
||||
isVertical ? 'writing-vertical-rl max-h-[50%]' : 'top-0 h-[44px] max-w-[50%]',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
bottom: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(100% - ${horizontalGap}%)`,
|
||||
width: showDoubleBorder ? '30px' : `${horizontalGap}%`,
|
||||
}
|
||||
: { right: `${horizontalGap}%` }
|
||||
: { insetInlineEnd: `${horizontalGap}%` }
|
||||
}
|
||||
>
|
||||
<h2 className={clsx('text-neutral-content text-center font-sans text-xs font-light')}>
|
||||
|
||||
@@ -7,6 +7,7 @@ interface PageInfoProps {
|
||||
bookFormat: string;
|
||||
section?: PageInfo;
|
||||
pageinfo?: PageInfo;
|
||||
showDoubleBorder: boolean;
|
||||
isVertical: boolean;
|
||||
horizontalGap: number;
|
||||
verticalMargin: number;
|
||||
@@ -16,6 +17,7 @@ const PageInfoView: React.FC<PageInfoProps> = ({
|
||||
bookFormat,
|
||||
section,
|
||||
pageinfo,
|
||||
showDoubleBorder,
|
||||
isVertical,
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
@@ -42,16 +44,17 @@ const PageInfoView: React.FC<PageInfoProps> = ({
|
||||
<div
|
||||
className={clsx(
|
||||
'pageinfo absolute bottom-0 flex items-center justify-end',
|
||||
isVertical ? 'writing-vertical-rl left-0 w-[32px]' : 'bg-base-100 right-0 h-12 w-full',
|
||||
isVertical ? 'writing-vertical-rl' : 'bg-base-100 h-12 w-full',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
bottom: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(${horizontalGap}% - 32px)`,
|
||||
left: showDoubleBorder ? `calc(${horizontalGap}% - 32px)` : 0,
|
||||
width: showDoubleBorder ? '32px' : `${horizontalGap}%`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
}
|
||||
: { paddingRight: `${horizontalGap}%` }
|
||||
: { insetInlineEnd: `${horizontalGap}%` }
|
||||
}
|
||||
>
|
||||
<h2 className='text-neutral-content text-right font-sans text-xs font-extralight'>
|
||||
|
||||
@@ -3,6 +3,7 @@ import React from 'react';
|
||||
|
||||
interface SectionInfoProps {
|
||||
section?: string;
|
||||
showDoubleBorder: boolean;
|
||||
isVertical: boolean;
|
||||
horizontalGap: number;
|
||||
verticalMargin: number;
|
||||
@@ -10,6 +11,7 @@ interface SectionInfoProps {
|
||||
|
||||
const SectionInfo: React.FC<SectionInfoProps> = ({
|
||||
section,
|
||||
showDoubleBorder,
|
||||
isVertical,
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
@@ -18,18 +20,17 @@ const SectionInfo: React.FC<SectionInfoProps> = ({
|
||||
<div
|
||||
className={clsx(
|
||||
'sectioninfo absolute flex items-center overflow-hidden',
|
||||
isVertical
|
||||
? 'writing-vertical-rl max-h-[85%] w-[32px]'
|
||||
: 'bg-base-100 top-0 h-[44px] w-full',
|
||||
isVertical ? 'writing-vertical-rl max-h-[85%]' : 'bg-base-100 top-0 h-[44px]',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
top: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(100% - ${horizontalGap}%)`,
|
||||
width: showDoubleBorder ? '32px' : `${horizontalGap}%`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
}
|
||||
: { paddingLeft: `${horizontalGap}%` }
|
||||
: { insetInlineStart: `${horizontalGap}%`, width: `calc(100% - ${horizontalGap * 2}%)` }
|
||||
}
|
||||
>
|
||||
<h2
|
||||
|
||||
@@ -14,13 +14,13 @@ import {
|
||||
WINDOWS_FONTS,
|
||||
} from '@/services/constants';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { getStyles } from '@/utils/style';
|
||||
import { getOSPlatform } from '@/utils/misc';
|
||||
import { getSysFontsList } from '@/utils/font';
|
||||
import { isTauriAppPlatform } from '@/services/environment';
|
||||
import { saveViewSettings } from '../../utils/viewSettingsHelper';
|
||||
|
||||
interface FontFaceProps {
|
||||
className?: string;
|
||||
@@ -60,9 +60,8 @@ const FontFace = ({
|
||||
|
||||
const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { appService } = useEnv();
|
||||
const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore();
|
||||
const { getView, getViewSettings, setViewSettings } = useReaderStore();
|
||||
const { envConfig, appService } = useEnv();
|
||||
const { getView, getViewSettings } = useReaderStore();
|
||||
const view = getView(bookKey);
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
|
||||
@@ -118,89 +117,49 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.defaultFont = defaultFont;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.defaultFont = defaultFont;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'defaultFont', defaultFont);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [defaultFont]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.defaultFontSize = defaultFontSize;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.defaultFontSize = defaultFontSize;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'defaultFontSize', defaultFontSize);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [defaultFontSize]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.minimumFontSize = minFontSize;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.minimumFontSize = minFontSize;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'minimumFontSize', minFontSize);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [minFontSize]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.fontWeight = fontWeight;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.fontWeight = fontWeight;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'fontWeight', fontWeight);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [fontWeight]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.serifFont = serifFont;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.serifFont = serifFont;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'serifFont', serifFont);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [serifFont]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.sansSerifFont = sansSerifFont;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.sansSerifFont = sansSerifFont;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'sansSerifFont', sansSerifFont);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [sansSerifFont]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.monospaceFont = monospaceFont;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.monospaceFont = monospaceFont;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'monospaceFont', monospaceFont);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [monospaceFont]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.overrideFont = overrideFont;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.overrideFont = overrideFont;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'overrideFont', overrideFont);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [overrideFont]);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { MdOutlineAutoMode } from 'react-icons/md';
|
||||
import { MdOutlineTextRotationNone, MdTextRotateVertical } from 'react-icons/md';
|
||||
import { TbTextDirectionRtl } from 'react-icons/tb';
|
||||
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
@@ -12,11 +12,12 @@ import { getStyles } from '@/utils/style';
|
||||
import { getMaxInlineSize } from '@/utils/config';
|
||||
import { getBookDirFromWritingMode, getBookLangCode } from '@/utils/book';
|
||||
import { MIGHT_BE_RTL_LANGS } from '@/services/constants';
|
||||
import { saveViewSettings } from '../../utils/viewSettingsHelper';
|
||||
import NumberInput from './NumberInput';
|
||||
|
||||
const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore();
|
||||
const { envConfig } = useEnv();
|
||||
const { getView, getViewSettings, setViewSettings } = useReaderStore();
|
||||
const { getBookData } = useBookDataStore();
|
||||
const view = getView(bookKey);
|
||||
@@ -44,100 +45,55 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const [showFooter, setShowFooter] = useState(viewSettings.showFooter!);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.paragraphMargin = paragraphMargin;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.paragraphMargin = paragraphMargin;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'paragraphMargin', paragraphMargin);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [paragraphMargin]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.lineHeight = lineHeight;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.lineHeight = lineHeight;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'lineHeight', lineHeight);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [lineHeight]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.wordSpacing = wordSpacing;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.wordSpacing = wordSpacing;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'wordSpacing', wordSpacing);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [wordSpacing]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.letterSpacing = letterSpacing;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.letterSpacing = letterSpacing;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'letterSpacing', letterSpacing);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [letterSpacing]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.textIndent = textIndent;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.textIndent = textIndent;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'textIndent', textIndent);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [textIndent]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.fullJustification = fullJustification;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.fullJustification = fullJustification;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'fullJustification', fullJustification);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [fullJustification]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.hyphenation = hyphenation;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.hyphenation = hyphenation;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'hyphenation', hyphenation);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hyphenation]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.marginPx = marginPx;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.marginPx = marginPx;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'marginPx', marginPx);
|
||||
view?.renderer.setAttribute('margin', `${marginPx}px`);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [marginPx]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.gapPercent = gapPercent;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.gapPercent = gapPercent;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'gapPercent', gapPercent);
|
||||
view?.renderer.setAttribute('gap', `${gapPercent}%`);
|
||||
if (viewSettings.scrolled) {
|
||||
view?.renderer.setAttribute('flow', 'scrolled');
|
||||
@@ -146,35 +102,20 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
}, [gapPercent]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.maxColumnCount = maxColumnCount;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.maxColumnCount = maxColumnCount;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'maxColumnCount', maxColumnCount);
|
||||
view?.renderer.setAttribute('max-column-count', maxColumnCount);
|
||||
view?.renderer.setAttribute('max-inline-size', `${getMaxInlineSize(viewSettings)}px`);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [maxColumnCount]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.maxInlineSize = maxInlineSize;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.maxInlineSize = maxInlineSize;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'maxInlineSize', maxInlineSize);
|
||||
view?.renderer.setAttribute('max-inline-size', `${getMaxInlineSize(viewSettings)}px`);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [maxInlineSize]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.maxBlockSize = maxBlockSize;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.maxBlockSize = maxBlockSize;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'maxBlockSize', maxBlockSize);
|
||||
view?.renderer.setAttribute('max-block-size', `${maxBlockSize}px`);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [maxBlockSize]);
|
||||
@@ -182,11 +123,10 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
useEffect(() => {
|
||||
// global settings are not supported for writing mode
|
||||
const prevWritingMode = viewSettings.writingMode;
|
||||
viewSettings.writingMode = writingMode;
|
||||
if (writingMode.includes('vertical')) {
|
||||
viewSettings.vertical = true;
|
||||
if (!writingMode.includes('vertical')) {
|
||||
viewSettings.vertical = false;
|
||||
}
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
saveViewSettings(envConfig, bookKey, 'writingMode', writingMode, true);
|
||||
if (view) {
|
||||
view.renderer.setStyles?.(getStyles(viewSettings));
|
||||
view.book.dir = getBookDirFromWritingMode(writingMode);
|
||||
@@ -202,69 +142,46 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
}, [writingMode]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.overrideLayout = overrideLayout;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.overrideLayout = overrideLayout;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'overrideLayout', overrideLayout);
|
||||
view?.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [overrideLayout]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings!.scrolled = isScrolledMode;
|
||||
saveViewSettings(envConfig, bookKey, 'scrolled', isScrolledMode);
|
||||
getView(bookKey)?.renderer.setAttribute('flow', isScrolledMode ? 'scrolled' : 'paginated');
|
||||
getView(bookKey)?.renderer.setAttribute(
|
||||
'max-inline-size',
|
||||
`${getMaxInlineSize(viewSettings)}px`,
|
||||
);
|
||||
getView(bookKey)?.renderer.setStyles?.(getStyles(viewSettings!));
|
||||
setViewSettings(bookKey, viewSettings!);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.scrolled = isScrolledMode;
|
||||
setSettings(settings);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isScrolledMode]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.doubleBorder = doubleBorder;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.doubleBorder = doubleBorder;
|
||||
setSettings(settings);
|
||||
if (doubleBorder && viewSettings.vertical) {
|
||||
viewSettings.gapPercent = Math.max(
|
||||
viewSettings.gapPercent,
|
||||
Math.ceil(4800 / window.innerWidth),
|
||||
);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'doubleBorder', doubleBorder);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [doubleBorder]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.borderColor = borderColor;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.borderColor = borderColor;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'borderColor', borderColor);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [borderColor]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.showHeader = showHeader;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.showHeader = showHeader;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'showHeader', showHeader);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.showFooter = showFooter;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.showFooter = showFooter;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'showFooter', showFooter);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showFooter]);
|
||||
|
||||
@@ -473,9 +390,12 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
label={_('Horizontal Margins (%)')}
|
||||
value={gapPercent}
|
||||
onChange={setGapPercent}
|
||||
min={viewSettings.vertical ? 2 : 0}
|
||||
min={
|
||||
viewSettings.vertical && (showFooter || showHeader)
|
||||
? Math.ceil(4800 / window.innerWidth)
|
||||
: 0
|
||||
}
|
||||
max={30}
|
||||
step={0.5}
|
||||
/>
|
||||
<NumberInput
|
||||
label={_('Maximum Number of Columns')}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEnv } from '@/context/EnvContext';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { useTranslation } from '@/hooks/useTranslation';
|
||||
import { getStyles } from '@/utils/style';
|
||||
import { saveViewSettings } from '../../utils/viewSettingsHelper';
|
||||
import cssbeautify from 'cssbeautify';
|
||||
import cssValidate from '@/utils/css';
|
||||
|
||||
const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const { envConfig } = useEnv();
|
||||
const { settings, isFontLayoutSettingsGlobal, setSettings } = useSettingsStore();
|
||||
const { getView, getViewSettings, setViewSettings } = useReaderStore();
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
@@ -67,12 +70,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.animated = animated;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.animated = animated;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'animated', animated);
|
||||
if (animated) {
|
||||
getView(bookKey)?.renderer.setAttribute('animated', '');
|
||||
} else {
|
||||
@@ -82,22 +80,12 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
}, [animated]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.disableClick = isDisableClick;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.disableClick = isDisableClick;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'disableClick', isDisableClick);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isDisableClick]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.continuousScroll = isContinuousScroll;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.continuousScroll = isContinuousScroll;
|
||||
setSettings(settings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'continuousScroll', isContinuousScroll);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isContinuousScroll]);
|
||||
|
||||
|
||||
@@ -28,7 +28,9 @@ type TabConfig = {
|
||||
|
||||
const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ bookKey }) => {
|
||||
const _ = useTranslation();
|
||||
const [activePanel, setActivePanel] = useState<SettingsPanelType>('Font');
|
||||
const [activePanel, setActivePanel] = useState<SettingsPanelType>(
|
||||
(localStorage.getItem('lastConfigPanel') || 'Font') as SettingsPanelType,
|
||||
);
|
||||
const { setFontLayoutSettingsDialogOpen } = useSettingsStore();
|
||||
|
||||
const tabConfig = [
|
||||
@@ -54,6 +56,11 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo
|
||||
},
|
||||
] as TabConfig[];
|
||||
|
||||
const handleSetActivePanel = (tab: SettingsPanelType) => {
|
||||
setActivePanel(tab);
|
||||
localStorage.setItem('lastConfigPanel', tab);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setFontLayoutSettingsDialogOpen(false);
|
||||
};
|
||||
@@ -76,7 +83,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo
|
||||
>
|
||||
<MdArrowBackIosNew />
|
||||
</button>
|
||||
<div className='dialog-tabs flex h-10 max-w-[100%] flex-grow items-center pl-4 gap-2'>
|
||||
<div className='dialog-tabs flex h-10 max-w-[100%] flex-grow items-center gap-2 pl-4'>
|
||||
{tabConfig.map(({ tab, icon: Icon, label }) => (
|
||||
<button
|
||||
key={tab}
|
||||
@@ -84,7 +91,7 @@ const SettingsDialog: React.FC<{ bookKey: string; config: BookConfig }> = ({ boo
|
||||
'btn btn-ghost text-base-content btn-sm',
|
||||
activePanel === tab ? 'btn-active' : '',
|
||||
)}
|
||||
onClick={() => setActivePanel(tab)}
|
||||
onClick={() => handleSetActivePanel(tab)}
|
||||
>
|
||||
<Icon className='mr-0' />
|
||||
{window.innerWidth >= 500 ? label : ''}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { ViewSettings } from '@/types/book';
|
||||
import { EnvConfigType } from '@/services/environment';
|
||||
import { useBookDataStore } from '@/store/bookDataStore';
|
||||
import { useReaderStore } from '@/store/readerStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
|
||||
export const saveViewSettings = async <K extends keyof ViewSettings>(
|
||||
envConfig: EnvConfigType,
|
||||
bookKey: string,
|
||||
key: K,
|
||||
value: ViewSettings[K],
|
||||
skipGlobal?: boolean,
|
||||
) => {
|
||||
const { settings, isFontLayoutSettingsGlobal, setSettings, saveSettings } =
|
||||
useSettingsStore.getState();
|
||||
const { getViewSettings, setViewSettings } = useReaderStore.getState();
|
||||
const { getConfig, saveConfig } = useBookDataStore.getState();
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
const config = getConfig(bookKey)!;
|
||||
viewSettings[key] = value;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
|
||||
if (isFontLayoutSettingsGlobal && !skipGlobal) {
|
||||
settings.globalViewSettings[key] = value;
|
||||
setSettings(settings);
|
||||
}
|
||||
await saveConfig(envConfig, bookKey, config, settings);
|
||||
await saveSettings(envConfig, settings);
|
||||
};
|
||||
@@ -71,7 +71,7 @@ export const DEFAULT_BOOK_LAYOUT: BookLayout = {
|
||||
writingMode: 'auto',
|
||||
vertical: false,
|
||||
rtl: false,
|
||||
doubleBorder: true,
|
||||
doubleBorder: false,
|
||||
borderColor: 'red',
|
||||
showHeader: true,
|
||||
showFooter: true,
|
||||
|
||||
@@ -18,7 +18,6 @@ export const getSysFontsList = async (): Promise<string[]> => {
|
||||
if (FONT_ENUM_SUPPORTED_OS_PLATFORMS.includes(osPlatform)) {
|
||||
const fonts = await invoke<string[]>('list_fonts');
|
||||
cachedSysFonts = [...new Set(fonts.filter((font) => !isSymbolicFontName(font)))].sort();
|
||||
console.log('Fetched font list:', cachedSysFonts);
|
||||
return cachedSysFonts;
|
||||
} else {
|
||||
console.warn(`Unsupported platform: ${osPlatform}`);
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: ed663c9ea5...9f611d4084
Reference in New Issue
Block a user