feat: floating bookmarks

add floating bookmarks
This commit is contained in:
2026-06-03 22:19:19 -05:00
parent 6b4c0c43f8
commit 054e7689bd
10 changed files with 263 additions and 12 deletions
@@ -0,0 +1,7 @@
import { useMemo } from "react";
import type { MarkerEntry } from "@/types";
import { layoutBookmarkRail, type BookmarkRailItem } from "@/utils/bookmarkRailLayout";
export function useBookmarkRailLayout(markers: MarkerEntry[]): BookmarkRailItem[] {
return useMemo(() => layoutBookmarkRail(markers), [markers]);
}
+5 -11
View File
@@ -10,6 +10,7 @@ import {
applyRenditionSettings,
isEpubCfi,
marginWidthToGap,
percentageFromCfi,
resolveSpineHref,
updateChapterTitleFromRendition,
type EpubRendition,
@@ -28,13 +29,6 @@ export interface ReadingAnchor {
percentage: number;
}
function percentageFromCfi(rendition: EpubRendition, cfi: string): number {
if (!rendition.book?.locations) return 0;
const pct = rendition.book.locations.percentageFromCfi(cfi);
if (pct === null || pct === undefined) return 0;
return Math.round(pct * 100);
}
function cfiFromRendition(rendition: EpubRendition | null): string | null {
if (!rendition) return null;
const start = (rendition as EpubRendition & { location?: { start?: { cfi?: string } } }).location
@@ -157,7 +151,7 @@ export function useEpubReader(
cfi = cfiFromRendition(rendition);
}
if (!cfi) return null;
const percentage = rendition ? percentageFromCfi(rendition, cfi) : 0;
const percentage = rendition ? (percentageFromCfi(rendition, cfi) ?? 0) : 0;
return { cfi, percentage };
}, [location]);
@@ -187,7 +181,7 @@ export function useEpubReader(
setLocation(anchor.cfi);
const rendition = renditionRef.current;
const pct = rendition ? percentageFromCfi(rendition, anchor.cfi) : anchor.percentage;
const pct = rendition ? (percentageFromCfi(rendition, anchor.cfi) ?? anchor.percentage) : anchor.percentage;
void flushProgress(anchor.cfi, pct > 0 ? pct : anchor.percentage);
}, [clearPeekState, flushProgress]);
@@ -267,7 +261,7 @@ export function useEpubReader(
if (!isEpubCfi(loc)) return;
const rendition = renditionRef.current;
const percentage = rendition ? percentageFromCfi(rendition, loc) : 0;
const percentage = rendition ? (percentageFromCfi(rendition, loc) ?? 0) : 0;
if (rendition) {
void updateChapterTitleFromRendition(rendition).then((title) => {
@@ -306,7 +300,7 @@ export function useEpubReader(
const cfi = start?.cfi;
if (!cfi || !isEpubCfi(cfi)) return;
const percentage = percentageFromCfi(rendition, cfi);
const percentage = percentageFromCfi(rendition, cfi) ?? 0;
void flushProgress(cfi, percentage);
if (percentage <= 0 && attempt < 2) {