From 27f57084e998fbca80e78837c33076eae6f2ce75 Mon Sep 17 00:00:00 2001 From: hamid zarghami Date: Sat, 14 Mar 2026 11:42:10 +0330 Subject: [PATCH] scale viewer --- src/config/paperSizes.ts | 15 ++++++ src/pages/editor/Editor.tsx | 2 +- src/pages/editor/components/EditorCanvas.tsx | 8 +++- .../editor/components/canvas/useStageSize.ts | 26 +++++----- src/pages/viewer/Viewer.tsx | 2 +- src/pages/viewer/components/BookPage.tsx | 12 +++-- src/pages/viewer/components/BookViewer.tsx | 48 +++++++++++++++---- 7 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 src/config/paperSizes.ts diff --git a/src/config/paperSizes.ts b/src/config/paperSizes.ts new file mode 100644 index 0000000..cc3e384 --- /dev/null +++ b/src/config/paperSizes.ts @@ -0,0 +1,15 @@ +/** + * ابعاد استاندارد کاغذ (ISO A) به پیکسل - همان مقیاس ادیتور (A4 = 794×1123) + */ +export const PAPER_DIMENSIONS = { + a3: { width: 1123, height: 1587 }, + a4: { width: 794, height: 1123 }, + a5: { width: 561, height: 794 }, +} as const; + +export type PaperSizeKey = keyof typeof PAPER_DIMENSIONS; + +export function getPaperDimensions(size: string): { width: number; height: number } { + const key = size?.toLowerCase() as PaperSizeKey; + return PAPER_DIMENSIONS[key] ?? PAPER_DIMENSIONS.a4; +} diff --git a/src/pages/editor/Editor.tsx b/src/pages/editor/Editor.tsx index 597a50d..b451175 100644 --- a/src/pages/editor/Editor.tsx +++ b/src/pages/editor/Editor.tsx @@ -45,7 +45,7 @@ const Editor: FC = () => { isLayersPanelOpen ? "xl:pl-[296px]" : "xl:pl-[80px]" )}> - + ) diff --git a/src/pages/editor/components/EditorCanvas.tsx b/src/pages/editor/components/EditorCanvas.tsx index 093e16d..cc73b4a 100644 --- a/src/pages/editor/components/EditorCanvas.tsx +++ b/src/pages/editor/components/EditorCanvas.tsx @@ -13,7 +13,11 @@ import ObjectsLayer from "./canvas/ObjectsLayer"; import CellEditor from "@/components/CellEditor"; import ZoomControls from "./ZoomControls"; -const EditorCanvas = () => { +type EditorCanvasProps = { + catalogSize?: string; +}; + +const EditorCanvas = ({ catalogSize }: EditorCanvasProps) => { const stageRef = useRef(null); const layerRef = useRef(null); @@ -30,7 +34,7 @@ const EditorCanvas = () => { } = useEditorStore(); const { transformerRef, handleStageMouseDown, handleStageMouseMove, handleStageMouseUp } = useDrawingHandlers(); - const stageSize = useStageSize(); + const stageSize = useStageSize(catalogSize); useKeyboardMovement(); const { handleSelect, handleCellClick, handleCellDblClick } = useSelectionHandlers(); diff --git a/src/pages/editor/components/canvas/useStageSize.ts b/src/pages/editor/components/canvas/useStageSize.ts index d5357d3..8db606f 100644 --- a/src/pages/editor/components/canvas/useStageSize.ts +++ b/src/pages/editor/components/canvas/useStageSize.ts @@ -1,35 +1,33 @@ import { useState, useEffect } from "react"; +import { getPaperDimensions } from "@/config/paperSizes"; -export const A4_WIDTH = 794; -export const A4_HEIGHT = 1123; const SCALE = 0.8; -export const useStageSize = () => { +export const useStageSize = (catalogSize?: string) => { + const { width: baseWidth, height: baseHeight } = getPaperDimensions(catalogSize ?? "a4"); + const [stageSize, setStageSize] = useState({ - width: A4_WIDTH, - height: A4_HEIGHT, + width: baseWidth, + height: baseHeight, scale: SCALE, }); useEffect(() => { + const { width, height } = getPaperDimensions(catalogSize ?? "a4"); + const handleResize = () => { const maxWidth = window.innerWidth - 400; const maxHeight = window.innerHeight - 100; - const scaleX = maxWidth / A4_WIDTH; - const scaleY = maxHeight / A4_HEIGHT; + const scaleX = maxWidth / width; + const scaleY = maxHeight / height; const newScale = Math.min(scaleX, scaleY, SCALE); - - setStageSize({ - width: A4_WIDTH, - height: A4_HEIGHT, - scale: newScale, - }); + setStageSize({ width, height, scale: newScale }); }; handleResize(); window.addEventListener("resize", handleResize); return () => window.removeEventListener("resize", handleResize); - }, []); + }, [catalogSize]); return stageSize; }; diff --git a/src/pages/viewer/Viewer.tsx b/src/pages/viewer/Viewer.tsx index b3b17c9..7bee578 100644 --- a/src/pages/viewer/Viewer.tsx +++ b/src/pages/viewer/Viewer.tsx @@ -58,7 +58,7 @@ const Viewer: FC = () => { return (
- +
); }; diff --git a/src/pages/viewer/components/BookPage.tsx b/src/pages/viewer/components/BookPage.tsx index bb56305..e7d55d3 100644 --- a/src/pages/viewer/components/BookPage.tsx +++ b/src/pages/viewer/components/BookPage.tsx @@ -5,6 +5,8 @@ import type { EditorObject } from '@/pages/editor/store/editorStore'; type BookPageProps = { page: PageData; scale?: number; + pageWidth?: number; + pageHeight?: number; onLinkClick?: (linkUrl: string) => void; }; @@ -15,7 +17,8 @@ type BookPageProps = { * این کامپوننت به عنوان child برای HTMLFlipBook استفاده می‌شود * نیاز به forwardRef دارد تا react-pageflip بتواند ref را مدیریت کند */ -const BookPage = forwardRef(({ page, scale = 1, onLinkClick }, ref) => { +const BookPage = forwardRef( + ({ page, scale = 1, pageWidth, pageHeight, onLinkClick }, ref) => { // تابع برای تبدیل opacity به رنگ (مثل editor) // در editor، getColorWithOpacity انتظار opacity 0-100 دارد // در dataTransformer، opacity از 0-1 به 0-100 تبدیل شده است @@ -462,6 +465,9 @@ const BookPage = forwardRef(({ page, scale = 1, o } }; + const width = pageWidth ?? 794 * scale; + const height = pageHeight ?? 1123 * scale; + return (
(({ page, scale = 1, o backgroundColor: '#ffffff', overflow: 'hidden', boxSizing: 'border-box', - width: `${794 * scale}px`, - height: `${1123 * scale}px`, + width: `${width}px`, + height: `${height}px`, isolation: 'isolate', zIndex: 1, }} diff --git a/src/pages/viewer/components/BookViewer.tsx b/src/pages/viewer/components/BookViewer.tsx index d438e4e..d7d8f3b 100644 --- a/src/pages/viewer/components/BookViewer.tsx +++ b/src/pages/viewer/components/BookViewer.tsx @@ -1,11 +1,18 @@ -import { type FC, useRef, useCallback, useState, useEffect } from 'react'; +import { type FC, useRef, useCallback, useState, useEffect, useMemo } from 'react'; import HTMLFlipBook from 'react-pageflip'; import { type PageData } from '../types'; import BookPage from './BookPage'; import { ArrowLeft2, ArrowRight2 } from 'iconsax-react'; +import { getPaperDimensions } from '@/config/paperSizes'; -type BookViewerProps = { +const VIEWER_SCALE = 0.5; + +// سایز کتاب همیشه A4 است (ثابت) +const BOOK_PAPER_SIZE = 'a4'; + +export type BookViewerProps = { pages: PageData[]; + catalogSize?: string; }; interface PageFlipAPI { @@ -27,10 +34,24 @@ interface FlipEvent { * این کامپوننت از HTMLFlipBook استفاده می‌کند که یک wrapper برای PageFlip است * از HTML برای رندر صفحات استفاده می‌شود (نه Canvas) برای سازگاری با Konva در آینده */ -const BookViewer: FC = ({ pages }) => { +const BookViewer: FC = ({ pages, catalogSize }) => { const bookRef = useRef(null); const [currentPage, setCurrentPage] = useState(0); + // سایز کتاب ثابت (همیشه A4) + const { width: bookWidth, height: bookHeight } = useMemo( + () => getPaperDimensions(BOOK_PAPER_SIZE), + [] + ); + const displayWidth = Math.round(bookWidth * VIEWER_SCALE); + const displayHeight = Math.round(bookHeight * VIEWER_SCALE); + + // نسبت محتوا بر اساس catalogSize (A3/A4/A5) + const contentScale = useMemo(() => { + const { width: contentWidth } = getPaperDimensions(catalogSize ?? 'a4'); + return VIEWER_SCALE * (bookWidth / contentWidth); + }, [catalogSize]); + // اطمینان از اینکه currentPage همیشه در محدوده معتبر است useEffect(() => { if (currentPage < 0) { @@ -156,13 +177,13 @@ const BookViewer: FC = ({ pages }) => {
= ({ pages }) => { onFlip={handlePageFlip} > {pages.map((page) => ( - + ))}