File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ import { gsap } from 'gsap' ;
2+ import { ScrollTrigger } from 'gsap/ScrollTrigger' ;
3+
4+ let pluginsRegistered = false ;
5+
6+ const ensurePlugins = ( ) => {
7+ if ( pluginsRegistered ) return ;
8+ gsap . registerPlugin ( ScrollTrigger ) ;
9+ pluginsRegistered = true ;
10+ } ;
11+
12+ export type HeroSectionRefs = {
13+ titleEl : HTMLHeadingElement ;
14+ subTextEl : HTMLDivElement ;
15+ } ;
16+
17+ export function initHeroSectionAnimation ( {
18+ titleEl,
19+ subTextEl,
20+ } : HeroSectionRefs ) {
21+ ensurePlugins ( ) ;
22+
23+ // gsap.context를 쓰면 cleanup이 아주 깔끔해짐
24+ const ctx = gsap . context ( ( ) => {
25+ gsap . fromTo (
26+ subTextEl ,
27+ { opacity : 0 , y : 40 } ,
28+ {
29+ opacity : 1 ,
30+ y : 0 ,
31+ duration : 0.8 ,
32+ ease : 'power2.out' ,
33+ scrollTrigger : {
34+ trigger : titleEl ,
35+ start : 'right bottom+=100 60%' ,
36+ toggleActions : 'play none none reverse' ,
37+ } ,
38+ }
39+ ) ;
40+ } ) ;
41+
42+ return ( ) => ctx . revert ( ) ; // ✅ cleanup 반환
43+ }
Original file line number Diff line number Diff line change 1+ 'use client' ;
2+
3+ import { useLayoutEffect , useRef } from 'react' ;
4+ import { initHeroSectionAnimation } from '@/animations/landingGSAP' ;
5+
16const HeroSection = ( ) => {
7+ const titleRef = useRef < HTMLHeadingElement > ( null ) ;
8+ const subTextRef = useRef < HTMLDivElement > ( null ) ;
9+
10+ useLayoutEffect ( ( ) => {
11+ if ( ! titleRef . current || ! subTextRef . current ) return ;
12+
13+ const cleanup = initHeroSectionAnimation ( {
14+ titleEl : titleRef . current ,
15+ subTextEl : subTextRef . current ,
16+ } ) ;
17+
18+ return cleanup ;
19+ } , [ ] ) ;
20+
221 return (
3- < div className = "flex flex-col items-center justify-center space-y-3 pt-30 text-center" >
4- < h1 className = "text-8xl font-bold" > 매일 성장하는</ h1 >
22+ < div className = "flex flex-col items-center justify-center space-y-3 pt-100 text-center" >
23+ < h1 ref = { titleRef } className = "text-8xl font-bold" >
24+ 매일 성장하는
25+ </ h1 >
526 < h1 className = "text-primary text-8xl font-bold" > 개발자의 여정</ h1 >
6- < div className = "text-2xl font-light" >
27+ < div ref = { subTextRef } className = "text-2xl font-light" >
728 < h2 > TIL 작성부터 목표 관리까지, DevFlow와 함께</ h2 >
829 < h2 > 체계적인 학습으로 더 나은 개발자로 성장하세요</ h2 >
930 </ div >
Original file line number Diff line number Diff line change @@ -6,15 +6,22 @@ const LandingPreview = () => {
66 < div className = "mt-30 flex h-full flex-col items-center justify-center space-y-3 pb-50 text-center" >
77 < h1 className = "text-4xl font-bold" > 체계적인 학습으로</ h1 >
88 < h1 className = "text-primary text-4xl font-bold" > 더 빠른 성장</ h1 >
9- < div className = "mx-20 mt-10 flex flex-col items-center gap-10 lg:flex-row lg:items-start lg:gap-50" >
10- < FeatureContent />
11- < Image
12- src = "/PreviewImage.png"
13- alt = "DevFlow 미리보기"
14- width = { 720 }
15- height = { 400 }
16- className = "w-full max-w-[480px] min-w-[360px] flex-shrink-0 object-contain md:max-w-[560px] lg:max-w-[640px] xl:max-w-[720px]"
17- />
9+ < div className = "mx-20 mt-10 grid max-w-7xl grid-cols-1 items-start gap-10 lg:grid-cols-2 lg:gap-2" >
10+ { /* 왼쪽: 400 밑으로 못 내려가게 */ }
11+ < div className = "flex min-w-[355px] justify-center" >
12+ < FeatureContent />
13+ </ div >
14+
15+ { /* 오른쪽: 이미지 그대로 */ }
16+ < div className = "flex justify-center" >
17+ < Image
18+ src = "/PreviewImage.png"
19+ alt = "DevFlow 미리보기"
20+ width = { 720 }
21+ height = { 400 }
22+ className = "w-full max-w-[480px] min-w-[360px] object-contain md:max-w-[560px] lg:max-w-[640px] xl:max-w-[720px]"
23+ />
24+ </ div >
1825 </ div >
1926 </ div >
2027 ) ;
Original file line number Diff line number Diff line change 1111 "dependencies" : {
1212 "clsx" : " ^2.1.1" ,
1313 "firebase" : " ^12.7.0" ,
14+ "gsap" : " ^3.14.2" ,
1415 "next" : " 16.1.1" ,
1516 "react" : " 19.2.3" ,
1617 "react-dom" : " 19.2.3" ,
You can’t perform that action at this time.
0 commit comments