11"use client" ;
22
3- import React from "react" ;
3+ import React , { useState , useEffect } from "react" ;
44import Image from "next/image" ;
5- import { motion } from "framer-motion" ;
5+ import { motion , useAnimation } from "framer-motion" ;
66import NavBar from "../NavBar/page" ;
77import Footer from "../Footer/page" ;
88
9+ const images = [
10+ "/Assets/Images/gallery_image.jpg" ,
11+ "/Assets/Images/cj9.jpg" ,
12+ "/Assets/Images/08.jpg" ,
13+ "/Assets/Images/cj1.jpg" ,
14+ "/Assets/Images/cj2.jpg" ,
15+ "/Assets/Images/cj3.jpg" ,
16+ "/Assets/Images/cj4.jpg" ,
17+ "/Assets/Images/cj5.jpg" ,
18+ "/Assets/Images/cj6.jpg" ,
19+ "/Assets/Images/cj7.jpg" ,
20+ "/Assets/Images/cj8.jpg" ,
21+ ] ;
22+
23+ const IMAGE_WIDTH = 600 + 48 ; // width + 2*mx-6 (24px each side)
24+
925const Gallery = ( ) => {
26+ const controls = useAnimation ( ) ;
27+ const [ isPaused , setIsPaused ] = useState ( false ) ;
28+ const [ offset , setOffset ] = useState ( 0 ) ; // offset in px
29+ const [ hoveredIdx , setHoveredIdx ] = useState < number | null > ( null ) ;
30+
31+ // Start animation
32+ useEffect ( ( ) => {
33+ if ( ! isPaused ) {
34+ controls . start ( {
35+ x : [ offset , offset - ( images . length * IMAGE_WIDTH ) ] ,
36+ transition : {
37+ repeat : Infinity ,
38+ repeatType : "loop" ,
39+ duration : 25 ,
40+ ease : "linear" ,
41+ } ,
42+ } ) ;
43+ } else {
44+ controls . stop ( ) ;
45+ }
46+ // eslint-disable-next-line
47+ } , [ isPaused , offset , controls ] ) ;
48+
49+ // When hover, set offset so hovered image is first
50+ const handleMouseEnter = ( idx : number ) => {
51+ setIsPaused ( true ) ;
52+ setHoveredIdx ( idx ) ;
53+ setOffset ( - idx * IMAGE_WIDTH ) ;
54+ controls . set ( { x : - idx * IMAGE_WIDTH } ) ;
55+ } ;
56+
57+ // On leave, resume animation from current offset
58+ const handleMouseLeave = ( ) => {
59+ setIsPaused ( false ) ;
60+ setHoveredIdx ( null ) ;
61+ } ;
62+
1063 return (
1164 < div className = "w-full min-h-screen bg-black" >
1265 < NavBar />
13-
66+
1467 < div className = "container mx-auto pt-32 pb-20 px-4 md:px-8 lg:px-16" >
1568 < motion . div
1669 initial = { { opacity : 0 , y : 20 } }
@@ -27,35 +80,48 @@ const Gallery = () => {
2780 </ motion . div >
2881
2982 < div className = "flex justify-center" >
30- < motion . div
31- initial = { { opacity : 0 , scale : 0.9 } }
32- animate = { { opacity : 1 , scale : 1 } }
33- transition = { {
34- duration : 0.8 ,
35- delay : 0.3 ,
36- ease : "easeOut"
37- } }
38- className = "relative overflow-hidden rounded-xl border border-white/10 shadow-lg w-full max-w-4xl mx-auto"
39- whileHover = { { scale : 1.02 } }
40- whileTap = { { scale : 0.98 } }
41- >
42- < div className = "relative w-full aspect-[16/9] md:aspect-[16/10] lg:aspect-[16/9]" >
43- < Image
44- src = "/Assets/Images/gallery_image.jpg"
45- alt = "Gallery Image"
46- fill
47- className = "object-cover transition-transform duration-700 hover:scale-105"
48- sizes = "(max-width: 768px) 100vw, (max-width: 1200px) 80vw, 70vw"
49- priority
50- />
51-
52- < div className = "absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-300 flex items-end justify-center p-6" >
53- < p className = "text-white text-base md:text-xl font-medium text-center" > Capturing our journey of innovation and collaboration</ p >
54- </ div >
55- </ div >
56- </ motion . div >
57- </ div > </ div >
58-
83+ < div className = "overflow-hidden w-full max-w-6xl mx-auto rounded-xl border border-white/10 shadow-lg" >
84+ < motion . div
85+ className = "flex"
86+ style = { { width : "max-content" } }
87+ animate = { controls }
88+ >
89+ { [ ...images , ...images ] . map ( ( src , idx ) => (
90+ < motion . div
91+ key = { idx }
92+ className = "relative flex-shrink-0 mx-6"
93+ style = { {
94+ width : "600px" ,
95+ height : "340px" ,
96+ } }
97+ whileHover = { {
98+ scale : 1.08 ,
99+ zIndex : 2 ,
100+ boxShadow : "0 8px 32px 0 rgba(0,0,0,0.45)" ,
101+ } }
102+ onMouseEnter = { ( ) => handleMouseEnter ( idx % images . length ) }
103+ onMouseLeave = { handleMouseLeave }
104+ >
105+ < Image
106+ src = { src }
107+ alt = { `Gallery Image ${ idx + 1 } ` }
108+ fill
109+ className = "object-cover rounded-xl"
110+ sizes = "(max-width: 768px) 90vw, (max-width: 1200px) 45vw, 600px"
111+ priority = { idx === 0 }
112+ />
113+ < div className = "absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-0 hover:opacity-100 transition-opacity duration-300 flex items-end justify-center p-6 rounded-xl" >
114+ < p className = "text-white text-base md:text-xl font-medium text-center" >
115+ Capturing our journey of innovation and collaboration
116+ </ p >
117+ </ div >
118+ </ motion . div >
119+ ) ) }
120+ </ motion . div >
121+ </ div >
122+ </ div >
123+ </ div >
124+
59125 < Footer />
60126 </ div >
61127 ) ;
0 commit comments