magnifier
deploy to danak / build_and_deploy (push) Has been cancelled

This commit is contained in:
hamid zarghami
2026-07-01 11:17:08 +03:30
parent 39e18c3331
commit 85ba8e4261
10 changed files with 585 additions and 22 deletions
+67 -19
View File
@@ -5,12 +5,15 @@ import { useBookEntranceController } from "@/pages/viewer/hooks/useBookEntranceC
import { useIsBrowserFullscreen } from "@/pages/viewer/hooks/useIsBrowserFullscreen";
import { useViewerViewport } from "@/pages/viewer/hooks/useViewerViewport";
import { isLegacyIOSSafari } from "@/pages/viewer/utils/isLegacyIOSSafari";
import { resolvePageBackground } from "@/pages/viewer/utils/pageBackground";
import { toggleViewerFullscreen } from "@/pages/viewer/utils/viewerFullscreen";
import { ArrowLeft2, ArrowRight2, Maximize4, Pause, Play, RowVertical } from "iconsax-react";
import { type FC, useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
import HTMLFlipBook from "react-pageflip";
import { type PageData } from "../types";
import BookPage from "./BookPage";
import Magnifier from "./Magnifier/Magnifier";
import ZoomButton from "./Toolbar/ZoomButton";
/** فاصله پیش‌فرض بین هر ورق در پخش خودکار (میلی‌ثانیه) */
const AUTO_PLAY_INTERVAL_MS = 3000;
@@ -118,10 +121,13 @@ function triggerFlipPrev(api: PageFlipWithFlipController | undefined) {
*/
const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings }) => {
const bookRef = useRef<FlipBookInstance | null>(null);
const bookAreaRef = useRef<HTMLDivElement | null>(null);
const flipbookWrapperRef = useRef<HTMLDivElement | null>(null);
const pageFlipHandlerRef = useRef<(e: FlipEvent) => void>(() => {});
const [currentPage, setCurrentPage] = useState(0);
const [isAutoPlayActive, setIsAutoPlayActive] = useState(false);
const [startPage, setStartPage] = useState(0);
const [magnifierEnabled, setMagnifierEnabled] = useState(false);
const isDesktop = useIsDesktop();
const legacyIOS = useLegacyIOSSafari();
const isBrowserFullscreen = useIsBrowserFullscreen();
@@ -139,6 +145,10 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
const backgroundColor = documentSettings?.backgroundColor ?? "#ffffff";
const backgroundGradient = documentSettings?.backgroundGradient;
const backgroundImageUrl = documentSettings?.backgroundImageUrl ?? "";
const pageBackgroundDefaults = useMemo(
() => ({ backgroundType, backgroundColor, backgroundGradient, backgroundImageUrl }),
[backgroundType, backgroundColor, backgroundGradient, backgroundImageUrl],
);
useEffect(() => {
setIsAutoPlayActive(autoPlay);
@@ -359,6 +369,21 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
setIsAutoPlayActive((prev) => !prev);
}, [pages.length]);
const toggleMagnifier = useCallback(() => {
setMagnifierEnabled((prev) => !prev);
}, []);
useEffect(() => {
if (!magnifierEnabled) return;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setMagnifierEnabled(false);
}
};
window.addEventListener("keydown", handleKeyDown);
return () => window.removeEventListener("keydown", handleKeyDown);
}, [magnifierEnabled]);
const navigateToPageIndex = useCallback(
(targetIndex: number) => {
const pageFlipAPI = bookRef.current?.pageFlip();
@@ -441,7 +466,7 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
return (
<div className="flex flex-col items-center gap-4 md:gap-6 w-full h-full max-md:min-h-0 max-md:max-w-full max-md:overflow-x-hidden max-md:pb-[env(safe-area-inset-bottom,0px)]" dir="rtl">
<div className="relative w-full flex flex-col flex-1 max-md:min-h-0 pt-8 md:pt-12 min-h-0 overflow-hidden">
<div className="relative flex flex-1 min-h-0 w-full items-center justify-center">
<div ref={bookAreaRef} className="relative flex flex-1 min-h-0 w-full items-center justify-center">
{/* Border و Shadow عمودی در وسط (فقط حالت دوصفحه‌ای دسکتاپ) */}
{!usePortrait && (
<div
@@ -456,9 +481,11 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
ایندکس/onFlip با دکمه‌ها می‌شود. محتوای فارسی داخل BookPage با dir=rtl است.
*/}
<div
ref={flipbookWrapperRef}
dir="ltr"
className="max-w-full flex justify-center shrink-0 rounded-sm"
style={{
cursor: magnifierEnabled ? "zoom-in" : undefined,
overflow: "hidden",
width: usePortrait ? pagePixelWidth : pagePixelWidth * 2,
height: pagePixelHeight,
@@ -484,35 +511,54 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
showCover={hasMultiplePages}
mobileScrollSupport={!usePortrait}
clickEventForward={true}
useMouseEvents={hasMultiplePages}
useMouseEvents={hasMultiplePages && !magnifierEnabled}
swipeDistance={hasMultiplePages ? (usePortrait ? 48 : 30) : 9999}
startZIndex={1}
showPageCorners={hasMultiplePages}
disableFlipByClick={true}
className={clx("flipbook-container mx-auto max-w-full", legacyIOS && "flipbook-legacy-ios")}
className={clx(
"flipbook-container mx-auto max-w-full",
legacyIOS && "flipbook-legacy-ios",
magnifierEnabled && "flipbook-magnifier-active",
)}
style={{}}
onFlip={onFlipForwarded}
onInit={handleBookInit}
onChangeState={handleChangeState}
>
{displayPages.map((page) => (
<BookPage
key={page.id}
page={page}
entrancePhase={getEntrancePhase(page.id)}
scale={contentScale}
pageWidth={pagePixelWidth}
pageHeight={pagePixelHeight}
onLinkClick={handleLinkClick}
backgroundType={page.backgroundType ?? backgroundType}
backgroundColor={page.backgroundColor ?? backgroundColor}
backgroundGradient={page.backgroundGradient ?? backgroundGradient}
backgroundImageUrl={page.backgroundImageUrl ?? backgroundImageUrl}
useHardPage={legacyIOS}
/>
))}
{displayPages.map((page) => {
const background = resolvePageBackground(page, pageBackgroundDefaults);
return (
<BookPage
key={page.id}
page={page}
entrancePhase={getEntrancePhase(page.id)}
scale={contentScale}
pageWidth={pagePixelWidth}
pageHeight={pagePixelHeight}
onLinkClick={handleLinkClick}
backgroundType={background.backgroundType}
backgroundColor={background.backgroundColor}
backgroundGradient={background.backgroundGradient}
backgroundImageUrl={background.backgroundImageUrl}
useHardPage={legacyIOS}
/>
);
})}
</HTMLFlipBook>
</div>
<Magnifier
enabled={magnifierEnabled}
containerRef={bookAreaRef}
interactionRef={flipbookWrapperRef}
pages={displayPages}
pageWidth={pagePixelWidth}
pageHeight={pagePixelHeight}
contentScale={contentScale}
pageDefaults={pageBackgroundDefaults}
useHardPage={legacyIOS}
pageIndex={currentPage}
/>
</div>
</div>
@@ -570,6 +616,8 @@ const BookViewer: FC<BookViewerProps> = ({ pages, catalogSize, documentSettings
{hasMultiplePages && autoPlay && <AutoPlayToggleButton isActive={isAutoPlayActive} onToggle={toggleAutoPlay} />}
<ZoomButton isActive={magnifierEnabled} onToggle={toggleMagnifier} />
<button
type="button"
onClick={toggleViewerFullscreen}