Initial commit of project structure
This commit is contained in:
179
Pottery-website/components/GallerySection.tsx
Normal file
179
Pottery-website/components/GallerySection.tsx
Normal file
@@ -0,0 +1,179 @@
|
||||
import React, { useState } from 'react';
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
import { GALLERY_IMAGES } from '../constants';
|
||||
|
||||
interface GalleryImage {
|
||||
src: string;
|
||||
likes: number;
|
||||
comments: number;
|
||||
caption: string;
|
||||
}
|
||||
|
||||
const GallerySection: React.FC = () => {
|
||||
const [selectedImage, setSelectedImage] = useState<GalleryImage | null>(null);
|
||||
|
||||
// Double the images for seamless infinite scroll
|
||||
const duplicatedImages = [...GALLERY_IMAGES, ...GALLERY_IMAGES] as GalleryImage[];
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="py-20 bg-white dark:bg-background-dark overflow-hidden">
|
||||
<div className="max-w-[1920px] mx-auto px-4">
|
||||
<motion.div
|
||||
className="flex justify-between items-center mb-8 px-2"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.6 }}
|
||||
>
|
||||
<div className="flex items-center gap-4">
|
||||
<div className="w-12 h-12 rounded-full bg-gradient-to-br from-purple-500 via-pink-500 to-orange-400 p-[2px]">
|
||||
<div className="w-full h-full rounded-full bg-white dark:bg-background-dark flex items-center justify-center">
|
||||
<span className="font-display text-lg">H</span>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-display text-xl text-text-main dark:text-white">@hotchpotsh_ceramics</h4>
|
||||
<p className="text-xs text-text-muted">24.8k followers</p>
|
||||
</div>
|
||||
</div>
|
||||
<a className="px-6 py-2 border border-text-main dark:border-white text-xs uppercase tracking-widest text-text-main dark:text-white hover:bg-text-main hover:text-white dark:hover:bg-white dark:hover:text-black transition-all duration-300 rounded-full" href="#">
|
||||
Follow
|
||||
</a>
|
||||
</motion.div>
|
||||
|
||||
{/* Infinite Carousel */}
|
||||
<div className="relative group overflow-hidden">
|
||||
<style>{`
|
||||
@keyframes marquee {
|
||||
0% { transform: translateX(0); }
|
||||
100% { transform: translateX(-${GALLERY_IMAGES.length * 304}px); }
|
||||
}
|
||||
.animate-marquee {
|
||||
animation: marquee 40s linear infinite;
|
||||
}
|
||||
.animate-marquee:hover {
|
||||
animation-play-state: paused;
|
||||
}
|
||||
`}</style>
|
||||
<div className="flex gap-4 animate-marquee w-max py-4">
|
||||
{duplicatedImages.map((img, idx) => (
|
||||
<motion.div
|
||||
key={idx}
|
||||
className="relative flex-shrink-0 w-72 h-72 overflow-hidden cursor-pointer rounded-lg"
|
||||
whileHover={{ scale: 1.02 }}
|
||||
onClick={() => setSelectedImage(img)}
|
||||
>
|
||||
<img
|
||||
alt={img.caption}
|
||||
className="w-full h-full object-cover"
|
||||
src={img.src}
|
||||
/>
|
||||
{/* Instagram-style hover overlay */}
|
||||
<motion.div
|
||||
className="absolute inset-0 bg-black/50 flex items-center justify-center gap-8 text-white"
|
||||
initial={{ opacity: 0 }}
|
||||
whileHover={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined" style={{ fontVariationSettings: "'FILL' 1" }}>favorite</span>
|
||||
<span className="font-bold">{img.likes.toLocaleString()}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="material-symbols-outlined">chat_bubble</span>
|
||||
<span className="font-bold">{img.comments}</span>
|
||||
</div>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* Lightbox Modal */}
|
||||
<AnimatePresence>
|
||||
{
|
||||
selectedImage && (
|
||||
<motion.div
|
||||
className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
onClick={() => setSelectedImage(null)}
|
||||
>
|
||||
<motion.div
|
||||
className="relative max-w-4xl w-full bg-white dark:bg-stone-900 rounded-xl overflow-hidden flex flex-col md:flex-row"
|
||||
initial={{ scale: 0.9, opacity: 0 }}
|
||||
animate={{ scale: 1, opacity: 1 }}
|
||||
exit={{ scale: 0.9, opacity: 0 }}
|
||||
transition={{ type: 'spring', damping: 25, stiffness: 300 }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* Image */}
|
||||
<div className="md:w-2/3 aspect-square md:aspect-auto">
|
||||
<img
|
||||
src={selectedImage.src}
|
||||
alt={selectedImage.caption}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Side panel */}
|
||||
<div className="md:w-1/3 p-6 flex flex-col">
|
||||
{/* Header */}
|
||||
<div className="flex items-center gap-3 pb-4 border-b border-stone-200 dark:border-stone-700">
|
||||
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-500 via-pink-500 to-orange-400 p-[2px]">
|
||||
<div className="w-full h-full rounded-full bg-white dark:bg-stone-900 flex items-center justify-center">
|
||||
<span className="font-display text-sm">H</span>
|
||||
</div>
|
||||
</div>
|
||||
<span className="font-bold text-sm text-text-main dark:text-white">hotchpotsh_ceramics</span>
|
||||
</div>
|
||||
|
||||
{/* Caption */}
|
||||
<div className="flex-1 py-4">
|
||||
<p className="text-sm text-text-main dark:text-white">
|
||||
<span className="font-bold">hotchpotsh_ceramics</span> {selectedImage.caption}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="border-t border-stone-200 dark:border-stone-700 pt-4">
|
||||
<div className="flex gap-4 mb-4">
|
||||
<button className="hover:scale-110 transition-transform">
|
||||
<span className="material-symbols-outlined text-2xl text-text-main dark:text-white" style={{ fontVariationSettings: "'FILL' 1" }}>favorite</span>
|
||||
</button>
|
||||
<button className="hover:scale-110 transition-transform">
|
||||
<span className="material-symbols-outlined text-2xl text-text-main dark:text-white">chat_bubble</span>
|
||||
</button>
|
||||
<button className="hover:scale-110 transition-transform">
|
||||
<span className="material-symbols-outlined text-2xl text-text-main dark:text-white">send</span>
|
||||
</button>
|
||||
<button className="hover:scale-110 transition-transform ml-auto">
|
||||
<span className="material-symbols-outlined text-2xl text-text-main dark:text-white">bookmark</span>
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-sm font-bold text-text-main dark:text-white">{selectedImage.likes.toLocaleString()} likes</p>
|
||||
<p className="text-xs text-text-muted mt-1">{selectedImage.comments} comments</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Close button */}
|
||||
<button
|
||||
className="absolute top-4 right-4 text-white bg-black/50 rounded-full p-2 hover:bg-black/70 transition-colors"
|
||||
onClick={() => setSelectedImage(null)}
|
||||
>
|
||||
<span className="material-symbols-outlined">close</span>
|
||||
</button>
|
||||
</motion.div>
|
||||
</motion.div>
|
||||
)
|
||||
}
|
||||
</AnimatePresence >
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default GallerySection;
|
||||
Reference in New Issue
Block a user