From dc946e4f379644fb516304784605da25946f3853 Mon Sep 17 00:00:00 2001 From: Krish Agarwal Date: Sun, 26 Jul 2026 18:14:30 +0530 Subject: [PATCH] Add:gallery images --- src/config/gallary.js | 27 +-- src/config/teammate.js | 4 +- src/pages/gallery/Gallery.jsx | 378 +++++++++++++++++++++++----------- 3 files changed, 273 insertions(+), 136 deletions(-) diff --git a/src/config/gallary.js b/src/config/gallary.js index 94da7b3..a44bb63 100644 --- a/src/config/gallary.js +++ b/src/config/gallary.js @@ -1,4 +1,19 @@ +import img2026_1 from "../assets/2026.jpg"; +import img2026_2 from "../assets/2026 (2).jpg"; + const images = [ + { + id: 101, + src: img2026_1, + alt: "Gallery Image 2026 1", + year: 2026, + }, + { + id: 102, + src: img2026_2, + alt: "Gallery Image 2026 2", + year: 2026, + }, { id: 0, src: "https://res.cloudinary.com/dbnfkkfov/image/upload/v1759606221/WhatsApp_Image_2025-10-04_at_20.38.01_n5yqjt.jpg", @@ -161,12 +176,6 @@ const images = [ alt: "Gallery Image 26", year: 2025, }, - { - id: 27, - src: "https://res.cloudinary.com/dsjxx976j/image/upload/v1756627317/asme126_eqyzzs.jpg", - alt: "ASME Image 1", - year: "others", - }, { id: 28, src: "https://res.cloudinary.com/dsjxx976j/image/upload/v1756627315/asme132_vzqgiw.jpg", @@ -353,12 +362,6 @@ const images = [ alt: "ASME Image 32", year: "others", }, - { - id: 59, - src: "https://res.cloudinary.com/dsjxx976j/image/upload/v1756627213/asme1_ksyaia.jpg", - alt: "ASME Image 33", - year: "others", - }, ]; export default images; diff --git a/src/config/teammate.js b/src/config/teammate.js index 7311c12..8f6d10f 100644 --- a/src/config/teammate.js +++ b/src/config/teammate.js @@ -11,7 +11,7 @@ const teamMembers = [ { name: "Aayush Barik", title: "Vice President", - img: "https://res.cloudinary.com/ddoeahbpv/image/upload/Aayush_Barik_Vice_President_klgnid.jpg", + img: "https://res.cloudinary.com/dm406z4pf/image/upload/v1785069742/Aayush_Barik_Vice_President_2_wbg5bq.jpg", description: "2", team: "Executive Body", linkedin: "https://www.linkedin.com/in/aayush-barik-668843339/", @@ -139,7 +139,7 @@ const teamMembers = [ { name: "Yegnesh Sagar", title: "Captain", - img: "https://res.cloudinary.com/ddoeahbpv/image/upload/images_1_ujpf6e.jpg", + img: "https://res.cloudinary.com/dm406z4pf/image/upload/v1785069027/1784538371641_vmsozp.png", description: "18", team: "Team Bluebird", linkedin: "https://www.linkedin.com/in/yegnesh-sagar-89778b348/", diff --git a/src/pages/gallery/Gallery.jsx b/src/pages/gallery/Gallery.jsx index 9639f59..9863d42 100644 --- a/src/pages/gallery/Gallery.jsx +++ b/src/pages/gallery/Gallery.jsx @@ -1,174 +1,308 @@ -import { useState, useEffect } from "react"; +import { useState, useEffect, useCallback, useMemo } from "react"; import images from "../../config/gallary"; +import { ChevronLeft, ChevronRight, Maximize2, X } from "lucide-react"; -const NavButton = ({ direction, onClick }) => { - const isNext = direction === "next"; - return ( - - ); -}; - -const YearButton = ({ year, isSelected, onClick }) => { - const label = year === "all" ? "All" : String(year); - return ( - - ); -}; - -const GalleryItem = ({ image }) => ( -
- {image.alt} -
-); - -export default function GallaryPage() { +export default function GalleryPage() { const [selectedYear, setSelectedYear] = useState("all"); const [currentSlide, setCurrentSlide] = useState(0); + const [lightboxIndex, setLightboxIndex] = useState(null); + const [failedImages, setFailedImages] = useState({}); + + // Slide Images for top hero (uses first 6 images from dataset) + const heroSlides = useMemo( + () => images.slice(0, Math.min(images.length, 6)), + [], + ); + // Auto Hero Slider (5s interval) useEffect(() => { + if (heroSlides.length === 0) return; const interval = setInterval(() => { - setCurrentSlide((prev) => (prev + 1) % images.length); + setCurrentSlide((prev) => (prev + 1) % heroSlides.length); }, 5000); return () => clearInterval(interval); + }, [heroSlides.length]); + + // Build sorted years list (numeric years sorted, then string years) + const years = useMemo(() => { + const allYears = Array.from(new Set(images.map((img) => img.year))); + const numericYears = allYears + .filter((y) => typeof y === "number") + .sort((a, b) => b - a); + const stringYears = allYears + .filter((y) => typeof y === "string" && y !== "all") + .sort(); + return ["all", ...numericYears, ...stringYears]; }, []); - // Build years list keeping numeric years sorted, then string years - const allYears = Array.from(new Set(images.map((image) => image.year))); - const numericYears = allYears - .filter((y) => typeof y === "number") - .sort((a, b) => a - b); - const stringYears = allYears - .filter((y) => typeof y === "string" && y !== "all") - .sort(); - const years = ["all", ...numericYears, ...stringYears]; - - const galleryImages = (() => { + // Filtered gallery images for grid + const galleryImages = useMemo(() => { if (selectedYear === "all") return images; - // if selectedYear is a string that is not numeric, filter by exact match if (typeof selectedYear === "string" && isNaN(Number(selectedYear))) { - return images.filter((image) => image.year === selectedYear); + return images.filter((img) => img.year === selectedYear); } - // otherwise treat as numeric year - return images.filter((image) => image.year === Number(selectedYear)); - })(); + return images.filter((img) => img.year === Number(selectedYear)); + }, [selectedYear]); + + // Fallback image helper + const getImageSrc = useCallback( + (image) => { + if (failedImages[image.id]) { + return "https://res.cloudinary.com/dbnfkkfov/image/upload/v1759606221/WhatsApp_Image_2025-10-04_at_20.38.01_n5yqjt.jpg"; + } + return image.src; + }, + [failedImages], + ); + + const handleImageError = (id) => { + setFailedImages((prev) => ({ ...prev, [id]: true })); + }; + + // Lightbox Controls + const openLightbox = (index) => { + setLightboxIndex(index); + document.body.style.overflow = "hidden"; + }; + + const closeLightbox = () => { + setLightboxIndex(null); + document.body.style.overflow = "auto"; + }; + + const nextLightbox = useCallback(() => { + if (lightboxIndex === null || galleryImages.length === 0) return; + setLightboxIndex((prev) => (prev + 1) % galleryImages.length); + }, [lightboxIndex, galleryImages.length]); + + const prevLightbox = useCallback(() => { + if (lightboxIndex === null || galleryImages.length === 0) return; + setLightboxIndex((prev) => + prev === 0 ? galleryImages.length - 1 : prev - 1, + ); + }, [lightboxIndex, galleryImages.length]); + + useEffect(() => { + const handleKeyDown = (e) => { + if (lightboxIndex === null) return; + if (e.key === "Escape") closeLightbox(); + if (e.key === "ArrowRight") nextLightbox(); + if (e.key === "ArrowLeft") prevLightbox(); + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [lightboxIndex, nextLightbox, prevLightbox]); return ( -
- {/* Hero Banner Carousel */} -
- {/* Carousel Slides */} +
+ {/* Clean Large Hero Photo (Textless, clearly visible like Achievement section) */} +
- {images.map((image, index) => ( + {heroSlides.map((slide, index) => (
{image.alt} handleImageError(slide.id)} + className="w-full h-full object-cover transition-transform duration-[8000ms] ease-out scale-105" />
))} - {/* Carousel Controls */} -
- {images.map((_, index) => ( - + +
+ {heroSlides.map((_, index) => ( +
+ +
- {/* Gallery Content */} + {/* Main Gallery Container */}
- {/* Year Filters and Description Section */} -
-
+ {/* Header & Controls Section */} +
+ {/* Title & Description Header */} +
-

+

Gallery

-
- {years.map((year) => ( - setSelectedYear(year)} - /> - ))} -
-

+

Step into our visual storybook — where every image captures a moment, every frame holds a memory, and every detail speaks of the - journey we’ve lived and the beauty we’ve created. Welcome to our - gallery, a celebration of experiences brought to life through the - lens. + journey we’ve lived and the beauty we’ve created.

-
- {/* Gallery Grid */} -
- {galleryImages.map((image) => ( - - ))} + {/* Clean Controls Bar (Filter Pills) */} +
+ {/* Year Filters */} +
+ {years.map((year) => { + const isSelected = selectedYear === year; + const label = + year === "all" + ? "All" + : typeof year === "string" + ? year.charAt(0).toUpperCase() + year.slice(1) + : String(year); + return ( + + ); + })} +
+
- {/* No Images Message */} - {galleryImages.length === 0 && ( + {/* Gallery Grid - Fixed to 3 per row on desktop */} + {galleryImages.length > 0 ? ( +
+ {galleryImages.map((image, index) => { + const imgSrc = getImageSrc(image); + + return ( +
openLightbox(index)} + className="group relative cursor-pointer overflow-hidden rounded-2xl bg-gray-100 dark:bg-slate-800 shadow-sm hover:shadow-xl transition-all duration-300 hover:-translate-y-1.5 aspect-[4/3] w-full border border-gray-200/80 dark:border-slate-700/60" + > + {image.alt handleImageError(image.id)} + loading="lazy" + className="w-full h-full object-cover transition-transform duration-500 ease-out group-hover:scale-105" + /> + + {/* Subtle Hover Overlay */} +
+
+ +
+
+
+ ); + })} +
+ ) : (
-

+

No images found for selected year.

)}
+ + {/* Clean Interactive Lightbox Modal */} + {lightboxIndex !== null && galleryImages[lightboxIndex] && ( +
+ {/* Header */} +
e.stopPropagation()} + > +
+ {lightboxIndex + 1} of {galleryImages.length} +
+ + +
+ + {/* Lightbox Main Photo */} +
e.stopPropagation()} + > + + +
+ {`Gallery +
+ + +
+ + {/* Footer */} +
+ Press Esc to exit +
+
+ )}
); }