Viewer improvements

This commit is contained in:
Reece 2025-07-15 01:00:05 +01:00
parent 934cd01268
commit 9cec0e743c

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState, useRef } from "react"; import React, { useEffect, useState, useRef, useCallback } from "react";
import { Paper, Stack, Text, ScrollArea, Loader, Center, Button, Group, NumberInput, useMantineTheme, ActionIcon, Box } from "@mantine/core"; import { Paper, Stack, Text, ScrollArea, Loader, Center, Button, Group, NumberInput, useMantineTheme, ActionIcon, Box } from "@mantine/core";
import { getDocument, GlobalWorkerOptions } from "pdfjs-dist"; import { getDocument, GlobalWorkerOptions } from "pdfjs-dist";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@ -184,7 +184,6 @@ const Viewer = ({
}, [previewFile, pdfFile]); }, [previewFile, pdfFile]);
const scrollAreaRef = useRef<HTMLDivElement>(null); const scrollAreaRef = useRef<HTMLDivElement>(null);
const isManualNavigationRef = useRef(false);
const pdfDocRef = useRef<any>(null); const pdfDocRef = useRef<any>(null);
const renderingPagesRef = useRef<Set<number>>(new Set()); const renderingPagesRef = useRef<Set<number>>(new Set());
const currentArrayBufferRef = useRef<ArrayBuffer | null>(null); const currentArrayBufferRef = useRef<ArrayBuffer | null>(null);
@ -270,24 +269,28 @@ const Viewer = ({
} }
}, [numPages, currentPage]); }, [numPages, currentPage]);
// Scroll to the current page when manually navigated // Function to scroll to a specific page
useEffect(() => { const scrollToPage = (pageNumber: number) => {
if (currentPage && pageRefs.current[currentPage - 1] && isManualNavigationRef.current) { const el = pageRefs.current[pageNumber - 1];
const el = pageRefs.current[currentPage - 1]; const scrollArea = scrollAreaRef.current;
el?.scrollIntoView({ behavior: "smooth", block: "center" });
if (el && scrollArea) {
const scrollAreaRect = scrollArea.getBoundingClientRect();
const elRect = el.getBoundingClientRect();
const currentScrollTop = scrollArea.scrollTop;
// Reset manual navigation flag after a delay // Position page near top of viewport with some padding
const timeout = setTimeout(() => { const targetScrollTop = currentScrollTop + (elRect.top - scrollAreaRect.top) - 20;
isManualNavigationRef.current = false;
}, 1000);
return () => clearTimeout(timeout); scrollArea.scrollTo({
top: targetScrollTop,
behavior: "smooth"
});
} }
}, [currentPage, pageImages]); };
// Detect visible page on scroll (only update display, don't trigger navigation) // Throttled scroll handler to prevent jerky updates
const handleScroll = () => { const handleScrollThrottled = useCallback(() => {
if (isManualNavigationRef.current) return;
const scrollArea = scrollAreaRef.current; const scrollArea = scrollAreaRef.current;
if (!scrollArea || !pageRefs.current.length) return; if (!scrollArea || !pageRefs.current.length) return;
@ -308,11 +311,20 @@ const Viewer = ({
} }
}); });
// Only update if the page actually changed and we're not in manual navigation // Update page number display only if changed
if (currentPage !== closestIdx + 1) { if (currentPage !== closestIdx + 1) {
setCurrentPage(closestIdx + 1); setCurrentPage(closestIdx + 1);
} }
}; }, [currentPage]);
// Throttle scroll events to reduce jerkiness
const handleScroll = useCallback(() => {
if (window.requestAnimationFrame) {
window.requestAnimationFrame(handleScrollThrottled);
} else {
handleScrollThrottled();
}
}, [handleScrollThrottled]);
useEffect(() => { useEffect(() => {
let cancelled = false; let cancelled = false;
@ -523,8 +535,7 @@ const Viewer = ({
px={8} px={8}
radius="xl" radius="xl"
onClick={() => { onClick={() => {
isManualNavigationRef.current = true; scrollToPage(1);
setCurrentPage(1);
}} }}
disabled={currentPage === 1} disabled={currentPage === 1}
style={{ minWidth: 36 }} style={{ minWidth: 36 }}
@ -538,8 +549,8 @@ const Viewer = ({
px={8} px={8}
radius="xl" radius="xl"
onClick={() => { onClick={() => {
isManualNavigationRef.current = true; const prevPage = Math.max(1, (currentPage || 1) - 1);
setCurrentPage(Math.max(1, (currentPage || 1) - 1)); scrollToPage(prevPage);
}} }}
disabled={currentPage === 1} disabled={currentPage === 1}
style={{ minWidth: 36 }} style={{ minWidth: 36 }}
@ -551,8 +562,7 @@ const Viewer = ({
onChange={value => { onChange={value => {
const page = Number(value); const page = Number(value);
if (!isNaN(page) && page >= 1 && page <= numPages) { if (!isNaN(page) && page >= 1 && page <= numPages) {
isManualNavigationRef.current = true; scrollToPage(page);
setCurrentPage(page);
} }
}} }}
min={1} min={1}
@ -572,8 +582,8 @@ const Viewer = ({
px={8} px={8}
radius="xl" radius="xl"
onClick={() => { onClick={() => {
isManualNavigationRef.current = true; const nextPage = Math.min(numPages, (currentPage || 1) + 1);
setCurrentPage(Math.min(numPages, (currentPage || 1) + 1)); scrollToPage(nextPage);
}} }}
disabled={currentPage === numPages} disabled={currentPage === numPages}
style={{ minWidth: 36 }} style={{ minWidth: 36 }}
@ -587,8 +597,7 @@ const Viewer = ({
px={8} px={8}
radius="xl" radius="xl"
onClick={() => { onClick={() => {
isManualNavigationRef.current = true; scrollToPage(numPages);
setCurrentPage(numPages);
}} }}
disabled={currentPage === numPages} disabled={currentPage === numPages}
style={{ minWidth: 36 }} style={{ minWidth: 36 }}