feat(web): unify reader TOC and bookmarks into one left nav drawer with tabs

This commit is contained in:
2026-09-08 21:08:42 +08:00
parent 4f4c7e5434
commit 48161ea1ff
7 changed files with 340 additions and 211 deletions
+24 -12
View File
@@ -1,6 +1,7 @@
import { useEffect, useRef, useState } from "react";
import { apiRaw } from "../api/client";
import { useBookmarks } from "../components/Bookmarks";
import { BookmarksTab } from "../components/Bookmarks";
import { ReaderNav } from "../components/reader-nav";
import { btn } from "../components/ui";
import { toast } from "../components/Toaster";
import { useProgressSaver, type ReaderProps } from "../lib/useProgress";
@@ -32,15 +33,7 @@ export default function EpubReader({ book, initialLocator, initialPercent }: Rea
const hostRef = useRef<HTMLDivElement>(null);
const rendRef = useRef<EpubRendition | null>(null);
const saver = useProgressSaver(book.id, { locator: initialLocator, percent: initialPercent });
const bm = useBookmarks({
book,
capture: saver.capture,
seek: (l) => {
const cfi = String(l.cfi ?? "");
if (!cfi) return;
Promise.resolve(rendRef.current?.display(cfi)).catch(() => toast("err", "书签定位失败"));
},
});
const [nav, setNav] = useState(false);
const [err, setErr] = useState("");
const [nonce, setNonce] = useState(0);
const [ready, setReady] = useState(false);
@@ -113,9 +106,28 @@ export default function EpubReader({ book, initialLocator, initialPercent }: Rea
<button className={btn} onClick={() => rendRef.current?.next()}>
下一页
</button>
{bm.btn}
<button className="rd-btn" aria-expanded={nav} aria-controls="reader-nav" onClick={() => setNav((v) => !v)}>
书签
</button>
</div>
{bm.panel}
{nav && (
<ReaderNav
tab="bm"
onClose={() => setNav(false)}
bookmarks={
<BookmarksTab
book={book}
capture={saver.capture}
seek={(l) => {
const cfi = String(l.cfi ?? "");
setNav(false);
if (!cfi) return;
Promise.resolve(rendRef.current?.display(cfi)).catch(() => toast("err", "书签定位失败"));
}}
/>
}
/>
)}
</div>
);
}