fix: pdf bookmark

for pdfs only select pages not text
This commit is contained in:
2026-06-03 23:01:12 -05:00
parent f091386974
commit f989b144cf
11 changed files with 111 additions and 198 deletions
-37
View File
@@ -1,37 +0,0 @@
import { useEffect, useMemo } from "react";
import { useAnnotations } from "@/context/AnnotationsContext";
import { isPdfAnchor, parsePdfAnchor } from "@/utils/pdfAnchor";
import { normalizeHighlightColor } from "@/constants/bookmarkHighlightColors";
export interface PdfPageHighlight {
rects: [number, number, number, number][];
color: string;
}
export function usePdfHighlights(ebookId: number, currentPage: number): PdfPageHighlight[] {
const { markers, loadBookmarks } = useAnnotations();
const bookMarkers = useMemo(
() => markers.filter((m) => m.ebook_id === ebookId),
[markers, ebookId],
);
useEffect(() => {
if (!ebookId || Number.isNaN(ebookId)) return;
void loadBookmarks(ebookId);
}, [ebookId, loadBookmarks]);
return useMemo(() => {
const highlights: PdfPageHighlight[] = [];
for (const marker of bookMarkers) {
if (!isPdfAnchor(marker.epub_cfi)) continue;
const parsed = parsePdfAnchor(marker.epub_cfi);
if (!parsed || parsed.page !== currentPage || !parsed.rects.length) continue;
highlights.push({
rects: parsed.rects,
color: normalizeHighlightColor(marker.highlight_color),
});
}
return highlights;
}, [bookMarkers, currentPage]);
}
-3
View File
@@ -26,7 +26,6 @@ export interface UsePdfReaderReturn {
error: string | null;
isBookmarkPeekActive: boolean;
readingAnchor: PdfReadingAnchor | null;
pageWrapRef: React.RefObject<HTMLDivElement | null>;
goToPage: (page: number) => void;
goToNextPage: () => void;
goToPrevPage: () => void;
@@ -55,7 +54,6 @@ export function usePdfReader(
const [isBookmarkPeekActive, setIsBookmarkPeekActive] = useState(false);
const [readingAnchor, setReadingAnchor] = useState<PdfReadingAnchor | null>(null);
const pageWrapRef = useRef<HTMLDivElement | null>(null);
const debounceTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
const isBookmarkPeekRef = useRef(false);
const readingAnchorRef = useRef<PdfReadingAnchor | null>(null);
@@ -247,7 +245,6 @@ export function usePdfReader(
error,
isBookmarkPeekActive,
readingAnchor,
pageWrapRef,
goToPage,
goToNextPage,
goToPrevPage,
-57
View File
@@ -1,57 +0,0 @@
import { useCallback, useEffect, useRef, useState } from "react";
import type { PendingSelection } from "./useEpubSelection";
import { rectsFromSelection, serializePdfAnchor } from "../utils/pdfAnchor";
export function usePdfSelection(
pageWrapRef: React.RefObject<HTMLDivElement | null>,
currentPage: number,
chapterTitle: string,
) {
const [pendingSelection, setPendingSelection] = useState<PendingSelection | null>(null);
const chapterTitleRef = useRef(chapterTitle);
chapterTitleRef.current = chapterTitle;
const clearSelection = useCallback(() => {
setPendingSelection(null);
}, []);
useEffect(() => {
const wrap = pageWrapRef.current;
if (!wrap) return;
const handler = () => {
window.setTimeout(() => {
const sel = window.getSelection();
const text = sel?.toString()?.trim() ?? "";
if (!text || !sel || sel.rangeCount === 0) {
setPendingSelection(null);
return;
}
const range = sel.getRangeAt(0);
if (!wrap.contains(range.commonAncestorContainer)) {
setPendingSelection(null);
return;
}
const rects = rectsFromSelection(range, wrap);
const anchor = serializePdfAnchor(currentPage, rects.length > 0 ? rects : undefined);
const rect = range.getBoundingClientRect();
setPendingSelection({
epubCfi: anchor,
locationText: text.slice(0, 2000),
chapterIndex: currentPage - 1,
chapterTitle: chapterTitleRef.current,
anchorTop: rect.bottom + 8,
anchorLeft: Math.min(rect.left, window.innerWidth - 280),
});
}, 10);
};
wrap.addEventListener("mouseup", handler);
return () => wrap.removeEventListener("mouseup", handler);
}, [pageWrapRef, currentPage]);
return { pendingSelection, clearSelection };
}