Files
moygroup/app/[lang]/galeri/GaleriClient.tsx
T
2026-06-03 16:13:15 +03:00

141 lines
6.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { X, ZoomIn } from "lucide-react";
import { Badge } from "@/app/components/ui/badge";
export default function GaleriClient({ lang, dict }: { lang: string; dict: any }) {
const t = dict.gallery;
const CATEGORIES = [t.all, t.venues, "Beach", "Bungalov", "Kite Surf", "Hotel"] as const;
type Category = string;
const IMAGES = [
{ src: "https://images.unsplash.com/photo-1517248135467-4c7edcad34c4?auto=format&fit=crop&q=80&w=800", cat: t.venues, title: "Akşam Servisi" },
{ src: "https://images.unsplash.com/photo-1507525428034-b723cf961d3e?auto=format&fit=crop&q=80&w=800", cat: "Beach", title: "Moy Beach Alaçatı" },
{ src: "https://images.unsplash.com/photo-1449844908441-8829872d2607?auto=format&fit=crop&q=80&w=800", cat: "Bungalov", title: "Doğada Konaklama" },
{ src: "https://images.unsplash.com/photo-1526685514088-290076a0d426?auto=format&fit=crop&q=80&w=800", cat: "Kite Surf", title: "Gökova Körfezi" },
{ src: "https://images.unsplash.com/photo-1566073771259-6a8506099945?auto=format&fit=crop&q=80&w=800", cat: "Hotel", title: "Kite Beach Hotel" },
{ src: "https://images.unsplash.com/photo-1519046904884-53103b34b206?auto=format&fit=crop&q=80&w=800", cat: "Beach", title: "Gün Batımı" },
{ src: "https://images.unsplash.com/photo-1571003123894-1f0594d2b5d9?auto=format&fit=crop&q=80&w=800", cat: "Hotel", title: "Oda Manzarası" },
{ src: "https://images.unsplash.com/photo-1614214227038-f9d9cf98b1ec?auto=format&fit=crop&q=80&w=800", cat: "Kite Surf", title: "Sabah Seansı" },
{ src: "https://images.unsplash.com/photo-1490197415175-074fd86b1fcc?auto=format&fit=crop&q=80&w=800", cat: t.venues, title: "Taze Deniz Ürünleri" },
];
const [active, setActive] = useState<Category>(t.all);
const [lightbox, setLightbox] = useState<{src:string, cat:string, title:string} | null>(null);
const filtered = active === t.all ? IMAGES : IMAGES.filter((img) => img.cat === active);
return (
<div className="min-h-screen bg-[var(--color-moy-dark)]">
{/* Hero */}
<div className="pt-40 pb-16 text-center px-6">
<p className="text-[10px] uppercase tracking-[0.28em] text-[var(--color-moy-gold)] mb-4">{t.eyebrow}</p>
<h1 className="text-5xl md:text-6xl font-serif text-white mb-6">{t.title}</h1>
<p className="text-gray-400 text-base max-w-md mx-auto leading-relaxed">
{t.subtitle}
</p>
</div>
{/* Filter pills */}
<div className="flex flex-wrap justify-center gap-3 px-6 mb-14">
{CATEGORIES.map((cat) => (
<button
key={cat}
onClick={() => setActive(cat)}
className={[
"px-5 py-2 text-[10px] uppercase tracking-[0.16em] font-medium transition-all duration-200",
active === cat
? "bg-[var(--color-moy-gold)] text-[var(--color-moy-dark)]"
: "border border-white/15 text-gray-400 hover:border-[var(--color-moy-gold)]/50 hover:text-[var(--color-moy-gold)]",
].join(" ")}
>
{cat}
</button>
))}
</div>
{/* Grid */}
<div className="max-w-7xl mx-auto px-4 sm:px-6 pb-28">
<motion.div
layout
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4"
>
<AnimatePresence mode="popLayout">
{filtered.map((img) => (
<motion.div
key={img.src}
layout
initial={{ opacity: 0, scale: 0.94 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.94 }}
transition={{ duration: 0.35, ease: [0.16, 1, 0.3, 1] }}
className="group relative aspect-square cursor-pointer overflow-hidden"
onClick={() => setLightbox(img)}
>
<img
src={img.src}
alt={img.title}
className="w-full h-full object-cover transition-transform duration-700 group-hover:scale-110"
/>
<div className="absolute inset-0 bg-[var(--color-moy-dark)]/0 group-hover:bg-[var(--color-moy-dark)]/50 transition-all duration-300 flex flex-col items-center justify-center gap-3">
<ZoomIn
size={28}
className="text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300 translate-y-2 group-hover:translate-y-0"
/>
<span className="text-white text-sm font-serif opacity-0 group-hover:opacity-100 transition-opacity duration-300">
{img.title}
</span>
</div>
<Badge
variant="dark"
className="absolute top-3 left-3 opacity-0 group-hover:opacity-100 transition-opacity duration-300"
>
{img.cat}
</Badge>
</motion.div>
))}
</AnimatePresence>
</motion.div>
</div>
{/* Lightbox */}
<AnimatePresence>
{lightbox && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[300] bg-black/90 flex items-center justify-center p-6"
onClick={() => setLightbox(null)}
>
<button
className="absolute top-6 right-6 text-white/60 hover:text-white transition-colors"
onClick={() => setLightbox(null)}
>
<X size={28} />
</button>
<motion.div
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
transition={{ duration: 0.3, ease: [0.16, 1, 0.3, 1] }}
className="max-w-4xl w-full"
onClick={(e) => e.stopPropagation()}
>
<img
src={lightbox.src}
alt={lightbox.title}
className="w-full max-h-[80vh] object-contain"
/>
<p className="text-center text-white font-serif text-xl mt-4">{lightbox.title}</p>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</div>
);
}