feat: add project files
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
"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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user