Skip to content

Commit 729590c

Browse files
authored
Merge pull request #8 from Aritra203/main
feat: update gallery with infinite scroll and hover start from hovere…
2 parents 15590f9 + 7ff023c commit 729590c

File tree

11 files changed

+98
-32
lines changed

11 files changed

+98
-32
lines changed

app/Gallery/page.tsx

Lines changed: 98 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,69 @@
11
"use client";
22

3-
import React from "react";
3+
import React, { useState, useEffect } from "react";
44
import Image from "next/image";
5-
import { motion } from "framer-motion";
5+
import { motion, useAnimation } from "framer-motion";
66
import NavBar from "../NavBar/page";
77
import 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+
925
const 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
);

public/Assets/Images/08.jpg

1.99 MB
Loading

public/Assets/Images/cj1.jpg

181 KB
Loading

public/Assets/Images/cj2.jpg

119 KB
Loading

public/Assets/Images/cj3.jpg

208 KB
Loading

public/Assets/Images/cj4.jpg

110 KB
Loading

public/Assets/Images/cj5.jpg

122 KB
Loading

public/Assets/Images/cj6.jpg

153 KB
Loading

public/Assets/Images/cj7.jpg

171 KB
Loading

public/Assets/Images/cj8.jpg

203 KB
Loading

0 commit comments

Comments
 (0)