From 6177bbbf8d03c73635c19472ea20ce619d09e6f3 Mon Sep 17 00:00:00 2001 From: zojgame Date: Thu, 29 Feb 2024 18:37:13 +0500 Subject: [PATCH] modal animation --- src/components/Layout.tsx | 18 ++- src/components/ModalContainer.tsx | 37 ++++++ .../desktop/Appartment/ButtonPanel.tsx | 10 +- .../desktop/Appartment/ImagesModal.tsx | 124 ++++++++++++------ .../desktop/Appartment/LayoutModal.tsx | 90 ++++++++++--- src/pages/Desktop/DesktopApartmentPage.tsx | 38 +++--- src/store/store.ts | 12 +- 7 files changed, 238 insertions(+), 91 deletions(-) create mode 100644 src/components/ModalContainer.tsx diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx index b9b11c7..635d86f 100644 --- a/src/components/Layout.tsx +++ b/src/components/Layout.tsx @@ -1,14 +1,24 @@ import { Outlet } from "react-router-dom"; import useStore from "../store/store"; +import { FullScreen, useFullScreenHandle } from "react-full-screen"; +import { useEffect } from "react"; +import { ModalContainer } from "./ModalContainer"; const Layout = () => { - const { modal, loader } = useStore(); + const { loader, setOnFullscreen } = useStore(); + const onFullscreenHandle = useFullScreenHandle(); + + useEffect(() => { + setOnFullscreen(onFullscreenHandle); + }, []); + return ( - <> - {modal} + + {/* {modal} */} {loader} - + + ); }; diff --git a/src/components/ModalContainer.tsx b/src/components/ModalContainer.tsx new file mode 100644 index 0000000..9502b5a --- /dev/null +++ b/src/components/ModalContainer.tsx @@ -0,0 +1,37 @@ +import { useEffect } from "react"; +import useStore from "../store/store"; + +function ModalContainer() { + const { modal, modalAnimation, setModal, setModalAnimation } = useStore(); + + useEffect(() => { + if (!modal) return; + setModalAnimation(1); + }, [modal]); + + useEffect(() => { + if (modalAnimation !== 0) return; + + const timeout = setTimeout(() => { + setModal(null); + }, 300); + + return clearTimeout(timeout); + }, [modalAnimation]); + + if (modal) { + return ( +
+ {modal} +
+ ); + } +} + +export default ModalContainer; diff --git a/src/components/desktop/Appartment/ButtonPanel.tsx b/src/components/desktop/Appartment/ButtonPanel.tsx index 9117db8..7b557ae 100644 --- a/src/components/desktop/Appartment/ButtonPanel.tsx +++ b/src/components/desktop/Appartment/ButtonPanel.tsx @@ -13,15 +13,21 @@ import ImagesModal from "./ImagesModal"; import PedestrianIcon from "../../../icons/Pedestrianicon"; type ButtonPanelProps = { - handleFullscreen: FullScreenHandle; + handleFullscreen: FullScreenHandle | null; }; const ButtonPanel = ({ handleFullscreen }: ButtonPanelProps) => { - const { setModal, is3DTour, currentView } = useStore(); + const [setModal, is3DTour, currentView] = useStore((state) => [ + state.setModal, + state.is3DTour, + state.currentView, + ]); const [isFullMode, setIsFullMode] = useState(false); const handleOnResizeClick = () => { + if (!handleFullscreen) return; + setIsFullMode((prev) => !prev); if (isFullMode) { handleFullscreen.enter(); diff --git a/src/components/desktop/Appartment/ImagesModal.tsx b/src/components/desktop/Appartment/ImagesModal.tsx index 70b1dd7..39b4243 100644 --- a/src/components/desktop/Appartment/ImagesModal.tsx +++ b/src/components/desktop/Appartment/ImagesModal.tsx @@ -5,31 +5,73 @@ import CrossButton from "../../CrossButton"; import BackButton from "../../BackButton"; const ImagesModal = () => { - const { currentVilla, setModal } = useStore(); + const { currentVilla, setModal, setModalAnimation } = useStore(); const [offset, setOffset] = useState(0); const modalRef = useRef(null); + const buttonContainerRef = useRef(null); useEffect(() => { if (!modalRef) return; gsap.fromTo( modalRef.current, { - height: 0, - x: "3000vw", + translateX: "100vw", + translateY: "-100vh", }, { - height: "100vh", - x: 0, + translateX: 0, + translateY: 0, + duration: 0.3, + } + ); + + if (!buttonContainerRef) return; + gsap.fromTo( + buttonContainerRef.current, + { + opacity: 0, + }, + { + opacity: 1, duration: 0.3, } - // { x: "-200vw", y: "-200vh" }, - // { y: "300vh" }, - // { y: "0", duration: 0.5 } ); }, []); function handleOnClose(): void { - setModal(null); + setModalAnimation(0); + const onAnimationComplete = () => { + setModal(null); + const timeout = setTimeout(() => { + clearTimeout(timeout); + }, 200); + }; + + // if (!modalRef) return; + // gsap.fromTo( + // modalRef.current, + // { + // translateX: 0, + // translateY: 0, + // }, + // { + // translateX: "100vw", + // translateY: "-100vh", + // duration: 0.3, + // onComplete: onAnimationComplete, + // } + // ); + + // gsap.fromTo( + // buttonContainerRef.current, + // { + // opacity: 1, + // }, + // { + // opacity: 0, + // duration: 0.3, + // } + // ); } function handleOnRightClick(): void { @@ -48,40 +90,40 @@ const ImagesModal = () => { } return ( -
-
- {currentVilla && - currentVilla.perspectiveWorkings.map((image) => ( -
- -
- ))} + <> +
+
+ {currentVilla && + currentVilla.perspectiveWorkings.map((image) => ( +
+ +
+ ))} +
-
- +
+
+ +
+ +
- - -
+ ); }; diff --git a/src/components/desktop/Appartment/LayoutModal.tsx b/src/components/desktop/Appartment/LayoutModal.tsx index a0751a3..e6637a7 100644 --- a/src/components/desktop/Appartment/LayoutModal.tsx +++ b/src/components/desktop/Appartment/LayoutModal.tsx @@ -1,4 +1,5 @@ -import { useEffect, useState } from "react"; +import { useEffect, useState, useRef } from "react"; +import gsap from "gsap"; import useStore from "../../../store/store"; import UnitList from "../../UnitList"; import LayoutSlider from "../../mobile/Appartment/LayoutSlider"; @@ -11,6 +12,25 @@ const LayoutModal = () => { const [currentUnits, setCurrentUnits] = useState( currentVilla?.groundFloorUnits ); + + const modalRef = useRef(null); + + useEffect(() => { + if (!modalRef) return; + gsap.fromTo( + modalRef.current, + { + left: "100vw", + bottom: "100vh", + }, + { + left: 0, + bottom: 0, + duration: 0.3, + } + ); + }, []); + useEffect(() => { if (currentVilla) { switch (currentView) { @@ -28,31 +48,59 @@ const LayoutModal = () => { }, [currentView, currentVilla]); const handleOnCloseClick = () => { - setModal(null); + const onAnimationComplete = () => { + const timeout = setTimeout(() => { + setModal(null); + clearTimeout(timeout); + }, 200); + }; + + gsap.fromTo( + modalRef.current, + { + left: 0, + bottom: 0, + }, + { + left: "100vw", + bottom: "100vh", + duration: 0.5, + onComplete: onAnimationComplete, + } + ); }; + return ( -
-
+ //
+ <> +
+
+
+ {currentUnits && } +
+
+ + +
+
+
+
-
-
- {currentUnits && } -
-
- - -
-
-
+ {/*
+ <> */} + ); }; diff --git a/src/pages/Desktop/DesktopApartmentPage.tsx b/src/pages/Desktop/DesktopApartmentPage.tsx index 00e1b9a..9bf0aa4 100644 --- a/src/pages/Desktop/DesktopApartmentPage.tsx +++ b/src/pages/Desktop/DesktopApartmentPage.tsx @@ -2,7 +2,6 @@ import { Unity } from "react-unity-webgl"; import { useEffect, useState } from "react"; import { ReactUnityEventParameter } from "react-unity-webgl/distribution/types/react-unity-event-parameters"; -import { FullScreen, useFullScreenHandle } from "react-full-screen"; import useStore from "../../store/store"; import LoaderModal from "../../components/LoaderModal"; import ButtonPanel from "../../components/desktop/Appartment/ButtonPanel"; @@ -12,8 +11,13 @@ import ViewToggle from "../../components/ViewToggle"; import ParameterDescription from "../../components/desktop/Appartment/ParameterDescription"; const DesktopApartmentPage = () => { - const { setCurrentView, setSendMessageToUnity, setLoader, setIs3DTour } = - useStore(); + const { + setCurrentView, + setSendMessageToUnity, + setLoader, + setIs3DTour, + onFullscreen, + } = useStore(); const { villa } = useVilla(); @@ -66,27 +70,19 @@ const DesktopApartmentPage = () => { } }, [isContainerLoaded]); - const onFullscreenHandle = useFullScreenHandle(); - return ( <> - -
-
- - - -
- +
+
+ + +
- + +
); }; diff --git a/src/store/store.ts b/src/store/store.ts index 5de0fe1..575b444 100644 --- a/src/store/store.ts +++ b/src/store/store.ts @@ -2,9 +2,12 @@ import { create } from "zustand"; import { ReactUnityEventParameter } from "react-unity-webgl/distribution/types/react-unity-event-parameters"; import { Villa } from "../types/appartment"; import { VILLAS } from "../consts/villas"; +import { FullScreenHandle } from "react-full-screen"; interface StoreType { currentVilla: Villa | null; + modalAnimation: number; + onFullscreen: FullScreenHandle | null; selectedOnMapVilla: Villa | null; loader: React.ReactNode | null; panel: React.ReactNode | null; @@ -19,6 +22,9 @@ interface StoreType { currentView: number; is3DTour: boolean; + + setModalAnimation: (animation: number) => void; + setOnFullscreen: (onFullscreen: FullScreenHandle) => void; setIs3DTour: (is3D: boolean) => void; setCurrentVilla: (villa: Villa) => void; setSelectedOnMapVilla: (villa: Villa | null) => void; @@ -36,7 +42,8 @@ interface StoreType { } const useStore = create((set) => ({ - // currentVilla: null, + modalAnimation: 0, + onFullscreen: null, currentVilla: VILLAS[0], is3DTour: false, selectedOnMapVilla: null, @@ -46,7 +53,8 @@ const useStore = create((set) => ({ loader: null, currentView: 1, - + setModalAnimation: (anim) => set(() => ({modalAnimation: anim})), + setOnFullscreen: (onFullscreen) => set(() => ({onFullscreen: onFullscreen})), setIs3DTour: (is3DTour) => set(() => ({ is3DTour: is3DTour })), setSelectedOnMapVilla: (villa) => set(() => ({ selectedOnMapVilla: villa })), setCurrentVilla: (villa) => set(() => ({ currentVilla: villa })),