feat(bookmarks): shared useBookmarks panel + wired into all four readers
This commit is contained in:
@@ -2,6 +2,7 @@ import DOMPurify from "dompurify";
|
||||
import { marked } from "marked";
|
||||
import { useEffect, useMemo, useRef, useState, type MouseEvent, type ReactNode } from "react";
|
||||
import { apiRaw } from "../api/client";
|
||||
import { useBookmarks } from "../components/Bookmarks";
|
||||
import { btn } from "../components/ui";
|
||||
import { chapterText, seekChapter, splitChapters } from "../lib/chapters";
|
||||
import { decodeText } from "../lib/encoding";
|
||||
@@ -130,9 +131,10 @@ export default function TextReader(props: ReaderProps) {
|
||||
return props.book.format === "md" ? <MdView {...props} /> : <TxtView {...props} />;
|
||||
}
|
||||
|
||||
function MdView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
function MdView({ book, initialLocator, initialPercent, chrome }: ReaderProps) {
|
||||
const boxRef = useRef<HTMLDivElement>(null);
|
||||
const saver = useProgressSaver(book.id);
|
||||
const saver = useProgressSaver(book.id, { locator: initialLocator, percent: initialPercent });
|
||||
const bm = useBookmarks({ book, capture: saver.capture, seek: (l) => seek(Number(l.scrollFraction) || 0) });
|
||||
const restored = useRef(false);
|
||||
const pr = useReaderPrefs();
|
||||
const [frac, setFrac] = useState(0);
|
||||
@@ -168,7 +170,7 @@ function MdView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
if (err) return <LoadState text={err} onRetry={retry} />;
|
||||
if (text == null) return <LoadState text="正文加载中…" />;
|
||||
return (
|
||||
<div className="rd-surface flex h-full flex-col" data-rd={pr.prefs.theme}>
|
||||
<div className="rd-surface relative flex h-full flex-col" data-rd={pr.prefs.theme}>
|
||||
<div
|
||||
ref={boxRef}
|
||||
onScroll={onScroll}
|
||||
@@ -181,15 +183,16 @@ function MdView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
dangerouslySetInnerHTML={{ __html: html ?? "" }}
|
||||
/>
|
||||
</div>
|
||||
{chrome.on && <ReaderSheet pr={pr} frac={frac} onSeek={seek} />}
|
||||
{chrome.on && <ReaderSheet pr={pr} frac={frac} onSeek={seek}>{bm.btn}</ReaderSheet>}
|
||||
{bm.panel}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 整本塞一个 <pre> 会冻死浏览器:按章渲染,一章一个滚动块。
|
||||
function TxtView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
function TxtView({ book, initialLocator, initialPercent, chrome }: ReaderProps) {
|
||||
const boxRef = useRef<HTMLDivElement>(null);
|
||||
const saver = useProgressSaver(book.id);
|
||||
const saver = useProgressSaver(book.id, { locator: initialLocator, percent: initialPercent });
|
||||
const inited = useRef(false);
|
||||
const restoreFrac = useRef<number | null>(null);
|
||||
const targetCi = useRef(0);
|
||||
@@ -199,6 +202,11 @@ function TxtView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
const [toc, setToc] = useState(false);
|
||||
const pr = useReaderPrefs();
|
||||
const { text, err, retry } = useFileText(book.file_url ?? "");
|
||||
const bm = useBookmarks({
|
||||
book,
|
||||
capture: saver.capture,
|
||||
seek: (l) => goChapter(Number(l.ch) || 0, Number(l.scrollFraction) || 0),
|
||||
});
|
||||
|
||||
const chapters = useMemo(() => (text == null ? null : splitChapters(text)), [text]);
|
||||
|
||||
@@ -279,6 +287,7 @@ function TxtView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
</div>
|
||||
{chrome.on && (
|
||||
<ReaderSheet pr={pr} frac={total} onSeek={seek}>
|
||||
{bm.btn}
|
||||
{chapters.length > 1 && (
|
||||
<>
|
||||
<button
|
||||
@@ -330,6 +339,7 @@ function TxtView({ book, initialLocator, chrome }: ReaderProps) {
|
||||
</nav>
|
||||
</>
|
||||
)}
|
||||
{bm.panel}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user