From bd7d1b6beebbc2eb291768ac9df91574533ff277 Mon Sep 17 00:00:00 2001 From: pipisebastian Date: Sun, 24 Nov 2024 07:26:49 +0900 Subject: [PATCH] =?UTF-8?q?feat:=208=20=EB=B0=A9=ED=96=A5=EC=97=90=20?= =?UTF-8?q?=EB=A6=AC=EC=82=AC=EC=9D=B4=EC=A7=95=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #178 --- client/src/features/page/Page.tsx | 29 +++-- client/src/features/page/hooks/usePage.ts | 122 ++++++++++++++++++++-- 2 files changed, 124 insertions(+), 27 deletions(-) diff --git a/client/src/features/page/Page.tsx b/client/src/features/page/Page.tsx index 23bf3d15..a376a5fd 100644 --- a/client/src/features/page/Page.tsx +++ b/client/src/features/page/Page.tsx @@ -2,12 +2,10 @@ import { serializedEditorDataProps } from "@noctaCrdt/Interfaces"; import { motion, AnimatePresence } from "framer-motion"; import { Editor } from "@features/editor/Editor"; import { Page as PageType } from "@src/types/page"; -import { pageAnimation, resizeHandleAnimation } from "./Page.animation"; -import { pageContainer, pageHeader, resizeHandle } from "./Page.style"; - +import { pageContainer, pageHeader, resizeHandles } from "./Page.style"; import { PageControlButton } from "./components/PageControlButton/PageControlButton"; import { PageTitle } from "./components/PageTitle/PageTitle"; -import { usePage } from "./hooks/usePage"; +import { DIRECTIONS, usePage } from "./hooks/usePage"; interface PageProps extends PageType { handlePageSelect: ({ pageId, isSidebar }: { pageId: string; isSidebar?: boolean }) => void; @@ -45,17 +43,12 @@ export const Page = ({ return ( - - - + {DIRECTIONS.map((direction) => ( + pageResize(e, direction)} + /> + ))} + ); }; diff --git a/client/src/features/page/hooks/usePage.ts b/client/src/features/page/hooks/usePage.ts index 61cbf7b5..f9cb9a40 100644 --- a/client/src/features/page/hooks/usePage.ts +++ b/client/src/features/page/hooks/usePage.ts @@ -5,6 +5,18 @@ import { useIsSidebarOpen } from "@stores/useSidebarStore"; import { Position, Size } from "@src/types/page"; const PADDING = SPACING.MEDIUM * 2; +export const DIRECTIONS = [ + "top", + "bottom", + "left", + "right", + "topLeft", + "topRight", + "bottomLeft", + "bottomRight", +] as const; + +type Direction = (typeof DIRECTIONS)[number]; export const usePage = ({ x, y }: Position) => { const [position, setPosition] = useState({ x, y }); @@ -68,28 +80,118 @@ export const usePage = ({ x, y }: Position) => { document.addEventListener("pointerup", handleDragEnd); }; - const pageResize = (e: React.MouseEvent) => { + const pageResize = (e: React.MouseEvent, direction: Direction) => { e.preventDefault(); const startX = e.clientX; const startY = e.clientY; const startWidth = size.width; const startHeight = size.height; + const startPosition = { x: position.x, y: position.y }; const resize = (e: MouseEvent) => { const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; - const newWidth = Math.max( - PAGE.MIN_WIDTH, - Math.min(startWidth + deltaX, window.innerWidth - position.x - getSidebarWidth() - PADDING), - ); - - const newHeight = Math.max( - PAGE.MIN_HEIGHT, - Math.min(startHeight + deltaY, window.innerHeight - position.y - PADDING), - ); + let newWidth = startWidth; + let newHeight = startHeight; + let newX = startPosition.x; + let newY = startPosition.y; + + switch (direction) { + case "right": { + // startWidth + deltaX 가 계속해서 변하는 값. 사용자가 마우스를 움직이면서 계속해서 변함 + newWidth = Math.min( + window.innerWidth - startPosition.x - getSidebarWidth() - PADDING, // 최대 넓이를 지정하고 싶을때 Math.min + Math.max(PAGE.MIN_WIDTH, startWidth + deltaX), //최소 넓이를 지정하고 싶을때 Math.max + ); + break; + } + + case "left": { + newWidth = Math.min( + startPosition.x + startWidth, + Math.max(PAGE.MIN_WIDTH, startWidth - deltaX), + ); + newX = Math.max(0, startPosition.x + startWidth - newWidth); + break; + } + + case "bottom": { + newHeight = Math.min( + window.innerHeight - startPosition.y - PADDING, + Math.max(PAGE.MIN_HEIGHT, startHeight + deltaY), + ); + break; + } + + case "top": { + newHeight = Math.min( + startPosition.y + startHeight, + Math.max(PAGE.MIN_HEIGHT, startHeight - deltaY), + ); + newY = Math.max(0, startPosition.y + startHeight - newHeight); + break; + } + + case "topLeft": { + newHeight = Math.min( + startPosition.y + startHeight, + Math.max(PAGE.MIN_HEIGHT, startHeight - deltaY), + ); + newY = Math.max(0, startPosition.y + startHeight - newHeight); + + newWidth = Math.min( + startPosition.x + startWidth, + Math.max(PAGE.MIN_WIDTH, startWidth - deltaX), + ); + newX = Math.max(0, startPosition.x + startWidth - newWidth); + break; + } + + case "topRight": { + newHeight = Math.min( + startPosition.y + startHeight, + Math.max(PAGE.MIN_HEIGHT, startHeight - deltaY), + ); + newY = Math.max(0, startPosition.y + startHeight - newHeight); + + newWidth = Math.min( + window.innerWidth - startPosition.x - getSidebarWidth() - PADDING, + Math.max(PAGE.MIN_WIDTH, startWidth + deltaX), + ); + break; + } + + case "bottomLeft": { + newHeight = Math.min( + window.innerHeight - startPosition.y - PADDING, + Math.max(PAGE.MIN_HEIGHT, startHeight + deltaY), + ); + + newWidth = Math.min( + startPosition.x + startWidth, + Math.max(PAGE.MIN_WIDTH, startWidth - deltaX), + ); + newX = Math.max(0, startPosition.x + startWidth - newWidth); + break; + } + + case "bottomRight": { + newHeight = Math.min( + window.innerHeight - startPosition.y - PADDING, + Math.max(PAGE.MIN_HEIGHT, startHeight + deltaY), + ); + + newWidth = Math.min( + window.innerWidth - startPosition.x - getSidebarWidth() - PADDING, + Math.max(PAGE.MIN_WIDTH, startWidth + deltaX), + ); + break; + } + } setSize({ width: newWidth, height: newHeight }); + setPosition({ x: newX, y: newY }); }; const stopResize = () => {