From 8167f27156f85dc0facc669f9724f27c39d03b96 Mon Sep 17 00:00:00 2001 From: Huang Xin Date: Fri, 2 May 2025 21:08:20 +0800 Subject: [PATCH] feat: add location info for each entry in table of contents (#1016) --- .../src/app/reader/components/FooterBar.tsx | 2 +- .../src/app/reader/components/PageInfo.tsx | 2 +- .../app/reader/components/sidebar/TOCView.tsx | 17 +++++--- apps/readest-app/src/libs/document.ts | 9 +++++ apps/readest-app/src/store/readerStore.ts | 11 ++---- apps/readest-app/src/utils/toc.ts | 39 ++++++++++++++----- 6 files changed, 55 insertions(+), 25 deletions(-) diff --git a/apps/readest-app/src/app/reader/components/FooterBar.tsx b/apps/readest-app/src/app/reader/components/FooterBar.tsx index 602756f6..1850c64a 100644 --- a/apps/readest-app/src/app/reader/components/FooterBar.tsx +++ b/apps/readest-app/src/app/reader/components/FooterBar.tsx @@ -131,7 +131,7 @@ const FooterBar: React.FC = ({ const progressValid = !!progressInfo; const progressFraction = progressValid && progressInfo?.total > 0 - ? ((progressInfo!.next ?? progressInfo!.current) + 1) / progressInfo!.total || 0 + ? (progressInfo!.current + 1) / progressInfo!.total || 0 : 0; return ( diff --git a/apps/readest-app/src/app/reader/components/PageInfo.tsx b/apps/readest-app/src/app/reader/components/PageInfo.tsx index 8cb221ab..b8f7668f 100644 --- a/apps/readest-app/src/app/reader/components/PageInfo.tsx +++ b/apps/readest-app/src/app/reader/components/PageInfo.tsx @@ -35,7 +35,7 @@ const PageInfoView: React.FC = ({ : '' : pageinfo ? _(isVertical ? '{{currentPage}} ยท {{totalPage}}' : 'Loc. {{currentPage}} / {{totalPage}}', { - currentPage: (pageinfo.next ?? pageinfo.current) + 1, + currentPage: pageinfo.current + 1, totalPage: pageinfo.total, }) : ''; diff --git a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx index baba6e57..7ae4074a 100644 --- a/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx +++ b/apps/readest-app/src/app/reader/components/sidebar/TOCView.tsx @@ -58,7 +58,7 @@ const TOCItemView: React.FC<{ }, [expandedItems, item.href]); return ( -
  • +
  • {item.subitems && ( @@ -77,7 +79,7 @@ const TOCItemView: React.FC<{ )} {item.label} + {item.location && ( + + {item.location.current + 1} + + )} {item.subitems && isExpanded && (
      @@ -161,7 +168,7 @@ const TOCView: React.FC<{ return (
      -
        +
          {toc && toc.map((item, index) => ( ((set, get) => ({ const { book: loadedBookDoc } = await new DocumentLoader(file).open(); const bookDoc = loadedBookDoc as BookDoc; if (bookDoc.toc?.length && bookDoc.sections?.length) { - updateTocID(bookDoc.toc); - const sections = bookDoc.sections.reduce((map: Record, section) => { - map[section.id] = section; - return map; - }, {}); - updateTocCFI(bookDoc, bookDoc.toc, sections); + updateToc(bookDoc, bookDoc.toc, bookDoc.sections); } // Set the book's language for formerly imported books, newly imported books have this field set book.primaryLanguage = diff --git a/apps/readest-app/src/utils/toc.ts b/apps/readest-app/src/utils/toc.ts index 87f6bd35..d487ce53 100644 --- a/apps/readest-app/src/utils/toc.ts +++ b/apps/readest-app/src/utils/toc.ts @@ -37,31 +37,50 @@ export const findTocItemBS = (toc: TOCItem[], cfi: string): TOCItem | null => { return result; }; -export const updateTocID = (items: TOCItem[], index = 0): number => { - items.forEach((item) => { - item.id ??= index++; - if (item.subitems) { - index = updateTocID(item.subitems, index); - } +export const updateToc = (bookDoc: BookDoc, items: TOCItem[], sections: SectionItem[]): void => { + const sizes = sections.map((s) => (s.linear != 'no' && s.size > 0 ? s.size : 0)); + let cumulativeSize = 0; + const cumulativeSizes = sizes.reduce((acc: number[], size) => { + acc.push(cumulativeSize); + cumulativeSize += size; + return acc; + }, []); + const totalSize = cumulativeSizes[cumulativeSizes.length - 1] || 0; + const sizePerLoc = 1500; + sections.forEach((section, index) => { + section.location = { + current: Math.floor(cumulativeSizes[index]! / sizePerLoc), + next: Math.floor((cumulativeSizes[index]! + sizes[index]!) / sizePerLoc), + total: Math.floor(totalSize / sizePerLoc), + }; }); - return index; + + const sectionsMap = sections.reduce((map: Record, section) => { + map[section.id] = section; + return map; + }, {}); + updateTocData(bookDoc, items, sectionsMap); }; -export const updateTocCFI = ( +const updateTocData = ( bookDoc: BookDoc, items: TOCItem[], sections: { [id: string]: SectionItem }, -): void => { + index = 0, +): number => { items.forEach((item) => { + item.id ??= index++; if (item.href) { const id = bookDoc.splitTOCHref(item.href)[0]!; const section = sections[id]; if (section) { item.cfi = section.cfi; + item.location = section.location; } } if (item.subitems) { - updateTocCFI(bookDoc, item.subitems, sections); + index = updateTocData(bookDoc, item.subitems, sections, index); } }); + return index; };