feat: add zoom functionality to BookReader and related components, enabling zoom state management and touch gesture handling
This commit is contained in:
@@ -19,6 +19,7 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
|
||||
const [isDoublePage, setIsDoublePage] = useState(false);
|
||||
const [showControls, setShowControls] = useState(false);
|
||||
const [showThumbnails, setShowThumbnails] = useState(false);
|
||||
const [isZoomed, setIsZoomed] = useState(false);
|
||||
const readerRef = useRef<HTMLDivElement>(null);
|
||||
const isLandscape = useOrientation();
|
||||
const { direction, toggleDirection, isRTL } = useReadingDirection();
|
||||
@@ -43,6 +44,7 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
|
||||
onClose,
|
||||
direction,
|
||||
nextBook,
|
||||
isZoomed,
|
||||
});
|
||||
|
||||
const { preloadPage, getPageUrl, cleanCache } = usePageCache({
|
||||
@@ -138,6 +140,7 @@ export function BookReader({ book, pages, onClose, nextBook }: BookReaderProps)
|
||||
shouldShowDoublePage={shouldShowDoublePage}
|
||||
isRTL={isRTL}
|
||||
onThumbnailLoad={handleThumbnailLoad}
|
||||
onZoomChange={setIsZoomed}
|
||||
/>
|
||||
|
||||
<NavigationBar
|
||||
|
||||
@@ -10,6 +10,7 @@ interface ReaderContentProps {
|
||||
shouldShowDoublePage: (page: number) => boolean;
|
||||
isRTL: boolean;
|
||||
onThumbnailLoad: (pageNumber: number) => void;
|
||||
onZoomChange?: (isZoomed: boolean) => void;
|
||||
}
|
||||
|
||||
export const ReaderContent = ({
|
||||
@@ -22,6 +23,7 @@ export const ReaderContent = ({
|
||||
shouldShowDoublePage,
|
||||
isRTL,
|
||||
onThumbnailLoad,
|
||||
onZoomChange,
|
||||
}: ReaderContentProps) => {
|
||||
return (
|
||||
<div className="relative flex-1 flex items-center justify-center overflow-hidden p-1">
|
||||
@@ -34,6 +36,7 @@ export const ReaderContent = ({
|
||||
isDoublePage={isDoublePage}
|
||||
isRTL={isRTL}
|
||||
order="first"
|
||||
onZoomChange={onZoomChange}
|
||||
/>
|
||||
|
||||
{isDoublePage && shouldShowDoublePage(currentPage) && (
|
||||
@@ -45,6 +48,7 @@ export const ReaderContent = ({
|
||||
isDoublePage={true}
|
||||
isRTL={isRTL}
|
||||
order="second"
|
||||
onZoomChange={onZoomChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { TransformWrapper, TransformComponent } from "react-zoom-pan-pinch";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useState } from "react";
|
||||
|
||||
interface ZoomablePageProps {
|
||||
pageUrl: string | null;
|
||||
@@ -9,6 +10,7 @@ interface ZoomablePageProps {
|
||||
isDoublePage?: boolean;
|
||||
isRTL?: boolean;
|
||||
order?: "first" | "second";
|
||||
onZoomChange?: (isZoomed: boolean) => void;
|
||||
}
|
||||
|
||||
export const ZoomablePage = ({
|
||||
@@ -19,7 +21,14 @@ export const ZoomablePage = ({
|
||||
isDoublePage = false,
|
||||
isRTL = false,
|
||||
order = "first",
|
||||
onZoomChange,
|
||||
}: ZoomablePageProps) => {
|
||||
const [currentScale, setCurrentScale] = useState(1);
|
||||
|
||||
const handleTransform = (ref: any, state: { scale: number; positionX: number; positionY: number }) => {
|
||||
setCurrentScale(state.scale);
|
||||
onZoomChange?.(state.scale > 1.1);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
@@ -55,6 +64,7 @@ export const ZoomablePage = ({
|
||||
panning={{ disabled: false }}
|
||||
limitToBounds={true}
|
||||
centerZoomedOut={false}
|
||||
onTransformed={handleTransform}
|
||||
>
|
||||
<TransformComponent
|
||||
wrapperClass="w-full h-full flex items-center justify-center"
|
||||
|
||||
@@ -10,6 +10,7 @@ interface UsePageNavigationProps {
|
||||
onClose?: (currentPage: number) => void;
|
||||
direction: "ltr" | "rtl";
|
||||
nextBook?: KomgaBook | null;
|
||||
isZoomed?: boolean;
|
||||
}
|
||||
|
||||
export const usePageNavigation = ({
|
||||
@@ -19,6 +20,7 @@ export const usePageNavigation = ({
|
||||
onClose,
|
||||
direction,
|
||||
nextBook,
|
||||
isZoomed = false,
|
||||
}: UsePageNavigationProps) => {
|
||||
const router = useRouter();
|
||||
const cPage = ClientOfflineBookService.getCurrentPage(book);
|
||||
@@ -133,25 +135,22 @@ export const usePageNavigation = ({
|
||||
|
||||
const handleTouchStart = useCallback(
|
||||
(event: TouchEvent) => {
|
||||
// Ne gérer que les gestes à un seul doigt
|
||||
if (event.touches.length === 1) {
|
||||
touchStartXRef.current = event.touches[0].clientX;
|
||||
touchStartYRef.current = event.touches[0].clientY;
|
||||
currentPageRef.current = currentPage;
|
||||
} else {
|
||||
// Reset les références pour les gestes multi-touch (pinch)
|
||||
// Si on est zoomé, on ne gère pas la navigation
|
||||
if (isZoomed) {
|
||||
touchStartXRef.current = null;
|
||||
touchStartYRef.current = null;
|
||||
return;
|
||||
}
|
||||
|
||||
touchStartXRef.current = event.touches[0].clientX;
|
||||
touchStartYRef.current = event.touches[0].clientY;
|
||||
currentPageRef.current = currentPage;
|
||||
},
|
||||
[currentPage]
|
||||
[currentPage, isZoomed]
|
||||
);
|
||||
|
||||
const handleTouchEnd = useCallback(
|
||||
(event: TouchEvent) => {
|
||||
// Ne traiter que les gestes à un seul doigt
|
||||
if (event.touches.length > 1) return;
|
||||
|
||||
if (touchStartXRef.current === null || touchStartYRef.current === null) return;
|
||||
|
||||
const touchEndX = event.changedTouches[0].clientX;
|
||||
@@ -163,7 +162,7 @@ export const usePageNavigation = ({
|
||||
// on ne fait rien (pour éviter de confondre avec un scroll)
|
||||
if (Math.abs(deltaY) > Math.abs(deltaX)) return;
|
||||
|
||||
// Augmenter le seuil pour éviter les changements de page accidentels
|
||||
// Seuil pour éviter les changements de page accidentels
|
||||
if (Math.abs(deltaX) > 100) {
|
||||
if (deltaX > 0) {
|
||||
// Swipe vers la droite
|
||||
|
||||
Reference in New Issue
Block a user