forked from akai/readest
feat: add options to show/hide header and footer widgets in paginated and scrolled mode, also closes #602 (#620)
This commit is contained in:
@@ -244,5 +244,8 @@
|
||||
"Contrast": "التباين",
|
||||
"Sunset": "غروب الشمس",
|
||||
"Double Border": "حدود مزدوجة",
|
||||
"Border Color": "لون الحدود"
|
||||
"Border Color": "لون الحدود",
|
||||
"Border Frame": "إطار الحدود",
|
||||
"Show Header": "عرض الرأس",
|
||||
"Show Footer": "عرض التذييل"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Kontrast",
|
||||
"Sunset": "Sonnenuntergang",
|
||||
"Double Border": "Doppelter Rand",
|
||||
"Border Color": "Randfarbe"
|
||||
"Border Color": "Randfarbe",
|
||||
"Border Frame": "Rahmenrand",
|
||||
"Show Header": "Kopfzeile anzeigen",
|
||||
"Show Footer": "Fußzeile anzeigen"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Αντίθεση",
|
||||
"Sunset": "Ηλιοβασίλεμα",
|
||||
"Double Border": "Διπλό περιθώριο",
|
||||
"Border Color": "Χρώμα περιγράμματος"
|
||||
"Border Color": "Χρώμα περιγράμματος",
|
||||
"Border Frame": "Πλαίσιο περιγράμματος",
|
||||
"Show Header": "Εμφάνιση κεφαλίδας",
|
||||
"Show Footer": "Εμφάνιση υποσέλιδου"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Contraste",
|
||||
"Sunset": "Atardecer",
|
||||
"Double Border": "Doble borde",
|
||||
"Border Color": "Color del borde"
|
||||
"Border Color": "Color del borde",
|
||||
"Border Frame": "Marco de borde",
|
||||
"Show Header": "Mostrar encabezado",
|
||||
"Show Footer": "Mostrar pie de página"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Contraste",
|
||||
"Sunset": "Coucher de soleil",
|
||||
"Double Border": "Double bordure",
|
||||
"Border Color": "Couleur de la bordure"
|
||||
"Border Color": "Couleur de la bordure",
|
||||
"Border Frame": "Cadre de bordure",
|
||||
"Show Header": "Afficher l'en-tête",
|
||||
"Show Footer": "Afficher le pied de page"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "विरोधाभास",
|
||||
"Sunset": "सनसेट",
|
||||
"Double Border": "डबल बॉर्डर",
|
||||
"Border Color": "बॉर्डर रंग"
|
||||
"Border Color": "बॉर्डर रंग",
|
||||
"Border Frame": "बॉर्डर फ्रेम",
|
||||
"Show Header": "हेडर दिखाएं",
|
||||
"Show Footer": "फ़ुटर दिखाएं"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Kontras",
|
||||
"Sunset": "Senja",
|
||||
"Double Border": "Garis Ganda",
|
||||
"Border Color": "Warna Garis"
|
||||
"Border Color": "Warna Garis",
|
||||
"Border Frame": "Bingkai Garis",
|
||||
"Show Header": "Tampilkan Header",
|
||||
"Show Footer": "Tampilkan Footer"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Contrasto",
|
||||
"Sunset": "Tramonto",
|
||||
"Double Border": "Doppio bordo",
|
||||
"Border Color": "Colore bordo"
|
||||
"Border Color": "Colore bordo",
|
||||
"Border Frame": "Cornice bordo",
|
||||
"Show Header": "Mostra intestazione",
|
||||
"Show Footer": "Mostra piè di pagina"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "コントラスト",
|
||||
"Sunset": "サンセット",
|
||||
"Double Border": "二重枠",
|
||||
"Border Color": "ボーダーカラー"
|
||||
"Border Color": "ボーダーカラー",
|
||||
"Border Frame": "ボーダーフレーム",
|
||||
"Show Header": "ヘッダーを表示",
|
||||
"Show Footer": "フッターを表示"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "대비",
|
||||
"Sunset": "일몰",
|
||||
"Double Border": "이중 테두리",
|
||||
"Border Color": "테두리 색상"
|
||||
"Border Color": "테두리 색상",
|
||||
"Border Frame": "테두리 프레임",
|
||||
"Show Header": "헤더 표시",
|
||||
"Show Footer": "푸터 표시"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Kontrast",
|
||||
"Sunset": "Zachód słońca",
|
||||
"Double Border": "Podwójna ramka",
|
||||
"Border Color": "Kolor ramki"
|
||||
"Border Color": "Kolor ramki",
|
||||
"Border Frame": "Ramka",
|
||||
"Show Header": "Pokaż nagłówek",
|
||||
"Show Footer": "Pokaż stopkę"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Contraste",
|
||||
"Sunset": "Pôr do Sol",
|
||||
"Double Border": "Borda Dupla",
|
||||
"Border Color": "Cor da Borda"
|
||||
"Border Color": "Cor da Borda",
|
||||
"Border Frame": "Moldura da Borda",
|
||||
"Show Header": "Mostrar Cabeçalho",
|
||||
"Show Footer": "Mostrar Rodapé"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Контраст",
|
||||
"Sunset": "Закат",
|
||||
"Double Border": "Двойная граница",
|
||||
"Border Color": "Цвет границы"
|
||||
"Border Color": "Цвет границы",
|
||||
"Border Frame": "Граница рамки",
|
||||
"Show Header": "Показать заголовок",
|
||||
"Show Footer": "Показать нижний колонтитул"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Kontrast",
|
||||
"Sunset": "Gün Batımı",
|
||||
"Double Border": "Çift Sınır",
|
||||
"Border Color": "Sınır Rengi"
|
||||
"Border Color": "Sınır Rengi",
|
||||
"Border Frame": "Sınır Çerçevesi",
|
||||
"Show Header": "Başlık Göster",
|
||||
"Show Footer": "Altbilgi Göster"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Контраст",
|
||||
"Sunset": "Захід сонця",
|
||||
"Double Border": "Подвійна рамка",
|
||||
"Border Color": "Колір рамки"
|
||||
"Border Color": "Колір рамки",
|
||||
"Border Frame": "Рамка рамки",
|
||||
"Show Header": "Показати заголовок",
|
||||
"Show Footer": "Показати нижню частину"
|
||||
}
|
||||
|
||||
@@ -244,5 +244,8 @@
|
||||
"Contrast": "Tương phản",
|
||||
"Sunset": "Hoàng hôn",
|
||||
"Double Border": "Đôi viền",
|
||||
"Border Color": "Màu viền"
|
||||
"Border Color": "Màu viền",
|
||||
"Border Frame": "Khung viền",
|
||||
"Show Header": "Hiển thị tiêu đề",
|
||||
"Show Footer": "Hiển thị chân trang"
|
||||
}
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
"Preview": "预览",
|
||||
"Contrast": "对比",
|
||||
"Sunset": "日落",
|
||||
"Double Border": "页面版框",
|
||||
"Border Color": "版框颜色"
|
||||
"Double Border": "显示版框",
|
||||
"Border Color": "版框颜色",
|
||||
"Border Frame": "页面版框",
|
||||
"Show Header": "显示页眉",
|
||||
"Show Footer": "显示页脚"
|
||||
}
|
||||
|
||||
@@ -243,6 +243,9 @@
|
||||
"Preview": "預覽",
|
||||
"Contrast": "對比",
|
||||
"Sunset": "日落",
|
||||
"Double Border": "頁面邊框",
|
||||
"Border Color": "邊框顏色"
|
||||
"Double Border": "顯示邊框",
|
||||
"Border Color": "邊框顏色",
|
||||
"Border Frame": "頁面邊框",
|
||||
"Show Header": "顯示頁眉",
|
||||
"Show Footer": "顯示頁腳"
|
||||
}
|
||||
|
||||
@@ -81,36 +81,50 @@ const BooksGrid: React.FC<BooksGridProps> = ({ bookKeys, onCloseBook }) => {
|
||||
/>
|
||||
<FoliateViewer bookKey={bookKey} bookDoc={bookDoc} config={config} />
|
||||
<FootnotePopup bookKey={bookKey} bookDoc={bookDoc} />
|
||||
{viewSettings.scrolled ? null : (
|
||||
<>
|
||||
{viewSettings.vertical && viewSettings.doubleBorder && (
|
||||
<DoubleBorder
|
||||
borderColor={viewSettings.borderColor}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
)}
|
||||
<SectionInfo
|
||||
section={sectionLabel}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
<HintInfo
|
||||
bookKey={bookKey}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
<PageInfoView
|
||||
bookFormat={book.format}
|
||||
section={section}
|
||||
pageinfo={pageinfo}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
</>
|
||||
<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 && viewSettings.doubleBorder && (
|
||||
<DoubleBorder
|
||||
showHeader={viewSettings.showHeader}
|
||||
showFooter={viewSettings.showFooter}
|
||||
borderColor={viewSettings.borderColor}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
)}
|
||||
{viewSettings.showHeader && (
|
||||
<SectionInfo
|
||||
section={sectionLabel}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
)}
|
||||
<HintInfo
|
||||
bookKey={bookKey}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
{viewSettings.showFooter && (
|
||||
<PageInfoView
|
||||
bookFormat={book.format}
|
||||
section={section}
|
||||
pageinfo={pageinfo}
|
||||
isVertical={viewSettings.vertical}
|
||||
horizontalGap={horizontalGapPercent}
|
||||
verticalMargin={verticalMarginPixels}
|
||||
/>
|
||||
)}
|
||||
<Annotator bookKey={bookKey} />
|
||||
<FooterBar
|
||||
|
||||
@@ -2,6 +2,8 @@ interface DoubleBorderProps {
|
||||
borderColor: string;
|
||||
horizontalGap: number;
|
||||
verticalMargin: number;
|
||||
showHeader: boolean;
|
||||
showFooter: boolean;
|
||||
}
|
||||
|
||||
const paddingPx = 10;
|
||||
@@ -10,51 +12,63 @@ const DoubleBorder: React.FC<DoubleBorderProps> = ({
|
||||
borderColor,
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
showHeader,
|
||||
showFooter,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
{/* outter frame */}
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
border: `4px solid ${borderColor}`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px + ${paddingPx * 2}px)`,
|
||||
top: `calc(${verticalMargin}px - ${paddingPx}px)`,
|
||||
left: `calc(${horizontalGap * 2}% - 32px - ${paddingPx}px)`,
|
||||
right: `calc(${horizontalGap * 2}% - 32px - ${paddingPx}px)`,
|
||||
left: `calc(${horizontalGap}% - ${showFooter ? 32 : 0}px - ${paddingPx}px)`,
|
||||
right: `calc(${horizontalGap}% - ${showHeader ? 32 : 0}px - ${paddingPx}px)`,
|
||||
}}
|
||||
></div>
|
||||
{/* inner frame */}
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
border: `1px solid ${borderColor}`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
top: `${verticalMargin}px`,
|
||||
left: `${horizontalGap * 2}%`,
|
||||
right: `${horizontalGap * 2}%`,
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
border: `1px solid ${borderColor}`,
|
||||
width: '32px',
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
top: `${verticalMargin}px`,
|
||||
left: `calc(${horizontalGap * 2}% - 32px)`,
|
||||
borderRight: 'none',
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
border: `1px solid ${borderColor}`,
|
||||
width: '32px',
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
top: `${verticalMargin}px`,
|
||||
left: `calc(100% - ${horizontalGap * 2}%)`,
|
||||
borderLeft: 'none',
|
||||
left: showFooter ? `${horizontalGap}%` : `calc(${horizontalGap}%)`,
|
||||
right: showHeader ? `${horizontalGap}%` : `calc(${horizontalGap}%)`,
|
||||
}}
|
||||
/>
|
||||
{/* footer */}
|
||||
{showFooter && (
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
borderTop: `1px solid ${borderColor}`,
|
||||
borderBottom: `1px solid ${borderColor}`,
|
||||
borderLeft: `1px solid ${borderColor}`,
|
||||
width: '32px',
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
top: `${verticalMargin}px`,
|
||||
left: `calc(${horizontalGap}% - 32px)`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{/* header */}
|
||||
{showHeader && (
|
||||
<div
|
||||
className={'borderframe pointer-events-none absolute'}
|
||||
style={{
|
||||
borderTop: `1px solid ${borderColor}`,
|
||||
borderBottom: `1px solid ${borderColor}`,
|
||||
borderRight: `1px solid ${borderColor}`,
|
||||
width: '32px',
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
top: `${verticalMargin}px`,
|
||||
left: `calc(100% - ${horizontalGap}%)`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -35,7 +35,7 @@ const FoliateViewer: React.FC<{
|
||||
const { getView, setView: setFoliateView, setProgress } = useReaderStore();
|
||||
const { getViewSettings, setViewSettings } = useReaderStore();
|
||||
const { getParallels } = useParallelViewStore();
|
||||
const { themeCode, isDarkMode } = useThemeStore();
|
||||
const { themeCode, isDarkMode, getIsDarkMode } = useThemeStore();
|
||||
const viewSettings = getViewSettings(bookKey)!;
|
||||
|
||||
const [toastMessage, setToastMessage] = useState('');
|
||||
@@ -64,7 +64,7 @@ const FoliateViewer: React.FC<{
|
||||
viewSettings.rtl = writingDir?.rtl || viewSettings.writingMode.includes('rl') || false;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
|
||||
applyColorScheme(detail.doc, isDarkMode);
|
||||
applyColorScheme(detail.doc, getIsDarkMode());
|
||||
mountAdditionalFonts(detail.doc);
|
||||
|
||||
if (!detail.doc.isEventListenersAdded) {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import clsx from 'clsx';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { useTrafficLightStore } from '@/store/trafficLightStore';
|
||||
import { eventDispatcher } from '@/utils/event';
|
||||
|
||||
interface SectionInfoProps {
|
||||
@@ -17,8 +15,6 @@ const HintInfo: React.FC<SectionInfoProps> = ({
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
}) => {
|
||||
const { isSideBarVisible } = useSidebarStore();
|
||||
const { isTrafficLightVisible } = useTrafficLightStore();
|
||||
const [hintMessage, setHintMessage] = React.useState<string | null>(null);
|
||||
const hintTimeout = useRef(2000);
|
||||
const dismissTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
@@ -49,17 +45,15 @@ const HintInfo: React.FC<SectionInfoProps> = ({
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'sectioninfo absolute flex justify-end overflow-hidden',
|
||||
!isVertical && (isTrafficLightVisible && !isSideBarVisible ? 'h-[44px]' : 'h-[30px]'),
|
||||
isVertical ? 'writing-vertical-rl w-[32px] items-center' : 'top-0 items-end',
|
||||
isVertical ? 'max-h-[50%]' : 'max-w-[50%]',
|
||||
'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%]',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
bottom: `calc(${horizontalGap / 2}% + ${verticalMargin}px)`,
|
||||
left: `calc(100% - ${horizontalGap * 2}%)`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
bottom: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(100% - ${horizontalGap}%)`,
|
||||
}
|
||||
: { right: `${horizontalGap}%` }
|
||||
}
|
||||
|
||||
@@ -42,14 +42,13 @@ const PageInfoView: React.FC<PageInfoProps> = ({
|
||||
<div
|
||||
className={clsx(
|
||||
'pageinfo absolute bottom-0 flex items-center justify-end',
|
||||
isVertical ? 'left-0' : 'right-0',
|
||||
isVertical ? 'writing-vertical-rl w-[32px]' : 'h-12',
|
||||
isVertical ? 'writing-vertical-rl left-0 w-[32px]' : 'bg-base-100 right-0 h-12 w-full',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
bottom: `calc(${horizontalGap / 2}% + ${verticalMargin}px)`,
|
||||
left: `calc(${horizontalGap * 2}% - 32px)`,
|
||||
bottom: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(${horizontalGap}% - 32px)`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
}
|
||||
: { paddingRight: `${horizontalGap}%` }
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
|
||||
import { useSidebarStore } from '@/store/sidebarStore';
|
||||
import { useTrafficLightStore } from '@/store/trafficLightStore';
|
||||
|
||||
interface SectionInfoProps {
|
||||
section?: string;
|
||||
isVertical: boolean;
|
||||
@@ -17,24 +14,22 @@ const SectionInfo: React.FC<SectionInfoProps> = ({
|
||||
horizontalGap,
|
||||
verticalMargin,
|
||||
}) => {
|
||||
const { isSideBarVisible } = useSidebarStore();
|
||||
const { isTrafficLightVisible } = useTrafficLightStore();
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
'sectioninfo absolute flex overflow-hidden',
|
||||
!isVertical && (isTrafficLightVisible && !isSideBarVisible ? 'h-[44px]' : 'h-[30px]'),
|
||||
isVertical ? 'writing-vertical-rl w-[32px] items-center' : 'top-0 items-end',
|
||||
isVertical ? 'max-h-[50%]' : 'max-w-[50%]',
|
||||
'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',
|
||||
)}
|
||||
style={
|
||||
isVertical
|
||||
? {
|
||||
top: `calc(${horizontalGap / 2}% + ${verticalMargin}px)`,
|
||||
left: `calc(100% - ${horizontalGap * 2}%)`,
|
||||
top: `${verticalMargin * 1.5}px`,
|
||||
left: `calc(100% - ${horizontalGap}%)`,
|
||||
height: `calc(100% - ${verticalMargin * 2}px)`,
|
||||
}
|
||||
: { left: `${horizontalGap}%` }
|
||||
: { paddingLeft: `${horizontalGap}%` }
|
||||
}
|
||||
>
|
||||
<h2 className={clsx('text-neutral-content text-center font-sans text-xs font-light')}>
|
||||
|
||||
@@ -225,7 +225,6 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
className='config-item-top'
|
||||
label={_('Default Font Size')}
|
||||
value={defaultFontSize}
|
||||
onChange={setDefaultFontSize}
|
||||
@@ -233,7 +232,6 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
max={120}
|
||||
/>
|
||||
<NumberInput
|
||||
className='config-item-bottom'
|
||||
label={_('Minimum Font Size')}
|
||||
value={minFontSize}
|
||||
onChange={setMinFontSize}
|
||||
@@ -249,7 +247,6 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
className='config-item-top'
|
||||
label={_('Font Weight')}
|
||||
value={fontWeight}
|
||||
onChange={setFontWeight}
|
||||
@@ -265,7 +262,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<h2 className='mb-2 font-medium'>{_('Font Family')}</h2>
|
||||
<div className='card border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item config-item-top'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Default Font')}</span>
|
||||
<FontDropdown
|
||||
options={fontFamilyOptions}
|
||||
@@ -275,7 +272,7 @@ const FontPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='config-item config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Override Book Font')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
|
||||
@@ -40,6 +40,8 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
const [isScrolledMode, setScrolledMode] = useState(viewSettings.scrolled!);
|
||||
const [doubleBorder, setDoubleBorder] = useState(viewSettings.doubleBorder!);
|
||||
const [borderColor, setBorderColor] = useState(viewSettings.borderColor!);
|
||||
const [showHeader, setShowHeader] = useState(viewSettings.showHeader!);
|
||||
const [showFooter, setShowFooter] = useState(viewSettings.showFooter!);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.paragraphMargin = paragraphMargin;
|
||||
@@ -246,6 +248,26 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [borderColor]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.showHeader = showHeader;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.showHeader = showHeader;
|
||||
setSettings(settings);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
viewSettings.showFooter = showFooter;
|
||||
setViewSettings(bookKey, viewSettings);
|
||||
if (isFontLayoutSettingsGlobal) {
|
||||
settings.globalViewSettings.showFooter = showFooter;
|
||||
setSettings(settings);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [showFooter]);
|
||||
|
||||
const langCode = getBookLangCode(bookData.bookDoc?.metadata?.language);
|
||||
const mightBeRTLBook = MIGHT_BE_RTL_LANGS.includes(langCode) || isCJKEnv();
|
||||
|
||||
@@ -309,36 +331,37 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
)}
|
||||
|
||||
{viewSettings.vertical && (
|
||||
<>
|
||||
<div className='w-full'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<h2 className='font-medium'>{_('Double Border')}</h2>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
checked={doubleBorder}
|
||||
onChange={() => setDoubleBorder(!doubleBorder)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className='w-full'>
|
||||
<h2 className='mb-2 font-medium'>{_('Border Frame')}</h2>
|
||||
<div className='card bg-base-100 border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Double Border')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
checked={doubleBorder}
|
||||
onChange={() => setDoubleBorder(!doubleBorder)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='w-full'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<h2 className='font-medium'>{_('Border Color')}</h2>
|
||||
<div className='flex gap-4'>
|
||||
<button
|
||||
className={`btn btn-circle btn-sm bg-red-300 hover:bg-red-500 ${borderColor === 'red' ? 'btn-active !bg-red-500' : ''}`}
|
||||
onClick={() => setBorderColor('red')}
|
||||
></button>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Border Color')}</span>
|
||||
<div className='flex gap-4'>
|
||||
<button
|
||||
className={`btn btn-circle btn-sm bg-red-300 hover:bg-red-500 ${borderColor === 'red' ? 'btn-active !bg-red-500' : ''}`}
|
||||
onClick={() => setBorderColor('red')}
|
||||
></button>
|
||||
|
||||
<button
|
||||
className={`btn btn-circle btn-sm bg-black/50 hover:bg-black ${borderColor === 'black' ? 'btn-active !bg-black' : ''}`}
|
||||
onClick={() => setBorderColor('black')}
|
||||
></button>
|
||||
<button
|
||||
className={`btn btn-circle btn-sm bg-black/50 hover:bg-black ${borderColor === 'black' ? 'btn-active !bg-black' : ''}`}
|
||||
onClick={() => setBorderColor('black')}
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='w-full'>
|
||||
@@ -346,7 +369,6 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<div className='card bg-base-100 border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<NumberInput
|
||||
className='config-item-top'
|
||||
label={_('Paragraph Margin')}
|
||||
value={paragraphMargin}
|
||||
onChange={setParagraphMargin}
|
||||
@@ -386,7 +408,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
max={4}
|
||||
step={1}
|
||||
/>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Full Justification')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -395,7 +417,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
onChange={() => setFullJustification(!fullJustification)}
|
||||
/>
|
||||
</div>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Hyphenation')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -404,7 +426,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
onChange={() => setHyphenation(!hyphenation)}
|
||||
/>
|
||||
</div>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Override Book Layout')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -421,8 +443,25 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<h2 className='mb-2 font-medium'>{_('Page')}</h2>
|
||||
<div className='card bg-base-100 border-base-200 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Show Header')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
checked={showHeader}
|
||||
onChange={() => setShowHeader(!showHeader)}
|
||||
/>
|
||||
</div>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Show Footer')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
className='toggle'
|
||||
checked={showFooter}
|
||||
onChange={() => setShowFooter(!showFooter)}
|
||||
/>
|
||||
</div>
|
||||
<NumberInput
|
||||
className='config-item-top'
|
||||
label={_('Vertical Margins (px)')}
|
||||
value={marginPx}
|
||||
onChange={setMarginPx}
|
||||
@@ -436,6 +475,7 @@ const LayoutPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
onChange={setGapPercent}
|
||||
min={viewSettings.vertical ? 2 : 0}
|
||||
max={30}
|
||||
step={0.5}
|
||||
/>
|
||||
<NumberInput
|
||||
label={_('Maximum Number of Columns')}
|
||||
|
||||
@@ -107,7 +107,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<h2 className='mb-2 font-medium'>{_('Animation')}</h2>
|
||||
<div className='card border-base-200 bg-base-100 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item config-item-top config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Paging Animation')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -124,7 +124,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
<h2 className='mb-2 font-medium'>{_('Behavior')}</h2>
|
||||
<div className='card border-base-200 bg-base-100 border shadow'>
|
||||
<div className='divide-base-200 divide-y'>
|
||||
<div className='config-item config-item-top'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Continuous Scroll')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
@@ -133,7 +133,7 @@ const MiscPanel: React.FC<{ bookKey: string }> = ({ bookKey }) => {
|
||||
onChange={() => setIsContinuousScroll(!isContinuousScroll)}
|
||||
/>
|
||||
</div>
|
||||
<div className='config-item config-item-bottom'>
|
||||
<div className='config-item'>
|
||||
<span className=''>{_('Disable Click-to-Flip')}</span>
|
||||
<input
|
||||
type='checkbox'
|
||||
|
||||
@@ -73,6 +73,8 @@ export const DEFAULT_BOOK_LAYOUT: BookLayout = {
|
||||
rtl: false,
|
||||
doubleBorder: true,
|
||||
borderColor: 'red',
|
||||
showHeader: true,
|
||||
showFooter: true,
|
||||
};
|
||||
|
||||
export const DEFAULT_BOOK_STYLE: BookStyle = {
|
||||
|
||||
@@ -10,6 +10,7 @@ interface ThemeState {
|
||||
systemIsDarkMode: boolean;
|
||||
themeCode: ThemeCode;
|
||||
isDarkMode: boolean;
|
||||
getIsDarkMode: () => boolean;
|
||||
setThemeMode: (mode: ThemeMode) => void;
|
||||
setThemeColor: (color: string) => void;
|
||||
updateAppTheme: (color: keyof Palette) => void;
|
||||
@@ -61,6 +62,7 @@ export const useThemeStore = create<ThemeState>((set, get) => {
|
||||
systemIsDarkMode,
|
||||
isDarkMode,
|
||||
themeCode,
|
||||
getIsDarkMode: () => get().isDarkMode,
|
||||
setThemeMode: (mode) => {
|
||||
if (typeof window !== 'undefined' && localStorage) {
|
||||
localStorage.setItem('themeMode', mode);
|
||||
|
||||
@@ -191,14 +191,6 @@ foliate-view {
|
||||
@apply hover:bg-base-100/50;
|
||||
}
|
||||
|
||||
.config-item-top {
|
||||
@apply rounded-t-2xl;
|
||||
}
|
||||
|
||||
.config-item-bottom {
|
||||
@apply rounded-b-2xl;
|
||||
}
|
||||
|
||||
.collapse-arrow > .collapse-title:after {
|
||||
top: var(--top-override, default-value);
|
||||
inset-inline-end: var(--end-override, default-value);
|
||||
|
||||
@@ -70,6 +70,8 @@ export interface BookLayout {
|
||||
rtl: boolean;
|
||||
doubleBorder: boolean;
|
||||
borderColor: string;
|
||||
showHeader: boolean;
|
||||
showFooter: boolean;
|
||||
}
|
||||
|
||||
export interface BookStyle {
|
||||
|
||||
+1
-1
Submodule packages/foliate-js updated: c50960743b...ed663c9ea5
Reference in New Issue
Block a user