Files
moybeach-main/components/Gallery.tsx
T
2026-06-03 17:31:50 +03:00

137 lines
6.1 KiB
TypeScript

"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { X, ZoomIn } from "lucide-react";
import Image from "next/image";
const photos = [
{ id: 1, categoryKey: "beach", url: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&q=80&w=1200" },
{ id: 2, categoryKey: "rooms", url: "https://images.unsplash.com/photo-1611892440504-42a792e24d32?auto=format&fit=crop&q=80&w=1200" },
{ id: 3, categoryKey: "restaurant", url: "https://images.unsplash.com/photo-1414235077428-338989a2e8c0?auto=format&fit=crop&q=80&w=1200" },
{ id: 4, categoryKey: "beach", url: "https://images.unsplash.com/photo-1519046904884-53103b34b206?auto=format&fit=crop&q=80&w=1200" },
{ id: 5, categoryKey: "events", url: "https://images.unsplash.com/photo-1511285560929-80b456fea0bc?auto=format&fit=crop&q=80&w=1200" },
{ id: 6, categoryKey: "restaurant", url: "https://images.unsplash.com/photo-1555396273-367ea4eb4db5?auto=format&fit=crop&q=80&w=1200" },
];
export default function Gallery({ dict }: { dict: any }) {
const categories = [
{ key: "all", label: dict.gallery.categories.all },
{ key: "beach", label: dict.gallery.categories.beach },
{ key: "restaurant", label: dict.gallery.categories.restaurant },
{ key: "rooms", label: dict.gallery.categories.rooms },
{ key: "events", label: dict.gallery.categories.events }
];
const [activeCategoryKey, setActiveCategoryKey] = useState("all");
const [selectedImage, setSelectedImage] = useState<string | null>(null);
const filteredPhotos =
activeCategoryKey === "all"
? photos
: photos.filter((p) => p.categoryKey === activeCategoryKey);
return (
<section id="gallery" className="py-24 bg-sand-light text-sea-dark">
<div className="container mx-auto px-6 max-w-7xl">
<div className="text-center mb-12">
<div className="flex items-center justify-center gap-3 mb-4">
<span className="w-8 h-px bg-coral" />
<h2 className="text-sm font-bold tracking-widest uppercase text-coral">{dict.gallery.title}</h2>
<span className="w-8 h-px bg-coral" />
</div>
<h3 className="text-4xl md:text-5xl font-serif mb-10">{dict.gallery.heading}</h3>
{/* Category filters */}
<div className="flex flex-wrap justify-center gap-3 mb-12">
{categories.map((cat) => (
<button
key={cat.key}
onClick={() => setActiveCategoryKey(cat.key)}
className={`px-5 py-2 rounded-full text-xs tracking-widest uppercase font-medium transition-all duration-300 ${
activeCategoryKey === cat.key
? "bg-sea-dark text-white shadow-md"
: "bg-white text-sea-dark border border-sand-dark/30 hover:border-sea-dark hover:bg-sea-dark/5"
}`}
>
{cat.label}
</button>
))}
</div>
</div>
<motion.div layout className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
<AnimatePresence mode="popLayout">
{filteredPhotos.map((photo) => (
<motion.div
key={photo.id}
layout
initial={{ opacity: 0, scale: 0.92 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.92 }}
transition={{ duration: 0.3 }}
className="relative h-72 cursor-pointer overflow-hidden rounded-2xl group shadow-sm hover:shadow-lg hover:shadow-sea-dark/10 transition-shadow duration-500"
onClick={() => setSelectedImage(photo.url)}
>
<Image
src={photo.url}
alt={dict.gallery.categories[photo.categoryKey]}
fill
className="object-cover transform group-hover:scale-108 transition-transform duration-700"
sizes="(max-width: 768px) 100vw, (max-width: 1024px) 50vw, 33vw"
style={{ transform: "scale(1)", transition: "transform 700ms" }}
/>
{/* Hover overlay */}
<div className="absolute inset-0 bg-sea-dark/40 opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-10 flex items-center justify-center">
<div className="flex flex-col items-center gap-2 text-white">
<ZoomIn size={28} />
<span className="text-[10px] uppercase tracking-[0.25em]">{dict.gallery.categories[photo.categoryKey]}</span>
</div>
</div>
</motion.div>
))}
</AnimatePresence>
</motion.div>
</div>
{/* Lightbox */}
<AnimatePresence>
{selectedImage && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[100] bg-black/92 flex items-center justify-center p-4"
onClick={() => setSelectedImage(null)}
>
<button
className="absolute top-6 right-6 text-white/70 hover:text-white transition-colors bg-white/10 hover:bg-white/20 p-2.5 rounded-full backdrop-blur-sm"
onClick={() => setSelectedImage(null)}
aria-label="Kapat"
>
<X size={20} />
</button>
<motion.div
initial={{ scale: 0.88, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.88, opacity: 0 }}
transition={{ duration: 0.25, ease: [0.22, 1, 0.36, 1] }}
className="relative max-w-4xl max-h-[88vh] w-full h-full"
onClick={(e) => e.stopPropagation()}
>
<Image
src={selectedImage}
alt="Büyütülmüş Görsel"
fill
className="object-contain rounded-lg"
sizes="100vw"
/>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</section>
);
}