From 8b08b993899bb2539ebe3563ac0920851d36cf42 Mon Sep 17 00:00:00 2001 From: nirii00 Date: Tue, 25 Feb 2025 21:11:39 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EC=98=A8=EB=B3=B4=EB=94=A9=20=EC=95=A0?= =?UTF-8?q?=EB=8B=88=EB=A9=94=EC=9D=B4=EC=85=98=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20-=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=ED=8E=B8=EC=A7=80=20=EC=95=A0=EB=8B=88=EB=A9=94=EC=9D=B4?= =?UTF-8?q?=EC=85=98=20=EB=AA=A8=EB=B0=94=EC=9D=BC=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20-=20=EC=98=A8=EB=B3=B4=EB=94=A9=20?= =?UTF-8?q?=EB=8B=A8=EA=B3=84=EC=97=90=20=EB=94=B0=EB=A5=B8=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=EA=B4=80=EB=A6=AC=20-=20=EC=98=A8=EB=B3=B4=EB=94=A9?= =?UTF-8?q?=EC=9D=B4=20=EB=81=9D=EB=82=9C=20=ED=9B=84=20=ED=99=88=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/Onboarding/SetZipCode.tsx | 15 ++- src/pages/Onboarding/UserInteraction.tsx | 121 +++++++++++++------- src/pages/Onboarding/WelcomeLetter.tsx | 38 ++++++ src/pages/Onboarding/components/Spinner.tsx | 17 +-- src/pages/Onboarding/index.tsx | 31 ++++- src/styles/animations.css | 47 +++++++- src/styles/utilities.css | 16 +-- 7 files changed, 205 insertions(+), 80 deletions(-) create mode 100644 src/pages/Onboarding/WelcomeLetter.tsx diff --git a/src/pages/Onboarding/SetZipCode.tsx b/src/pages/Onboarding/SetZipCode.tsx index b941f78..b072660 100644 --- a/src/pages/Onboarding/SetZipCode.tsx +++ b/src/pages/Onboarding/SetZipCode.tsx @@ -1,3 +1,5 @@ +import { useEffect, useState } from 'react'; + import Spinner from './components/Spinner'; const SetZipCode = ({ @@ -6,7 +8,13 @@ const SetZipCode = ({ setIsZipCodeSet: React.Dispatch>; }) => { const DUMMY_ZIPCODE = '122A2'; + const [isBtnActive, setIsBtnActive] = useState(false); + useEffect(() => { + setTimeout(() => { + setIsBtnActive(true); + }, 6300); + }, []); return ( <>
@@ -16,13 +24,16 @@ const SetZipCode = ({
{DUMMY_ZIPCODE.split('').map((char, index) => ( - + ))}
diff --git a/src/pages/Onboarding/UserInteraction.tsx b/src/pages/Onboarding/UserInteraction.tsx index a7fee26..d6e33f7 100644 --- a/src/pages/Onboarding/UserInteraction.tsx +++ b/src/pages/Onboarding/UserInteraction.tsx @@ -1,18 +1,31 @@ import { useState, useRef, useEffect } from 'react'; -import { Link } from 'react-router'; import { twMerge } from 'tailwind-merge'; import envelope from '@/assets/images/closed-letter.png'; -import envelopeTop from '@/assets/images/envelope-pink-back-top.png'; +// import envelopeTop from '@/assets/images/envelope-pink-back-top.png'; import envelopeFront from '@/assets/images/opened-letter-front.png'; -export default function UserInteraction() { +export default function UserInteraction({ + setIsAnimationOver, +}: { + setIsAnimationOver: React.Dispatch>; +}) { const imgRef = useRef(null); - const [imgPos, setImgPos] = useState<{ top: number; width: number }>({ top: 0, width: 0 }); + const [imgPos, setImgPos] = useState<{ + top: number; + width: number; + height: number; + left: number; + }>({ + top: 0, + width: 0, + height: 0, + left: 0, + }); const [imgToBottom, setImgToBottom] = useState(false); const [startAnimation, setStartAnimation] = useState(false); - const [openAnimation, setOpenAnimation] = useState(false); + // const [openAnimation, setOpenAnimation] = useState(false); const [letterOutAnimation, setLetterOutAnimation] = useState(false); const [envelopeOut, setEnvelopeOut] = useState(false); const [finishAnimation, setFinishAnimation] = useState(false); @@ -20,7 +33,7 @@ export default function UserInteraction() { const handleLetterClick = () => { if (imgRef.current) { const rect = imgRef.current.getBoundingClientRect(); - setImgPos({ top: rect.top, width: rect.width }); + setImgPos({ top: rect.top, width: rect.width, height: rect.height, left: rect.left }); } setStartAnimation(true); setTimeout(() => { @@ -31,18 +44,18 @@ export default function UserInteraction() { useEffect(() => { if (imgToBottom) { setTimeout(() => { - setOpenAnimation(true); + setLetterOutAnimation(true); }, 1000); } }, [imgToBottom]); - useEffect(() => { - if (openAnimation) { - setTimeout(() => { - setLetterOutAnimation(true); - }, 2000); - } - }, [openAnimation]); + // useEffect(() => { + // if (openAnimation) { + // setTimeout(() => { + // setLetterOutAnimation(true); + // }, 2000); + // } + // }, [openAnimation]); useEffect(() => { if (letterOutAnimation) { @@ -56,9 +69,18 @@ export default function UserInteraction() { if (envelopeOut) { setTimeout(() => { setFinishAnimation(true); - }, 2000); + }, 1000); } }, [envelopeOut]); + + useEffect(() => { + if (finishAnimation) { + setTimeout(() => { + setIsAnimationOver(true); + }, 2000); + } + }, [finishAnimation]); + if (startAnimation === false) { return ( <> @@ -80,67 +102,78 @@ export default function UserInteraction() { ); } else { return ( - <> +
분홍색 편지지 - {letterOutAnimation && ( -
- )} - {openAnimation && ( + {/* {openAnimation && ( - )} + )} */} 분홍색 편지지 { + // if (e.animationName === 'envelopeSink') { + // const rect = sinkRef.current?.getBoundingClientRect(); + // if (rect?.top) setSinkRefTop({ top: rect?.top }); + // console.log('Animation ended. boundingRect top:', rect?.top); + // } + // }} className={twMerge( - `z-0 mx-10 h-auto rounded transition-transform duration-1000 ease-in-out`, - imgToBottom && 'translate-y-full', + `z-0 mx-10 h-auto rounded`, + imgToBottom && !envelopeOut && 'animate-envelopeSink', envelopeOut && 'animate-envelopeOut', )} style={{ - top: `${imgPos.top}px`, + top: `calc(${imgPos.top}px - 5rem)`, position: 'absolute', width: `${imgPos.width}px`, + left: '0px', }} /> - {/* TODO: 편지지 링크 */} - {finishAnimation && } - + {letterOutAnimation && ( +
+ )} +
); } } diff --git a/src/pages/Onboarding/WelcomeLetter.tsx b/src/pages/Onboarding/WelcomeLetter.tsx new file mode 100644 index 0000000..50b7e4e --- /dev/null +++ b/src/pages/Onboarding/WelcomeLetter.tsx @@ -0,0 +1,38 @@ +import { useNavigate } from 'react-router'; + +export default function index() { + // eslint-disable-next-line react-hooks/rules-of-hooks + const navigate = useNavigate(); + return ( +
+
+

To.따숨이

+

환영합니다! 우리 함께 마음을 나누어 보아요

+
+

안녕하세요, 따숨이님!

+
+

요즘 어떤 말을 하고싶으신가요?

+

36.5에서 따뜻한 마음의 편지를 나누어 보세요.

+
+

따뜻한 편지 문화를 위해 아래의 안내 사항을 숙지해주세요!

+

1. 욕설, 비방, 성희롱은 금지입니다.

+

+ 2. 만약 위의 이유로 신고를 당할 경우 경고를 받게 되고, 세번의 경고를 받게 되면 서비스를 + 이용하실 수 없습니다. +

+

3. 고민 편지에 대한 답장은 검수 후에 전달됩니다.

+
+

From.9황작물

+
+ +
+ ); +} diff --git a/src/pages/Onboarding/components/Spinner.tsx b/src/pages/Onboarding/components/Spinner.tsx index c4b9295..40baf62 100644 --- a/src/pages/Onboarding/components/Spinner.tsx +++ b/src/pages/Onboarding/components/Spinner.tsx @@ -13,23 +13,9 @@ const Spinner = ({ target, index }: SpinnerProps) => { const SPEED = 100 + 10 * index; const [position, setPosition] = useState(0); const [isRunning, setIsRunning] = useState(true); - let LETTER_HEIGHT = 40; + const LETTER_HEIGHT = 45; const animationFrameRef = useRef(null); - //TODO: 여러 기기에서 실효성 확인 - // 웹에서는 없어도 될 것 같음 - // calculate full height of the cycle - const containerRef = useRef(null); - useEffect(() => { - if (containerRef.current) { - console.log(LETTER_HEIGHT); - const letter = containerRef.current.querySelector('p'); - if (letter) { - LETTER_HEIGHT = letter.getBoundingClientRect().height; - } - } - console.log(LETTER_HEIGHT); - }, []); const FULL_ROTATION = -TARGET_ARR.length * LETTER_HEIGHT; useEffect(() => { @@ -72,7 +58,6 @@ const Spinner = ({ target, index }: SpinnerProps) => { style={{ willChange: 'transform' }} >
diff --git a/src/pages/Onboarding/index.tsx b/src/pages/Onboarding/index.tsx index 14b839c..70d7cec 100644 --- a/src/pages/Onboarding/index.tsx +++ b/src/pages/Onboarding/index.tsx @@ -1,14 +1,41 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import SetZipCode from './SetZipCode'; import UserInteraction from './UserInteraction'; +import WelcomeLetter from './welcomeLetter'; const OnboardingPage = () => { const [isZipCodeSet, setIsZipCodeSet] = useState(false); + const [isAnimationOver, setIsAnimationOver] = useState(false); + useEffect(() => { + if (isZipCodeSet || isAnimationOver) { + sessionStorage.setItem( + 'onBoarding', + JSON.stringify({ isZipCodeSet: isZipCodeSet, isAnimationOver: isAnimationOver }), + ); + } + }, [isZipCodeSet, isAnimationOver]); + + useEffect(() => { + const prevDataString = sessionStorage.getItem('onBoarding'); + if (prevDataString) { + const newData = JSON.parse(prevDataString); + console.log(newData); + setIsZipCodeSet(newData.isZipCodeSet); + setIsAnimationOver(newData.isAnimationOver); + console.log('isZipCode', isZipCodeSet, 'isAnimation', isAnimationOver); + } + }, []); return (
- {isZipCodeSet ? : } + {!isZipCodeSet ? ( + + ) : !isAnimationOver ? ( + + ) : ( + + )}
); }; diff --git a/src/styles/animations.css b/src/styles/animations.css index 154ca77..7217bbd 100644 --- a/src/styles/animations.css +++ b/src/styles/animations.css @@ -77,6 +77,14 @@ } } + --animate-float: float 2s ease-in-out infinite; + --animate-openEnvelope: openEnvelope 2s ease-in-out forwards; + --animate-expandScale: expandScale 2s ease-in-out forwards; + --animate-envelopeSink: envelopeSink 1s ease-in-out forwards; + --animate-envelopeOut: envelopeOut 2s ease-in-out forwards; + --animate-fadeOut: letter-fadeOut 1s ease 1s forwards; + --animate-fadeIn: letter-fadeIn 1s ease 1s forwards; + /* onBoarding */ /* comment floating */ @keyframes float { @@ -89,6 +97,19 @@ } } + /* onBoarding */ + /* letter sinking */ + @keyframes envelopeSink { + 0% { + transform: translateY(0); + transform-origin: bottom; + } + 100% { + transform: translateY(100%); + transform-origin: bottom; + } + } + /* onBoarding */ /* letter opening */ @keyframes openEnvelope { @@ -119,10 +140,32 @@ /* envelope out animation*/ @keyframes envelopeOut { 0% { - transform: translateY(0); + transform: translateY(100%); } 100% { - transform: translateY(100vh); + transform: translateY(2000%); + } + } + + /* onBoarding */ + /* welcomeLetter fadeIn */ + @keyframes letter-fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + /* onBoarding */ + /* welcomeLetter fadeOut */ + @keyframes letter-fadeOut { + from { + opacity: 1; + } + to { + opacity: 0; } } } diff --git a/src/styles/utilities.css b/src/styles/utilities.css index 5a3b206..f9e4577 100644 --- a/src/styles/utilities.css +++ b/src/styles/utilities.css @@ -84,19 +84,7 @@ border-style: solid !important; } - .animate-float { - animation: float 2s ease-in-out infinite; - } - - .animate-openEnvelope { - animation: openEnvelope 2s ease-in-out forwards; - } - - .animate-expandScale { - animation: expandScale 2s ease-in-out forwards; - } - - .animate-envelopeOut { - animation: envelopeOut 2s ease-in-out forwards; + .letter-gradient { + background: linear-gradient(to bottom, #ffffff, #f2f2f2); } }