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); } }