@@ -81,7 +81,7 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
/>
|
||||
<FoliateViewer bookKey={bookKey} bookDoc={bookDoc} config={config} />
|
||||
<FootnotePopup bookKey={bookKey} bookDoc={bookDoc} />
|
||||
{viewSettings.vertical && (
|
||||
{viewSettings.vertical && viewSettings.scrolled && (
|
||||
<>
|
||||
<div
|
||||
className='bg-base-100 absolute left-0 top-0 h-full'
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useClickEvent, useTouchEvent } from '../hooks/useIframeEvents';
|
||||
import { useFoliateEvents } from '../hooks/useFoliateEvents';
|
||||
import { useProgressSync } from '../hooks/useProgressSync';
|
||||
import { useProgressAutoSave } from '../hooks/useProgressAutoSave';
|
||||
import { applyColorScheme, getStyles, mountAdditionalFonts } from '@/utils/style';
|
||||
import { getStyles, mountAdditionalFonts } from '@/utils/style';
|
||||
import { getBookDirFromLanguage, getBookDirFromWritingMode } from '@/utils/book';
|
||||
import { useUICSS } from '@/hooks/useUICSS';
|
||||
import {
|
||||
@@ -35,7 +35,7 @@ const FoliateViewer: React.FC<{
|
||||
const { getView, setView: setFoliateView, setProgress } = useReaderStore();
|
||||
const { getViewSettings, setViewSettings } = useReaderStore();
|
||||
const { getParallels } = useParallelViewStore();
|
||||
const { themeCode, isDarkMode, getIsDarkMode } = useThemeStore();
|
||||
const { themeCode, isDarkMode } = useThemeStore();
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
|
||||
const [toastMessage, setToastMessage] = useState('');
|
||||
@@ -64,7 +64,6 @@ const FoliateViewer: React.FC<{
|
||||
viewSettings.rtl = writingDir?.rtl || viewSettings.writingMode.includes('rl') || false;
|
||||
setViewSettings(bookKey, { ...viewSettings });
|
||||
|
||||
applyColorScheme(detail.doc, getIsDarkMode());
|
||||
mountAdditionalFonts(detail.doc);
|
||||
|
||||
if (!detail.doc.isEventListenersAdded) {
|
||||
@@ -123,9 +122,6 @@ const FoliateViewer: React.FC<{
|
||||
if (viewRef.current && viewRef.current.renderer) {
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
viewRef.current.renderer.setStyles?.(getStyles(viewSettings));
|
||||
// Safari does not recognize color-scheme from the root document in iframe
|
||||
const doc = viewRef.current.renderer.getContents()[0]!.doc;
|
||||
applyColorScheme(doc, isDarkMode);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [themeCode, isDarkMode]);
|
||||
|
||||
@@ -164,6 +164,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
viewSettings.gapPercent,
|
||||
Math.ceil(4800 / window.innerWidth),
|
||||
);
|
||||
setGapPercent(viewSettings.gapPercent);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'doubleBorder', doubleBorder);
|
||||
@@ -176,11 +177,35 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
}, [borderColor]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showHeader && !viewSettings.vertical) {
|
||||
viewSettings.marginPx = Math.max(viewSettings.marginPx, 44);
|
||||
setMarginPx(viewSettings.marginPx);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
} else if (showHeader && viewSettings.vertical) {
|
||||
viewSettings.gapPercent = Math.max(
|
||||
viewSettings.gapPercent,
|
||||
Math.ceil(4800 / window.innerWidth),
|
||||
);
|
||||
setGapPercent(viewSettings.gapPercent);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'showHeader', showHeader);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showFooter && !viewSettings.vertical) {
|
||||
viewSettings.marginPx = Math.max(viewSettings.marginPx, 44);
|
||||
setMarginPx(viewSettings.marginPx);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
} else if (showFooter && viewSettings.vertical) {
|
||||
viewSettings.gapPercent = Math.max(
|
||||
viewSettings.gapPercent,
|
||||
Math.ceil(4800 / window.innerWidth),
|
||||
);
|
||||
setGapPercent(viewSettings.gapPercent);
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
}
|
||||
saveViewSettings(envConfig, bookKey, 'showFooter', showFooter);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showFooter]);
|
||||
@@ -382,7 +407,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
label={_('Vertical Margins (px)')}
|
||||
value={marginPx}
|
||||
onChange={setMarginPx}
|
||||
min={0}
|
||||
min={!viewSettings.vertical && (showFooter || showHeader) ? 44 : 0}
|
||||
max={88}
|
||||
step={4}
|
||||
/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FiMinus, FiPlus } from 'react-icons/fi';
|
||||
|
||||
interface NumberInputProps {
|
||||
@@ -26,6 +26,10 @@ const NumberInput: React.FC<NumberInputProps> = ({
|
||||
const [localValue, setLocalValue] = useState(value);
|
||||
const numberStep = step || 1;
|
||||
|
||||
useEffect(() => {
|
||||
setLocalValue(value);
|
||||
}, [value]);
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
|
||||
@@ -137,7 +137,11 @@ export const useTouchEvent = (
|
||||
if (hoveredBookKey && touchEnd) {
|
||||
const deltaY = touchEnd.screenY - touchStart.screenY;
|
||||
const deltaX = touchEnd.screenX - touchStart.screenX;
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 10) {
|
||||
if (!viewSettings!.scrolled && !viewSettings!.vertical) {
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY) && Math.abs(deltaX) > 10) {
|
||||
setHoveredBookKey(null);
|
||||
}
|
||||
} else {
|
||||
setHoveredBookKey(null);
|
||||
}
|
||||
}
|
||||
@@ -161,8 +165,10 @@ export const useTouchEvent = (
|
||||
Math.abs(deltaY) > Math.abs(deltaX) &&
|
||||
Math.abs(deltaX) < windowWidth * 0.3
|
||||
) {
|
||||
// swipe up to toggle the header bar and the footer bar
|
||||
setHoveredBookKey(hoveredBookKey ? null : bookKey);
|
||||
// swipe up to toggle the header bar and the footer bar, only for horizontal page mode
|
||||
if (!viewSettings!.scrolled && !viewSettings!.vertical) {
|
||||
setHoveredBookKey(hoveredBookKey ? null : bookKey);
|
||||
}
|
||||
} else {
|
||||
if (hoveredBookKey) {
|
||||
setHoveredBookKey(null);
|
||||
@@ -187,15 +193,10 @@ export const useTouchEvent = (
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// swipe touch is not compatible with scrolled mode, so only enable it in page mode
|
||||
if (!viewSettings!.scrolled) {
|
||||
window.addEventListener('message', handleTouch);
|
||||
return () => {
|
||||
window.removeEventListener('message', handleTouch);
|
||||
};
|
||||
} else {
|
||||
return () => {};
|
||||
}
|
||||
window.addEventListener('message', handleTouch);
|
||||
return () => {
|
||||
window.removeEventListener('message', handleTouch);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [hoveredBookKey, viewRef]);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useEffect } from 'react';
|
||||
import { useThemeStore } from '@/store/themeStore';
|
||||
import { useSettingsStore } from '@/store/settingsStore';
|
||||
import { applyCustomTheme } from '@/styles/themes';
|
||||
import { applyColorScheme } from '@/utils/style';
|
||||
|
||||
export const useTheme = () => {
|
||||
const { settings } = useSettingsStore();
|
||||
@@ -17,6 +16,6 @@ export const useTheme = () => {
|
||||
useEffect(() => {
|
||||
const colorScheme = isDarkMode ? 'dark' : 'light';
|
||||
document.documentElement.setAttribute('data-theme', `${themeColor}-${colorScheme}`);
|
||||
applyColorScheme(document, isDarkMode);
|
||||
document.documentElement.style.setProperty('color-scheme', colorScheme);
|
||||
}, [themeColor, isDarkMode]);
|
||||
};
|
||||
|
||||
@@ -137,10 +137,11 @@ const getLayoutStyles = (
|
||||
bg: string,
|
||||
fg: string,
|
||||
primary: string,
|
||||
isDarkMode: boolean,
|
||||
) => `
|
||||
@namespace epub "http://www.idpf.org/2007/ops";
|
||||
html {
|
||||
color-scheme: light dark;
|
||||
color-scheme: ${isDarkMode ? 'dark' : 'light'};
|
||||
color: ${fg};
|
||||
}
|
||||
a:any-link {
|
||||
@@ -158,6 +159,8 @@ const getLayoutStyles = (
|
||||
|
||||
html {
|
||||
--theme-bg-color: ${bg};
|
||||
--theme-fg-color: ${fg};
|
||||
--theme-primary-color: ${primary};
|
||||
--default-text-align: ${justify ? 'justify' : 'start'};
|
||||
hanging-punctuation: allow-end last;
|
||||
orphans: 2;
|
||||
@@ -248,15 +251,19 @@ export const getFootnoteStyles = () => `
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 1em !important;
|
||||
}
|
||||
|
||||
a:any-link {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
padding: 1em !important;
|
||||
}
|
||||
|
||||
p, li, blockquote, dd {
|
||||
margin: unset;
|
||||
text-indent: unset;
|
||||
@@ -268,6 +275,7 @@ export interface ThemeCode {
|
||||
fg: string;
|
||||
primary: string;
|
||||
palette: Palette;
|
||||
isDarkMode: boolean;
|
||||
}
|
||||
|
||||
export const getThemeCode = () => {
|
||||
@@ -303,6 +311,7 @@ export const getThemeCode = () => {
|
||||
fg: defaultPalette['base-content'],
|
||||
primary: defaultPalette.primary,
|
||||
palette: defaultPalette,
|
||||
isDarkMode,
|
||||
} as ThemeCode;
|
||||
};
|
||||
|
||||
@@ -325,6 +334,7 @@ export const getStyles = (viewSettings: ViewSettings, themeCode?: ThemeCode) =>
|
||||
themeCode.bg,
|
||||
themeCode.fg,
|
||||
themeCode.primary,
|
||||
themeCode.isDarkMode,
|
||||
);
|
||||
// scale the font size on-the-fly so that we can sync the same font size on different devices
|
||||
const isMobile = ['ios', 'android'].includes(getOSPlatform());
|
||||
@@ -364,8 +374,3 @@ export const mountAdditionalFonts = (document: Document) => {
|
||||
style.textContent = getAdditionalFontFaces();
|
||||
document.head.appendChild(style);
|
||||
};
|
||||
|
||||
export const applyColorScheme = (document: Document, isDarkMode: boolean) => {
|
||||
const colorScheme = isDarkMode ? 'dark' : 'light';
|
||||
document.documentElement.style.setProperty('color-scheme', colorScheme);
|
||||
};
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: b4a0bbca87...5fb4a4b46e
Reference in New Issue
Block a user