@@ -60,6 +60,20 @@ const bounceAnimation = {
6060 } ,
6161} ;
6262
63+ const backgroundVariants = {
64+ initial : {
65+ backgroundColor : "#1a1a1a" ,
66+ } ,
67+ animate : {
68+ backgroundColor : "#2a2a2a" ,
69+ transition : {
70+ duration : 20 ,
71+ repeat : Infinity ,
72+ repeatType : "reverse" as const ,
73+ } ,
74+ } ,
75+ } ;
76+
6377export default function LandingPage ( ) {
6478 const isLargeScreen = useMediaQuery ( { minWidth : 641 } ) ;
6579 const [ currentSlide , setCurrentSlide ] = useState ( 0 ) ;
@@ -71,12 +85,12 @@ export default function LandingPage() {
7185 useEffect ( ( ) => {
7286 setIsLoaded ( true ) ;
7387 lenisRef . current = new Lenis ( {
74- duration : 0.8 , // 1.2์์ 0.8๋ก ๋ณ๊ฒฝ
75- easing : ( t : number ) => Math . min ( 1 , 1.001 - Math . pow ( 2 , - 10 * t ) ) ,
88+ duration : 1.2 ,
89+ easing : ( t ) => Math . min ( 1 , 1.001 - Math . pow ( 2 , - 10 * t ) ) ,
7690 smoothWheel : true ,
7791 wheelMultiplier : 2 ,
78- touchMultiplier : 1. 2,
79- infinite : false ,
92+ touchMultiplier : 2 ,
93+ infinite : true ,
8094 } ) ;
8195
8296 function raf ( time : number ) {
@@ -87,36 +101,38 @@ export default function LandingPage() {
87101 requestAnimationFrame ( raf ) ;
88102
89103 let lastScrollTime = 0 ;
90- const scrollThreshold = 500 ; // ms
104+ const scrollThreshold = 150 ;
91105
92106 lenisRef . current . on ( "scroll" , ( { progress } : { progress : number } ) => {
93107 const currentTime = Date . now ( ) ;
94108 if ( currentTime - lastScrollTime < scrollThreshold ) return ;
95109
96110 if ( ! isScrollingRef . current ) {
97111 const totalSlides = slides . length ;
98- const newSlideIndex = Math . min ( slides . length - 1 , Math . max ( 0 , Math . round ( progress * ( totalSlides - 1 ) ) ) ) ;
112+ const progressPerSlide = 1 / ( totalSlides - 1 ) ;
113+ const currentProgress = progress / progressPerSlide ;
114+ let newSlideIndex = Math . round ( currentProgress ) ;
115+
116+ if ( progress >= 0.99 ) {
117+ newSlideIndex = 0 ;
118+ setTimeout ( ( ) => {
119+ lenisRef . current ?. scrollTo ( 0 , {
120+ duration : 1.2 ,
121+ easing : ( t ) => t * ( 2 - t ) ,
122+ } ) ;
123+ } , 100 ) ;
124+ }
99125
100126 if ( newSlideIndex !== currentSlide ) {
101127 setCurrentSlide ( newSlideIndex ) ;
102128 isScrollingRef . current = true ;
103- const targetScroll =
104- ( newSlideIndex / ( totalSlides - 1 ) ) *
105- ( isLargeScreen ? containerRef . current ! . scrollHeight : containerRef . current ! . scrollWidth ) ;
106-
107- lenisRef . current ?. scrollTo ( targetScroll , {
108- immediate : false ,
109- duration : 600 , // 800์์ 600์ผ๋ก ๋ณ๊ฒฝ
110- easing : ( t : number ) => t * ( 2 - t ) ,
111- } ) ;
112-
113- lastScrollTime = currentTime ;
114129
115130 setTimeout ( ( ) => {
116131 isScrollingRef . current = false ;
117- } , 600 ) ; // 800์์ 600์ผ๋ก ๋ณ๊ฒฝ
132+ } , 200 ) ;
118133 }
119134 }
135+ lastScrollTime = currentTime ;
120136 } ) ;
121137
122138 document . documentElement . style . scrollbarWidth = "none" ;
@@ -143,34 +159,41 @@ export default function LandingPage() {
143159 < AnimatePresence >
144160 { isLoaded && (
145161 < motion . div
146- initial = { { opacity : 0 } }
147- animate = { { opacity : 1 } }
162+ variants = { backgroundVariants }
163+ initial = "initial"
164+ animate = "animate"
148165 exit = { { opacity : 0 } }
149166 transition = { { duration : 1 } }
150167 ref = { containerRef }
151- className = { `h-[400vh] min-h-[768px] overflow-hidden bg-gradient-to-br from-[#1a1a1a] to-[#2a2a2a] ${
152- isLargeScreen ? "" : "flex flex-col"
153- } `}
168+ className = { `relative h-[400vh] min-h-[768px] overflow-hidden ${ isLargeScreen ? "" : "flex flex-col" } ` }
154169 >
155- < div className = { `fixed inset-0 ${ isLargeScreen ? "flex" : "flex flex-col" } ` } >
170+ < div className = "absolute inset-0 opacity-20" >
171+ < div className = "particles-container" />
172+ </ div >
173+
174+ < motion . div
175+ className = { `fixed inset-0 ${ isLargeScreen ? "flex" : "flex flex-col" } ` }
176+ style = { {
177+ backdropFilter : "blur(8px)" ,
178+ WebkitBackdropFilter : "blur(8px)" ,
179+ } }
180+ >
156181 < motion . div
157- className = { `relative ${ isLargeScreen ? "w-1/2" : "flex h-1/2 w-full items-center justify-center overflow-hidden" } ` }
182+ className = { `relative ${
183+ isLargeScreen ? "w-1/2" : "flex h-1/2 w-full items-center justify-center overflow-hidden"
184+ } `}
158185 animate = { {
159186 width : currentSlide === 0 ? "100%" : isLargeScreen ? "50%" : "100%" ,
160187 height : currentSlide === 0 ? "100%" : isLargeScreen ? "100%" : "50%" ,
161188 } }
162189 transition = { { duration : 0.8 , ease : "easeInOut" } }
163190 >
164191 < motion . div
165- className = "absolute inset-0 flex items-center justify-center"
166- initial = { { opacity : 0 } }
192+ className = "relative flex h-full w-full items-center justify-center"
167193 animate = { {
168- opacity : 1 ,
169- } }
170- transition = { {
171- duration : 0.8 , // Updated transition duration
172- ease : "easeInOut" ,
194+ scale : currentSlide === 0 ? 1 : 0.8 ,
173195 } }
196+ transition = { { duration : 0.8 , ease : "easeInOut" } }
174197 >
175198 { currentSlide === 0 ? (
176199 < Image
@@ -179,6 +202,7 @@ export default function LandingPage() {
179202 width = { 800 }
180203 height = { 800 }
181204 className = "h-full max-h-[800px] w-full max-w-[800px] object-contain"
205+ priority
182206 />
183207 ) : currentSlide === 4 || currentSlide === 5 ? (
184208 < motion . div
@@ -187,20 +211,20 @@ export default function LandingPage() {
187211 initial = { { opacity : 0 , y : 20 } }
188212 animate = { { opacity : 1 , y : 0 } }
189213 exit = { { opacity : 0 , y : - 20 } }
190- transition = { { duration : 1.2 , ease : "easeInOut" } } // Update 1
214+ transition = { { duration : 1.2 , ease : "easeInOut" } }
191215 >
192216 < motion . h2
193- className = "mb-2 mt-0 text-center text-xl font-semibold text-gray-100 max-[640px]:mb-1 max-[640px]:px-4 md:mb-4 md:mt-0 md:text-3xl"
217+ className = "mb-2 mt-0 text-center text-xl font-semibold text-gray-100 drop-shadow-[0_2px_2px_rgba(0,0,0,0.3)] max-[640px]:mb-1 max-[640px]:px-4 md:mb-4 md:mt-0 md:text-3xl"
194218 initial = { { opacity : 0 , y : 20 } }
195219 animate = { { opacity : 1 , y : 0 } }
196- transition = { { delay : 0.3 , duration : 0.6 } } // Update 2
220+ transition = { { delay : 0.3 , duration : 0.6 } }
197221 >
198222 { slides [ currentSlide ] . blackAreaTitle }
199223 </ motion . h2 >
200224 < motion . div
201225 initial = { { opacity : 0 , y : 20 } }
202226 animate = { { opacity : 1 , y : 0 } }
203- transition = { { delay : 0.4 , duration : 0.6 } } // Update 2
227+ transition = { { delay : 0.4 , duration : 0.6 } }
204228 className = "mb-2 w-full max-w-[600px] max-[640px]:max-w-[75%] max-[640px]:px-4 md:mb-4"
205229 style = { { maxHeight : "calc(100% - 12rem)" } }
206230 >
@@ -221,28 +245,27 @@ export default function LandingPage() {
221245 className = "mb-0 max-w-[600px] whitespace-pre-wrap text-center text-sm text-gray-200 max-[640px]:mt-1 max-[640px]:px-4 md:text-xl"
222246 initial = { { opacity : 0 , y : 20 } }
223247 animate = { { opacity : 1 , y : 0 } }
224- transition = { { delay : 0.5 , duration : 0.6 } } // Update 2
248+ transition = { { delay : 0.5 , duration : 0.6 } }
225249 >
226250 { slides [ currentSlide ] . blackAreaContent }
227251 </ motion . p >
228252 </ motion . div >
229253 ) : (
230254 < motion . div
231- className = "absolute inset-0 flex items-center justify-center "
255+ className = "relative h-full max-h-[600px] w-full max-w-[600px] "
232256 initial = { { opacity : 0 } }
233257 animate = { { opacity : 1 } }
234258 exit = { { opacity : 0 } }
235- transition = { { duration : 0.8 } } // Update 3
259+ transition = { { duration : 0.8 } }
236260 >
237- < div className = "relative h-full max-h-[600px] w-full max-w-[600px]" >
238- < Image
239- src = "/brand.png"
240- alt = "Brand Logo"
241- fill
242- className = "object-contain"
243- sizes = "(max-width: 600px) 100vw, 600px"
244- />
245- </ div >
261+ < Image
262+ src = "/brand.png"
263+ alt = "Brand Logo"
264+ fill
265+ className = "object-contain"
266+ sizes = "(max-width: 600px) 100vw, 600px"
267+ priority
268+ />
246269 </ motion . div >
247270 ) }
248271 </ motion . div >
@@ -267,75 +290,103 @@ export default function LandingPage() {
267290 < AnimatePresence mode = "wait" >
268291 { currentSlide > 0 && (
269292 < motion . div
270- key = { currentSlide }
271- className = { `relative z-40 flex ${
272- isLargeScreen ? "w-1/2" : "h-1/2 w-full"
273- } flex-col items-center justify-center p-4 pb-6 pt-4 max-[640px]:px-12 max-[640px]:py-3 md:p-6 md:pb-8 md:pt-6`}
293+ className = { `relative z-40 flex ${ isLargeScreen ? "w-1/2" : "h-1/2 w-full" } ` }
274294 style = { {
275295 background : "linear-gradient(135deg, #71db77 0%, #56c45d 100%)" ,
276296 display : "flex" ,
277297 flexDirection : "column" ,
278298 justifyContent : "center" ,
279299 alignItems : "center" ,
280300 height : isLargeScreen ? "100%" : "50%" ,
301+ overflow : "hidden" ,
281302 } }
282- initial = { { opacity : 0 , [ isLargeScreen ? "y" : "x" ] : isLargeScreen ? "100%" : "100%" } }
283- animate = { { opacity : 1 , [ isLargeScreen ? "y" : "x" ] : 0 } }
284- exit = { { opacity : 0 , [ isLargeScreen ? "y" : "x" ] : isLargeScreen ? "-100%" : "-100%" } }
285- transition = { { duration : 0.4 , ease : "easeInOut" } } // Updated transition duration
303+ initial = { { width : 0 } }
304+ animate = { { width : isLargeScreen ? "50%" : "100%" } }
305+ transition = { { duration : 0.8 , ease : "easeInOut" } }
286306 >
287- < motion . h2
288- className = "mb-2 mt-0 text-center text-xl font-semibold text-[#1a1a1a] max-[640px]:mb-1 max-[640px]:px-4 md:mb-4 md:mt-0 md:text-3xl"
289- initial = { { opacity : 0 , y : 20 } }
290- animate = { { opacity : 1 , y : 0 } }
291- transition = { { delay : 0.05 , duration : 0.3 } } // Updated transition
292- >
293- { slides [ currentSlide ] . title }
294- </ motion . h2 >
295- < motion . div
296- initial = { { opacity : 0 , y : 20 } }
297- animate = { { opacity : 1 , y : 0 } }
298- transition = { { delay : 0.1 , duration : 0.3 } } // Updated transition
299- className = "mb-2 w-full max-w-[600px] max-[640px]:max-w-[75%] max-[640px]:px-4 md:mb-4"
300- style = { { maxHeight : "calc(100% - 12rem)" } }
301- >
302- < div
303- className = "relative w-full overflow-hidden rounded-lg shadow-lg"
304- style = { { paddingBottom : "56.25%" } }
307+ < AnimatePresence mode = "wait" >
308+ < motion . div
309+ key = { currentSlide }
310+ className = "flex h-full w-full flex-col items-center justify-center p-4 pb-6 pt-4 max-[640px]:px-12 max-[640px]:py-3 md:p-6 md:pb-8 md:pt-6"
311+ initial = { { y : "100%" } }
312+ animate = { { y : 0 } }
313+ exit = { { y : "-100%" } }
314+ transition = { { duration : 0.4 , ease : "easeInOut" } }
305315 >
306- < Image
307- src = { slides [ currentSlide ] . image || "" }
308- alt = { slides [ currentSlide ] . title || "" }
309- fill
310- style = { { objectFit : "cover" } }
311- sizes = "(max-width: 768px) 100vw, 600px"
312- />
313- </ div >
314- </ motion . div >
315- < motion . p
316- className = "mb-0 max-w-[600px] whitespace-pre-wrap text-center text-sm text-[#1a1a1a] max-[640px]:mt-1 max-[640px]:px-4 md:text-xl"
317- initial = { { opacity : 0 , y : 20 } }
318- animate = { { opacity : 1 , y : 0 } }
319- transition = { { delay : 0.15 , duration : 0.3 } } // Updated transition
320- >
321- { slides [ currentSlide ] . content }
322- </ motion . p >
316+ < motion . h2
317+ className = "mb-2 mt-0 text-center text-xl font-semibold text-[#1a1a1a] max-[640px]:mb-1 max-[640px]:px-4 md:mb-4 md:mt-0 md:text-3xl"
318+ initial = { { opacity : 0 , y : 20 } }
319+ animate = { { opacity : 1 , y : 0 } }
320+ transition = { { delay : 0.05 , duration : 0.3 } }
321+ >
322+ { slides [ currentSlide ] . title }
323+ </ motion . h2 >
324+ < motion . div
325+ initial = { { opacity : 0 , y : 20 } }
326+ animate = { { opacity : 1 , y : 0 } }
327+ transition = { { delay : 0.1 , duration : 0.3 } }
328+ className = "mb-2 w-full max-w-[600px] max-[640px]:max-w-[75%] max-[640px]:px-4 md:mb-4"
329+ style = { { maxHeight : "calc(100% - 12rem)" } }
330+ >
331+ < div
332+ className = "relative w-full overflow-hidden rounded-lg shadow-lg transition-shadow duration-300 hover:shadow-2xl"
333+ style = { { paddingBottom : "56.25%" } }
334+ >
335+ < Image
336+ src = { slides [ currentSlide ] . image || "" }
337+ alt = { slides [ currentSlide ] . title || "" }
338+ fill
339+ style = { { objectFit : "cover" } }
340+ sizes = "(max-width: 768px) 100vw, 600px"
341+ className = "transition-transform duration-300 hover:scale-105"
342+ />
343+ </ div >
344+ </ motion . div >
345+ < motion . p
346+ className = "mb-0 max-w-[600px] whitespace-pre-wrap text-center text-sm text-[#1a1a1a] max-[640px]:mt-1 max-[640px]:px-4 md:text-xl"
347+ initial = { { opacity : 0 , y : 20 } }
348+ animate = { { opacity : 1 , y : 0 } }
349+ transition = { { delay : 0.15 , duration : 0.3 } }
350+ >
351+ { slides [ currentSlide ] . content }
352+ </ motion . p >
353+ </ motion . div >
354+ </ AnimatePresence >
323355 </ motion . div >
324356 ) }
325357 </ AnimatePresence >
326- </ div >
358+ </ motion . div >
327359
328360 { currentSlide > 0 && (
329- < div
330- className = { `fixed ${ isLargeScreen ? "right-4 top-1/2 -translate-y-1/2 space-y-2" : "bottom-4 left-1/2 flex -translate-x-1/2 space-x-2" } ` }
361+ < motion . div
362+ className = { `fixed ${
363+ isLargeScreen
364+ ? "right-8 top-1/2 -translate-y-1/2 space-y-3"
365+ : "bottom-8 left-1/2 flex -translate-x-1/2 space-x-3"
366+ } `}
331367 >
332368 { slides . slice ( 1 ) . map ( ( _ , index ) => (
333- < div
369+ < motion . div
334370 key = { index + 1 }
335- className = { `h-4 w-4 rounded-full ${ index + 1 === currentSlide ? "bg-[#108b2d]" : "bg-[#f8fff8]" } ` }
371+ className = "h-3 w-3 cursor-pointer rounded-full border-2 border-white/50"
372+ whileHover = { { scale : 1.2 } }
373+ animate = { {
374+ backgroundColor : index + 1 === currentSlide ? "#108b2d" : "transparent" ,
375+ scale : index + 1 === currentSlide ? 1.2 : 1 ,
376+ } }
377+ onClick = { ( ) => {
378+ if ( ! isScrollingRef . current ) {
379+ const targetScroll =
380+ ( ( index + 1 ) / ( slides . length - 1 ) ) * ( containerRef . current ?. scrollHeight || 0 ) ;
381+ lenisRef . current ?. scrollTo ( targetScroll , {
382+ duration : 1.2 ,
383+ easing : ( t ) => t * ( 2 - t ) ,
384+ } ) ;
385+ }
386+ } }
336387 />
337388 ) ) }
338- </ div >
389+ </ motion . div >
339390 ) }
340391 </ motion . div >
341392 ) }
0 commit comments