anatolian2/components/experiences/PhotoGallery.tsx
Temmuz Aslan 591d878ac6 Initial commit: The Anatolian Edit website
Next.js 14 website with standalone output configured for Docker deployment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 22:34:25 +03:00

119 lines
3.9 KiB
TypeScript
Raw Permalink 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 Image from "next/image";
import { motion, AnimatePresence } from "framer-motion";
const galleryImages = [
{
src: "/images/hero_main.jpg",
alt: "Friends walking along a sun-drenched boulevard on Istanbul's Asian side",
},
{
src: "/images/manifesto_coastline.jpg",
alt: "Locals relaxing on the waterfront with the Marmara Sea and Princes' Islands beyond",
},
{
src: "/images/first_light.jpg",
alt: "Traditional Turkish breakfast spread with eggs, cheese, simit, and tea",
},
{
src: "/images/the_other_side.jpg",
alt: "Aerial view of Fenerbahçe Park, Kalamış Marina, and the Asian side coastline",
},
];
export function PhotoGallery() {
const [lightboxIndex, setLightboxIndex] = useState<number | null>(null);
return (
<section className="py-16 md:py-24 section-padding">
<div className="max-w-7xl mx-auto">
<h2 className="font-display text-3xl md:text-4xl font-bold text-deep-nazar mb-12 text-center">
Through the Lens
</h2>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
{galleryImages.map((img, i) => (
<motion.button
key={i}
className={`relative overflow-hidden rounded-2xl ${
i === 0 ? "col-span-2 row-span-2 aspect-square" : "aspect-[4/3]"
}`}
whileHover={{ scale: 0.98 }}
onClick={() => setLightboxIndex(i)}
>
<Image
src={img.src}
alt={img.alt}
fill
className="object-cover hover:scale-110 transition-transform duration-700"
sizes={i === 0 ? "(max-width: 768px) 100vw, 66vw" : "(max-width: 768px) 50vw, 33vw"}
/>
</motion.button>
))}
</div>
</div>
{/* Lightbox */}
<AnimatePresence>
{lightboxIndex !== null && (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-50 bg-black/90 flex items-center justify-center p-4"
onClick={() => setLightboxIndex(null)}
>
<button
className="absolute top-4 right-4 text-white/70 hover:text-white text-3xl z-10"
onClick={() => setLightboxIndex(null)}
aria-label="Close lightbox"
>
&times;
</button>
<button
className="absolute left-4 top-1/2 -translate-y-1/2 text-white/70 hover:text-white text-3xl z-10"
onClick={(e) => {
e.stopPropagation();
setLightboxIndex((lightboxIndex - 1 + galleryImages.length) % galleryImages.length);
}}
aria-label="Previous image"
>
&#8249;
</button>
<button
className="absolute right-4 top-1/2 -translate-y-1/2 text-white/70 hover:text-white text-3xl z-10"
onClick={(e) => {
e.stopPropagation();
setLightboxIndex((lightboxIndex + 1) % galleryImages.length);
}}
aria-label="Next image"
>
&#8250;
</button>
<motion.div
key={lightboxIndex}
initial={{ scale: 0.9, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.9, opacity: 0 }}
className="relative w-full max-w-4xl aspect-[3/2]"
onClick={(e) => e.stopPropagation()}
>
<Image
src={galleryImages[lightboxIndex].src}
alt={galleryImages[lightboxIndex].alt}
fill
className="object-contain"
sizes="100vw"
/>
</motion.div>
</motion.div>
)}
</AnimatePresence>
</section>
);
}