mirror of
https://github.com/Snigdha-OS/Snigdha-OS.github.io.git
synced 2025-09-06 12:45:18 +02:00
🚀 feat: add image zoom options
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo } from 'react';
|
||||||
import { motion } from 'framer-motion';
|
import { motion } from 'framer-motion';
|
||||||
import { Camera } from 'lucide-react';
|
import { Camera, X } from 'lucide-react';
|
||||||
import { GalleryImage } from '../components/gallery/GalleryImage';
|
import { GalleryImage } from '../components/gallery/GalleryImage';
|
||||||
import { CategoryFilter } from '../components/gallery/CategoryFilter';
|
import { CategoryFilter } from '../components/gallery/CategoryFilter';
|
||||||
import { galleryImages, categories } from '../data/gallery';
|
import { galleryImages, categories } from '../data/gallery';
|
||||||
|
|
||||||
export default function Gallery() {
|
export default function Gallery() {
|
||||||
const [selectedCategory, setSelectedCategory] = useState('All');
|
const [selectedCategory, setSelectedCategory] = useState('All');
|
||||||
|
const [zoomedImage, setZoomedImage] = useState(null);
|
||||||
|
|
||||||
const filteredImages = useMemo(() => {
|
const filteredImages = useMemo(() => {
|
||||||
return selectedCategory === 'All'
|
return selectedCategory === 'All'
|
||||||
@@ -15,32 +16,77 @@ export default function Gallery() {
|
|||||||
}, [selectedCategory]);
|
}, [selectedCategory]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="py-12">
|
<div className="py-12 bg-gradient-to-b from-white to-blue-50">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={{ opacity: 0, y: 20 }}
|
initial={{ opacity: 0, y: 20 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
|
transition={{ duration: 0.8 }}
|
||||||
className="text-center mb-12"
|
className="text-center mb-12"
|
||||||
>
|
>
|
||||||
<Camera className="h-12 w-12 text-cornflower-blue mx-auto mb-4" />
|
<Camera className="h-16 w-16 text-blue-600 mx-auto mb-6" />
|
||||||
<h1 className="text-4xl font-bold text-gray-900">Gallery</h1>
|
<h1 className="text-5xl font-extrabold text-gray-900">Gallery</h1>
|
||||||
<p className="mt-4 text-lg text-gray-600">
|
<p className="mt-4 text-lg text-gray-600 max-w-2xl mx-auto">
|
||||||
Explore the visual journey of Snigdha OS
|
Immerse yourself in the visual journey of <span className="text-blue-600">Snigdha OS</span>
|
||||||
</p>
|
</p>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
||||||
|
<motion.div
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 0.2, duration: 0.8 }}
|
||||||
|
>
|
||||||
<CategoryFilter
|
<CategoryFilter
|
||||||
categories={categories}
|
categories={categories}
|
||||||
selectedCategory={selectedCategory}
|
selectedCategory={selectedCategory}
|
||||||
onSelect={setSelectedCategory}
|
onSelect={setSelectedCategory}
|
||||||
/>
|
/>
|
||||||
|
</motion.div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<motion.div
|
||||||
|
className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8 mt-10"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
transition={{ delay: 0.4, duration: 0.8 }}
|
||||||
|
>
|
||||||
{filteredImages.map((image) => (
|
{filteredImages.map((image) => (
|
||||||
<GalleryImage key={image.src} {...image} />
|
<motion.div
|
||||||
|
key={image.src}
|
||||||
|
whileHover={{ scale: 1.05 }}
|
||||||
|
whileTap={{ scale: 0.95 }}
|
||||||
|
onClick={() => setZoomedImage(image.src)}
|
||||||
|
className="cursor-pointer"
|
||||||
|
>
|
||||||
|
<GalleryImage {...image} />
|
||||||
|
</motion.div>
|
||||||
))}
|
))}
|
||||||
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
{zoomedImage && (
|
||||||
|
<motion.div
|
||||||
|
className="fixed inset-0 bg-black bg-opacity-75 flex items-center justify-center z-50"
|
||||||
|
initial={{ opacity: 0 }}
|
||||||
|
animate={{ opacity: 1 }}
|
||||||
|
exit={{ opacity: 0 }}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
onClick={() => setZoomedImage(null)}
|
||||||
|
className="absolute top-4 right-4 text-white bg-black bg-opacity-50 rounded-full p-2 hover:bg-opacity-75 focus:outline-none"
|
||||||
|
>
|
||||||
|
<X className="h-6 w-6" />
|
||||||
|
</button>
|
||||||
|
<motion.img
|
||||||
|
src={zoomedImage}
|
||||||
|
alt="Zoomed"
|
||||||
|
className="max-w-full max-h-full rounded-lg shadow-lg"
|
||||||
|
initial={{ scale: 0.8 }}
|
||||||
|
animate={{ scale: 1 }}
|
||||||
|
exit={{ scale: 0.8 }}
|
||||||
|
transition={{ duration: 0.3 }}
|
||||||
|
/>
|
||||||
|
</motion.div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
Reference in New Issue
Block a user