Get rid of unnecessary data fields in BookConfig

This commit is contained in:
chrox
2024-12-17 22:33:18 +01:00
parent 419db86a4d
commit bd549d2a0f
9 changed files with 67 additions and 27 deletions
@@ -26,7 +26,7 @@ const BookmarkToggler: React.FC<BookmarkTogglerProps> = ({ bookKey }) => {
const toggleBookmark = () => {
const { booknotes: bookmarks = [] } = config;
const { location: cfi, sectionHref: href, range } = progress;
const { location: cfi, range } = progress;
if (!cfi) return;
if (!isBookmarked) {
setIsBookmarked(true);
@@ -36,7 +36,6 @@ const BookmarkToggler: React.FC<BookmarkTogglerProps> = ({ bookKey }) => {
id: uniqueId(),
type: 'bookmark',
cfi,
href,
text: truncatedText,
note: '',
created: Date.now(),
@@ -217,14 +217,12 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
const { booknotes: annotations = [] } = config;
if (selection) navigator.clipboard.writeText(selection.text);
const { sectionHref: href } = progress;
const cfi = view?.getCFI(selection.index, selection.range);
if (!cfi) return;
const annotation: BookNote = {
id: uniqueId(),
type: 'excerpt',
cfi,
href,
text: selection.text,
note: '',
created: Date.now(),
@@ -250,7 +248,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
if (!selection || !selection.text) return;
setHighlightOptionsVisible(true);
const { booknotes: annotations = [] } = config;
const { sectionHref: href } = progress;
const cfi = view?.getCFI(selection.index, selection.range);
if (!cfi) return;
const style = settings.globalReadSettings.highlightStyle;
@@ -259,7 +256,6 @@ const Annotator: React.FC<{ bookKey: string }> = ({ bookKey }) => {
id: uniqueId(),
type: 'annotation',
cfi,
href,
style,
color,
text: selection.text,
@@ -72,7 +72,6 @@ const Notebook: React.FC = ({}) => {
type: 'annotation',
cfi,
note,
href: selection.href || '',
text: selection.text,
created: Date.now(),
};
@@ -2,7 +2,7 @@ import React from 'react';
import * as CFI from 'foliate-js/epubcfi.js';
import { useBookDataStore } from '@/store/bookDataStore';
import { findParentPath } from '@/utils/toc';
import { findTocItemBS } from '@/utils/toc';
import { TOCItem } from '@/libs/document';
import { BookNote, BookNoteType } from '@/types/book';
import BooknoteItem from './BooknoteItem';
@@ -26,17 +26,14 @@ const BooknoteView: React.FC<{
const booknoteGroups: { [href: string]: BooknoteGroup } = {};
for (const booknote of booknotes) {
const parentPath = findParentPath(toc, booknote.href);
if (parentPath.length > 0) {
const href = parentPath[0]!.href || '';
const label = parentPath[0]!.label || '';
const id = toc.findIndex((item) => item.href === href) || Infinity;
booknote.href = href;
if (!booknoteGroups[href]) {
booknoteGroups[href] = { id, href, label, booknotes: [] };
}
booknoteGroups[href].booknotes.push(booknote);
const tocItem = findTocItemBS(toc, booknote.cfi);
const href = tocItem?.href || '';
const label = tocItem?.label || '';
const id = tocItem?.id || 0;
if (!booknoteGroups[href]) {
booknoteGroups[href] = { id, href, label, booknotes: [] };
}
booknoteGroups[href].booknotes.push(booknote);
}
Object.values(booknoteGroups).forEach((group) => {
+11
View File
@@ -1,4 +1,5 @@
import { BookFormat } from '@/types/book';
import * as epubcfi from 'foliate-js/epubcfi.js';
// A groupBy polyfill for foliate-js
Object.groupBy ??= (iterable, callbackfn) => {
@@ -30,15 +31,24 @@ Map.groupBy ??= (iterable, callbackfn) => {
return map;
};
export const CFI = epubcfi;
export type DocumentFile = File;
export interface TOCItem {
id: number;
label: string;
href: string;
cfi?: string;
subitems?: TOCItem[];
}
export interface SectionItem {
id: string;
cfi: string;
size: number;
}
export interface BookDoc {
metadata: {
title: string;
@@ -48,6 +58,7 @@ export interface BookDoc {
publisher?: string;
};
toc: Array<TOCItem>;
sections: Array<SectionItem>;
getCover(): Promise<Blob | null>;
}
+8 -3
View File
@@ -3,8 +3,8 @@ import { create } from 'zustand';
import { BookContent, BookConfig, PageInfo, BookProgress, ViewSettings } from '@/types/book';
import { EnvConfigType } from '@/services/environment';
import { FoliateView } from '@/app/reader/components/FoliateViewer';
import { BookDoc, DocumentLoader, TOCItem } from '@/libs/document';
import { updateTocID } from '@/utils/toc';
import { BookDoc, DocumentLoader, SectionItem, TOCItem } from '@/libs/document';
import { updateTocCFI, updateTocID } from '@/utils/toc';
import { useSettingsStore } from './settingsStore';
import { useBookDataStore } from './bookDataStore';
import { useLibraryStore } from './libraryStore';
@@ -114,8 +114,13 @@ export const useReaderStore = create<ReaderStore>((set, get) => ({
console.log('Loading book', key);
const { book: loadedBookDoc } = await new DocumentLoader(file).open();
const bookDoc = loadedBookDoc as BookDoc;
if (bookDoc.toc) {
if (bookDoc.toc && bookDoc.sections) {
updateTocID(bookDoc.toc);
const sections = bookDoc.sections.reduce((map: Record<string, SectionItem>, section) => {
map[section.id] = section;
return map;
}, {});
updateTocCFI(bookDoc.toc, sections);
}
useBookDataStore.setState((state) => ({
booksData: {
-4
View File
@@ -27,7 +27,6 @@ export interface BookNote {
id: string;
type: BookNoteType;
cfi: string;
href: string;
text?: string;
style?: HighlightStyle;
color?: HighlightColor;
@@ -111,10 +110,7 @@ export interface BookConfig {
lastUpdated: number;
progress?: [number, number];
location?: string;
booknotes?: BookNote[];
removedNotesTimestamps?: Record<string, number>;
searchConfig?: BookSearchConfig;
viewSettings?: Partial<ViewSettings>;
}
+38 -1
View File
@@ -1,4 +1,4 @@
import { TOCItem } from '@/libs/document';
import { SectionItem, TOCItem, CFI } from '@/libs/document';
export const findParentPath = (toc: TOCItem[], href: string): TOCItem[] => {
for (const item of toc) {
@@ -15,6 +15,28 @@ export const findParentPath = (toc: TOCItem[], href: string): TOCItem[] => {
return [];
};
export const findTocItemBS = (toc: TOCItem[], cfi: string): TOCItem | null => {
let left = 0;
let right = toc.length - 1;
let result: TOCItem | null = null;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
const currentCfi = toc[mid]!.cfi || '';
const comparison = CFI.compare(currentCfi, cfi);
if (comparison === 0) {
return toc[mid]!;
} else if (comparison < 0) {
result = toc[mid]!;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
};
export const updateTocID = (items: TOCItem[], index = 0): number => {
items.forEach((item) => {
item.id ??= index++;
@@ -24,3 +46,18 @@ export const updateTocID = (items: TOCItem[], index = 0): number => {
});
return index;
};
export const updateTocCFI = (items: TOCItem[], sections: { [id: string]: SectionItem }): void => {
items.forEach((item) => {
if (item.href) {
const id = item.href.split('#')[0]!;
const section = sections[id];
if (section) {
item.cfi = section.cfi;
}
}
if (item.subitems) {
updateTocCFI(item.subitems, sections);
}
});
};