config: add an option to sort TOC by page number, closes #1304 (#1308)

This commit is contained in:
Huang Xin
2025-06-02 13:23:59 +08:00
committed by GitHub
parent 87d610bb62
commit a9965fd52c
24 changed files with 90 additions and 42 deletions
@@ -337,5 +337,6 @@
"System Language": "لغة النظام",
"Security": "الأمان",
"Allow JavaScript": "السماح بـ JavaScript",
"Enable only if you trust the file.": "تمكين فقط إذا كنت تثق في الملف."
"Enable only if you trust the file.": "تمكين فقط إذا كنت تثق في الملف.",
"Sort TOC by Page": "ترتيب جدول المحتويات حسب الصفحة"
}
@@ -333,5 +333,6 @@
"System Language": "Systemsprache",
"Security": "Sicherheit",
"Allow JavaScript": "JavaScript zulassen",
"Enable only if you trust the file.": "Nur aktivieren, wenn Sie der Datei vertrauen."
"Enable only if you trust the file.": "Nur aktivieren, wenn Sie der Datei vertrauen.",
"Sort TOC by Page": "TOC nach Seite sortieren"
}
@@ -333,5 +333,6 @@
"System Language": "Γλώσσα συστήματος",
"Security": "Ασφάλεια",
"Allow JavaScript": "Επιτρέψτε JavaScript",
"Enable only if you trust the file.": "Ενεργοποιήστε μόνο εάν εμπιστεύεστε το αρχείο."
"Enable only if you trust the file.": "Ενεργοποιήστε μόνο εάν εμπιστεύεστε το αρχείο.",
"Sort TOC by Page": "Ταξινόμηση TOC κατά σελίδα"
}
@@ -334,5 +334,6 @@
"System Language": "Idioma del sistema",
"Security": "Seguridad",
"Allow JavaScript": "Permitir JavaScript",
"Enable only if you trust the file.": "Permitir solo si confías en el archivo."
"Enable only if you trust the file.": "Permitir solo si confías en el archivo.",
"Sort TOC by Page": "Ordenar TOC por página"
}
@@ -334,5 +334,6 @@
"System Language": "Langue du système",
"Security": "Sécurité",
"Allow JavaScript": "Autoriser JavaScript",
"Enable only if you trust the file.": "Activer uniquement si vous faites confiance au fichier."
"Enable only if you trust the file.": "Activer uniquement si vous faites confiance au fichier.",
"Sort TOC by Page": "Tris la table des matières par page"
}
@@ -333,5 +333,6 @@
"System Language": "सिस्टम भाषा",
"Security": "सुरक्षा",
"Allow JavaScript": "जावास्क्रिप्ट की अनुमति दें",
"Enable only if you trust the file.": "केवल तभी सक्षम करें जब आप फ़ाइल पर भरोसा करते हों।"
"Enable only if you trust the file.": "केवल तभी सक्षम करें जब आप फ़ाइल पर भरोसा करते हों।",
"Sort TOC by Page": "सामग्री को पृष्ठ द्वारा क्रमबद्ध करें"
}
@@ -332,5 +332,6 @@
"System Language": "Bahasa Sistem",
"Security": "Keamanan",
"Allow JavaScript": "Izinkan JavaScript",
"Enable only if you trust the file.": "Aktifkan hanya jika Anda mempercayai file tersebut."
"Enable only if you trust the file.": "Aktifkan hanya jika Anda mempercayai file tersebut.",
"Sort TOC by Page": "Urutkan TOC berdasarkan Halaman"
}
@@ -334,5 +334,6 @@
"System Language": "Lingua di sistema",
"Security": "Security",
"Allow JavaScript": "Consenti JavaScript",
"Enable only if you trust the file.": "Abilita solo se ti fidi del file."
"Enable only if you trust the file.": "Abilita solo se ti fidi del file.",
"Sort TOC by Page": "Ordina sommario per pagina"
}
@@ -332,5 +332,6 @@
"System Language": "システム言語",
"Security": "セキュリティ",
"Allow JavaScript": "JavaScriptを許可",
"Enable only if you trust the file.": "ファイルを信頼する場合にのみ有効にしてください。"
"Enable only if you trust the file.": "ファイルを信頼する場合にのみ有効にしてください。",
"Sort TOC by Page": "目次をページで並べ替え"
}
@@ -332,5 +332,6 @@
"System Language": "시스템 언어",
"Security": "보안",
"Allow JavaScript": "JavaScript 허용",
"Enable only if you trust the file.": "파일을 신뢰하는 경우에만 활성화하세요."
"Enable only if you trust the file.": "파일을 신뢰하는 경우에만 활성화하세요.",
"Sort TOC by Page": "목차를 페이지별로 정렬"
}
@@ -333,5 +333,6 @@
"System Language": "Systemtaal",
"Security": "Beveiliging",
"Allow JavaScript": "JavaScript toestaan",
"Enable only if you trust the file.": "Schakel alleen in als u het bestand vertrouwt."
"Enable only if you trust the file.": "Schakel alleen in als u het bestand vertrouwt.",
"Sort TOC by Page": "__STRING_NOT_TRANSLATED__"
}
@@ -335,5 +335,6 @@
"System Language": "Język systemu",
"Security": "Bezpieczeństwo",
"Allow JavaScript": "Zezwól na JavaScript",
"Enable only if you trust the file.": "Zezwól tylko wtedy, gdy ufasz plikowi."
"Enable only if you trust the file.": "Zezwól tylko wtedy, gdy ufasz plikowi.",
"Sort TOC by Page": "Sortuj spis treści według strony"
}
@@ -334,5 +334,6 @@
"System Language": "Idioma do Sistema",
"Security": "Segurança",
"Allow JavaScript": "Permitir JavaScript",
"Enable only if you trust the file.": "Ativar apenas se você confiar no arquivo."
"Enable only if you trust the file.": "Ativar apenas se você confiar no arquivo.",
"Sort TOC by Page": "Ordenar TOC por Página"
}
@@ -335,5 +335,6 @@
"System Language": "Системный язык",
"Security": "Безопасность",
"Allow JavaScript": "Разрешить JavaScript",
"Enable only if you trust the file.": "Включите только если доверяете файлу."
"Enable only if you trust the file.": "Включите только если доверяете файлу.",
"Sort TOC by Page": "Сортировать содержание по странице"
}
@@ -333,5 +333,6 @@
"System Language": "System Dili",
"Security": "Security",
"Allow JavaScript": "JavaScript'e İzin Ver",
"Enable only if you trust the file.": "Yalnızca dosyaya güveniyorsanız etkinleştirin."
"Enable only if you trust the file.": "Yalnızca dosyaya güveniyorsanız etkinleştirin.",
"Sort TOC by Page": "İçindekileri Sayfaya Göre Sırala"
}
@@ -335,5 +335,6 @@
"System Language": "Системна мова",
"Security": "Безпека",
"Allow JavaScript": "Дозволити JavaScript",
"Enable only if you trust the file.": "Увімкніть лише якщо довіряєте файлу."
"Enable only if you trust the file.": "Увімкніть лише якщо довіряєте файлу.",
"Sort TOC by Page": "Сортувати зміст за сторінкою"
}
@@ -332,5 +332,6 @@
"System Language": "Ngôn ngữ hệ thống",
"Security": "An ninh",
"Allow JavaScript": "Cho phép JavaScript",
"Enable only if you trust the file.": "Chỉ bật nếu bạn tin tưởng tệp."
"Enable only if you trust the file.": "Chỉ bật nếu bạn tin tưởng tệp.",
"Sort TOC by Page": "Sort Mục lục theo Trang"
}
@@ -332,5 +332,6 @@
"System Language": "系统语言",
"Security": "安全",
"Allow JavaScript": "允许 JavaScript",
"Enable only if you trust the file.": "建议仅在您信任该文件时启用"
"Enable only if you trust the file.": "建议仅在您信任该文件时启用",
"Sort TOC by Page": "按页码排序目录"
}
@@ -332,5 +332,6 @@
"System Language": "系統語言",
"Security": "安全",
"Allow JavaScript": "允許 JavaScript",
"Enable only if you trust the file.": "建議僅在您信任該檔案時啟用"
"Enable only if you trust the file.": "建議僅在您信任該檔案時啟用",
"Sort TOC by Page": "依頁碼排序目錄"
}
@@ -2,8 +2,9 @@ import clsx from 'clsx';
import React from 'react';
import Image from 'next/image';
import MenuItem from '@/components/MenuItem';
import { MdCheck } from 'react-icons/md';
import { setAboutDialogVisible } from '@/components/AboutWindow';
import { useReaderStore } from '@/store/readerStore';
import { useLibraryStore } from '@/store/libraryStore';
import { useSidebarStore } from '@/store/sidebarStore';
import { useTranslation } from '@/hooks/useTranslation';
@@ -11,6 +12,7 @@ import { isWebAppPlatform } from '@/services/environment';
import { eventDispatcher } from '@/utils/event';
import { DOWNLOAD_READEST_URL } from '@/services/constants';
import useBooksManager from '../../hooks/useBooksManager';
import MenuItem from '@/components/MenuItem';
interface BookMenuProps {
menuClassName?: string;
@@ -19,9 +21,13 @@ interface BookMenuProps {
const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen }) => {
const _ = useTranslation();
const { getViewSettings, setViewSettings } = useReaderStore();
const { getVisibleLibrary } = useLibraryStore();
const { openParallelView } = useBooksManager();
const { sideBarBookKey } = useSidebarStore();
const viewSettings = getViewSettings(sideBarBookKey!);
const [isSortedTOC, setIsSortedTOC] = React.useState(viewSettings?.sortedTOC || false);
const handleParallelView = (id: string) => {
openParallelView(id);
@@ -43,18 +49,25 @@ const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen })
eventDispatcher.dispatch('export-annotations', { bookKey: sideBarBookKey });
setIsDropdownOpen?.(false);
};
const handleToggleSortTOC = () => {
setIsSortedTOC((prev) => !prev);
setIsDropdownOpen?.(false);
if (sideBarBookKey) {
const viewSettings = getViewSettings(sideBarBookKey)!;
viewSettings.sortedTOC = !isSortedTOC;
setViewSettings(sideBarBookKey, viewSettings);
}
setTimeout(() => window.location.reload(), 100);
};
const isWebApp = isWebAppPlatform();
return (
<div
tabIndex={0}
className={clsx(
'book-menu dropdown-content border-base-100 z-20 w-60 shadow-2xl',
menuClassName,
)}
className={clsx('book-menu dropdown-content border-base-100 z-20 shadow-2xl', menuClassName)}
>
<MenuItem label={_('Parallel Read')} noIcon>
<MenuItem label={_('Parallel Read')}>
<ul className='max-h-60 overflow-y-auto'>
{getVisibleLibrary()
.filter((book) => book.format !== 'PDF' && book.format !== 'CBZ')
@@ -81,11 +94,16 @@ const BookMenu: React.FC<BookMenuProps> = ({ menuClassName, setIsDropdownOpen })
))}
</ul>
</MenuItem>
<MenuItem label={_('Export Annotations')} noIcon onClick={handleExportAnnotations} />
<MenuItem label={_('Reload Page')} noIcon shortcut='Shift+R' onClick={handleReloadPage} />
<MenuItem label={_('Export Annotations')} onClick={handleExportAnnotations} />
<MenuItem
label={_('Sort TOC by Page')}
Icon={isSortedTOC ? MdCheck : undefined}
onClick={handleToggleSortTOC}
/>
<MenuItem label={_('Reload Page')} shortcut='Shift+R' onClick={handleReloadPage} />
<hr className='border-base-200 my-1' />
{isWebApp && <MenuItem label={_('Download Readest')} noIcon onClick={downloadReadest} />}
<MenuItem label={_('About Readest')} noIcon onClick={showAboutReadest} />
{isWebApp && <MenuItem label={_('Download Readest')} onClick={downloadReadest} />}
<MenuItem label={_('About Readest')} onClick={showAboutReadest} />
</div>
);
};
@@ -142,6 +142,7 @@ export const DEFAULT_CJK_VIEW_SETTINGS: Partial<ViewSettings> = {
export const DEFAULT_VIEW_CONFIG: ViewConfig = {
sideBarTab: 'toc',
uiLanguage: '',
sortedTOC: false,
};
export const DEFAULT_TTS_CONFIG: TTSConfig = {
+3 -6
View File
@@ -3,7 +3,7 @@ import { create } from 'zustand';
import { BookContent, BookConfig, PageInfo, BookProgress, ViewSettings } from '@/types/book';
import { EnvConfigType } from '@/services/environment';
import { FoliateView } from '@/types/view';
import { BookDoc, DocumentLoader, TOCItem } from '@/libs/document';
import { DocumentLoader, TOCItem } from '@/libs/document';
import { updateToc } from '@/utils/toc';
import { useSettingsStore } from './settingsStore';
import { useBookDataStore } from './bookDataStore';
@@ -122,13 +122,10 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
const content = (await appService.loadBookContent(book, settings)) as BookContent;
const { file, config } = content;
console.log('Loading book', key);
const { book: loadedBookDoc } = await new DocumentLoader(file).open({
const { book: bookDoc } = await new DocumentLoader(file).open({
allowScript: config.viewSettings?.allowScript,
});
const bookDoc = loadedBookDoc as BookDoc;
if (bookDoc.toc?.length && bookDoc.sections?.length) {
updateToc(bookDoc, bookDoc.toc, bookDoc.sections);
}
updateToc(bookDoc, config.viewSettings?.sortedTOC ?? false);
// Set the book's language for formerly imported books, newly imported books have this field set
book.primaryLanguage =
book.primaryLanguage ?? getPrimaryLanguage(bookDoc.metadata.language);
+1
View File
@@ -121,6 +121,7 @@ export interface BookFont {
export interface ViewConfig {
sideBarTab: string;
uiLanguage: string;
sortedTOC: boolean;
}
export interface TTSConfig {
+19 -7
View File
@@ -37,7 +37,11 @@ export const findTocItemBS = (toc: TOCItem[], cfi: string): TOCItem | null => {
return result;
};
export const updateToc = (bookDoc: BookDoc, items: TOCItem[], sections: SectionItem[]): void => {
export const updateToc = (bookDoc: BookDoc, sortedTOC: boolean): void => {
const items = bookDoc?.toc || [];
const sections = bookDoc?.sections || [];
if (!items.length || !sections.length) return;
const sizes = sections.map((s) => (s.linear != 'no' && s.size > 0 ? s.size : 0));
let cumulativeSize = 0;
const cumulativeSizes = sizes.reduce((acc: number[], size) => {
@@ -59,13 +63,12 @@ export const updateToc = (bookDoc: BookDoc, items: TOCItem[], sections: SectionI
map[section.id] = section;
return map;
}, {});
updateTocData(bookDoc, items, sections, sectionsMap);
items.sort((a, b) => {
if (a.location && b.location) {
return a.location.current - b.location.current;
}
return 0;
});
if (sortedTOC) {
sortTocItems(items);
}
};
const updateTocData = (
@@ -95,3 +98,12 @@ const updateTocData = (
});
return index;
};
const sortTocItems = (items: TOCItem[]): void => {
items.sort((a, b) => {
if (a.location && b.location) {
return a.location.current - b.location.current;
}
return 0;
});
};