Skip to content

Commit 0f6d98e

Browse files
committed
feat: Add animation in landing page
1 parent 0790a8c commit 0f6d98e

3 files changed

Lines changed: 104 additions & 42 deletions

File tree

src/pages/landingPage/IntroSection.jsx

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import idolImage from '@/assets/images/introSectionIdolImage.webp';
33
import PrimaryButton from '@/components/PrimaryButton';
44
import { useNavigate } from 'react-router-dom';
55
import { setCredits } from '@/utils/creditStorage.js';
6+
import FadeInDiv from '@/components/FadeInDiv';
67

78
function IntroSection() {
89
const navigate = useNavigate();
@@ -14,33 +15,41 @@ function IntroSection() {
1415

1516
return (
1617
<div className="py-[120px] relative flex flex-col items-center w-full">
17-
<h1 className="z-10 text-center text-[26px] font-bold">
18-
내가 좋아하는 아이돌을 <br />
19-
가장 <span className="text-coralRed">쉽게 덕질</span> 하는 방법
20-
</h1>
21-
<img
22-
src={fandomKLogo}
23-
alt="FandomKLogo"
24-
className="cursor-pointer z-10 mt-[20px] w-[236px] h-[44px] tablet:w-[324px] tablet:h-[62px] pc:w-[512px] pc:h-[98px] select-none"
25-
onClick={() => {
26-
handleClick(false);
27-
}}
28-
/>
29-
<img
30-
src={idolImage}
31-
alt="idolImage"
32-
className="w-[392px] h-[328px] mt-[20px] h-auto opacity-70 top-[100px] tablet:w-[712px] tablet:w-[596px] pc:absolute pc:w-[932px] pc:h-[780px] select-none"
33-
/>
34-
<PrimaryButton
35-
className={
36-
'mt-[40px] w-[230px] h-[48px] rounded-[3px] text-[14px] tablet:mt-[100px] tablet:w-[477px] pc:mt-[600px]'
37-
}
38-
onClickFunc={() => {
39-
handleClick(true);
40-
}}
41-
>
42-
지금 시작하기
43-
</PrimaryButton>
18+
<FadeInDiv className="z-10">
19+
<h1 className="text-center text-[26px] font-bold">
20+
내가 좋아하는 아이돌을 <br />
21+
가장 <span className="text-coralRed">쉽게 덕질</span> 하는 방법
22+
</h1>
23+
</FadeInDiv>
24+
<FadeInDiv className="z-10 cursor-pointer z-10 mt-[20px] w-[236px] h-[44px] tablet:w-[324px] tablet:h-[62px] pc:w-[512px] pc:h-[98px] select-none">
25+
<img
26+
src={fandomKLogo}
27+
alt="FandomKLogo"
28+
className="z-10 cursor-pointer z-10 mt-[20px] w-[236px] h-[44px] tablet:w-[324px] tablet:h-[62px] pc:w-[512px] pc:h-[98px]"
29+
onClick={() => {
30+
handleClick(false);
31+
}}
32+
/>
33+
</FadeInDiv>
34+
<FadeInDiv className="w-[392px] mt-[20px] opacity-70 top-[100px] tablet:w-[712px] tablet:h-[596px] pc:absolute pc:w-[932px] pc:h-[780px] select-none">
35+
<img
36+
src={idolImage}
37+
alt="아이돌 사진"
38+
className="w-[392px] h-[328px] mt-[20px] opacity-70 top-[100px] tablet:w-[712px] tablet:h-[596px] pc:absolute pc:w-[932px] pc:h-[780px] select-none"
39+
/>
40+
</FadeInDiv>
41+
<FadeInDiv delay="0.3s">
42+
<PrimaryButton
43+
className={
44+
'mt-[40px] w-[230px] h-[48px] rounded-[3px] text-[14px] tablet:mt-[100px] tablet:w-[477px] pc:mt-[600px]'
45+
}
46+
onClickFunc={() => {
47+
handleClick(true);
48+
}}
49+
>
50+
지금 시작하기
51+
</PrimaryButton>
52+
</FadeInDiv>
4453
</div>
4554
);
4655
}

src/pages/landingPage/LandingPage.jsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import phoneImage1 from '@/assets/images/mainSectionPhoneImage1.webp';
44
import phoneImage2 from '@/assets/images/mainSectionPhoneImage2.webp';
55
import phoneImage3 from '@/assets/images/mainSectionPhoneImage3.webp';
66
import MainSectionList from '@/pages/landingPage/MainSectionList';
7+
import { useEffect } from 'react';
78

89
const sections = [
910
{
@@ -27,6 +28,17 @@ const sections = [
2728
];
2829

2930
function LandingPage() {
31+
useEffect(() => {
32+
const handleRefresh = () => {
33+
window.scrollTo(0, 0); // 새로고침 시 페이지 상단으로 이동
34+
};
35+
36+
window.addEventListener('beforeunload', handleRefresh);
37+
38+
return () => {
39+
window.removeEventListener('beforeunload', handleRefresh);
40+
};
41+
}, []);
3042
return (
3143
<div className="bg-midnightBlack text-softWhite font-pretendard min-h-screen">
3244
<img

src/pages/landingPage/MainSectionList.jsx

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import FadeInDiv from '@/components/FadeInDiv';
2+
import { useState, useRef, useEffect } from 'react';
3+
14
function MainSectionList({ headText, semiHeadText, imgData, backgroundImage }) {
25
const { src, alt } = imgData;
36

@@ -8,28 +11,66 @@ function MainSectionList({ headText, semiHeadText, imgData, backgroundImage }) {
811
mainSectionBackgroundImage3: 'bg-mainSectionBackgroundImage3',
912
})[name] || '';
1013

14+
const targetRef = useRef(null); // 관찰할 DOM 요소
15+
const [triggered, setTriggered] = useState(false); // 트리거 상태 관리
16+
17+
useEffect(() => {
18+
const observer = new IntersectionObserver(
19+
([entry]) => {
20+
if (entry.isIntersecting) {
21+
setTriggered(true); // 트리거 상태를 true로 변경
22+
observer.disconnect(); // 한 번 실행 후 옵저버 정지
23+
}
24+
},
25+
{
26+
root: null, // 뷰포인트 기준 (null은 브라우저의 뷰포인트를 기준으로 함)
27+
threshold: 0.15, // 요소가 10%만 뷰포인트에 들어와도 트리거
28+
}
29+
);
30+
31+
if (targetRef.current) {
32+
observer.observe(targetRef.current); // 타겟 요소 관찰 시작
33+
}
34+
35+
return () => {
36+
if (targetRef.current) {
37+
observer.disconnect(); // 컴포넌트 언마운트 시 옵저버 정지
38+
}
39+
};
40+
}, []);
41+
1142
return (
12-
<div className="relative flex flex-col items-center overflow-hidden">
43+
<div
44+
className="relative flex flex-col items-center overflow-hidden"
45+
ref={targetRef}
46+
>
1347
{/* 배경 이미지 */}
14-
<div
48+
<FadeInDiv
49+
triggered={triggered}
1550
className={`z-0 absolute top-[90px] tablet:top-[45px] pc:top-[90px] w-[768px] h-[768px] pc:w-[900px] pc:h-[900px] bg-cover bg-center ${getBackgroundClass(backgroundImage)}`}
1651
>
1752
<div className="z-2 absolute inset-0 bg-radial-black"></div>
18-
</div>
19-
53+
</FadeInDiv>
2054
{/* 콘텐츠 */}
21-
<div className="flex flex-col z-10 mt-[60px] mb-[240px] items-center gap-4 text-center">
22-
<h2 className="text-[16px] leading-[20px] font-medium text-[#D2C030]">
23-
{headText}
24-
</h2>
25-
<h1 className="text-[24px] leading-[28px] font-bold whitespace-pre-line">
26-
{semiHeadText}
27-
</h1>
28-
<img
29-
src={src}
30-
alt={alt}
55+
<div className="flex flex-col z-10 mt-[60px] mb-[120px] items-center gap-4 text-center">
56+
<FadeInDiv triggered={triggered} delay="0s">
57+
<h2 className="text-[16px] leading-[20px] font-medium text-[#D2C030]">
58+
{headText}
59+
</h2>
60+
<h1 className="text-[24px] leading-[28px] font-bold whitespace-pre-line">
61+
{semiHeadText}
62+
</h1>
63+
</FadeInDiv>
64+
<FadeInDiv
65+
triggered={triggered}
3166
className="mt-[60px] w-[240px] h-[520px] tablet:w-[200px] tablet:h-[432px] pc:w-[320px] pc:h-[692px]"
32-
/>
67+
>
68+
<img
69+
src={src}
70+
alt={alt}
71+
className="w-[240px] h-[520px] tablet:w-[200px] tablet:h-[432px] pc:w-[320px] pc:h-[692px]"
72+
/>
73+
</FadeInDiv>
3374
</div>
3475
</div>
3576
);

0 commit comments

Comments
 (0)