sky-and-soil/src/components/PropertyGallery.tsx
2025-12-05 23:20:44 +05:30

313 lines
7.8 KiB
TypeScript

"use client";
import { useState } from "react";
import Image from "next/image";
interface PropertyGalleryProps {
images: string[];
title: string;
}
export default function PropertyGallery({ images, title }: PropertyGalleryProps) {
const [activeImage, setActiveImage] = useState(0);
const [showLightbox, setShowLightbox] = useState(false);
const [lightboxIndex, setLightboxIndex] = useState(0);
const openLightbox = (index: number) => {
setLightboxIndex(index);
setShowLightbox(true);
document.body.style.overflow = 'hidden';
};
const closeLightbox = () => {
setShowLightbox(false);
document.body.style.overflow = 'unset';
};
// Ensure we have at least 5 images for the gallery (1 big + 4 small)
const displayImages = [...images];
while (displayImages.length < 5) {
displayImages.push("/assets/images/image.png");
}
const nextImage = () => {
setLightboxIndex((prev) => (prev + 1) % displayImages.length);
};
const prevImage = () => {
setLightboxIndex((prev) => (prev - 1 + displayImages.length) % displayImages.length);
};
return (
<>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
<div className="md:col-span-2 relative h-[500px] rounded-2xl overflow-hidden group cursor-pointer" onClick={() => openLightbox(activeImage)}>
<Image
src={displayImages[activeImage]}
alt={title}
fill
className="object-cover transition-transform duration-300 group-hover:scale-105"
/>
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-colors duration-300" />
<div className="absolute bottom-4 right-4 bg-black/70 text-white px-3 py-1.5 rounded-lg text-sm opacity-0 group-hover:opacity-100 transition-opacity">
Click to enlarge
</div>
</div>
<div className="grid grid-cols-2 grid-rows-2 gap-4 h-[500px]">
{displayImages.slice(0, 3).map((img, idx) => (
<div
key={idx}
onClick={() => setActiveImage(idx)}
className={`relative w-full h-full rounded-xl overflow-hidden cursor-pointer transition-all duration-300 ${activeImage === idx ? 'ring-4 ring-primary scale-95' : 'hover:scale-95'
}`}
>
<Image src={img} alt={`View ${idx + 1}`} fill className="object-cover" />
</div>
))}
{/* View All Photos Button (4th slot) */}
<div
onClick={() => openLightbox(0)}
className="relative w-full h-full rounded-xl overflow-hidden cursor-pointer group"
>
<Image
src={displayImages[3]}
alt="View all photos"
fill
className="object-cover"
/>
<div className="absolute inset-0 bg-black/60 group-hover:bg-black/70 transition-colors flex flex-col items-center justify-center text-white">
<svg className="w-10 h-10 mb-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className="font-semibold text-lg">View All Photos</span>
<span className="text-sm opacity-90">({displayImages.length} images)</span>
</div>
</div>
</div>
</div>
{/* Lightbox Modal */}
{showLightbox && (
<div className="fixed inset-0 z-50 bg-black/95 flex items-center justify-center">
{/* Close Button */}
<button
onClick={closeLightbox}
className="absolute top-4 right-4 text-white hover:text-gray-300 transition-colors z-10"
aria-label="Close gallery"
>
<svg className="w-10 h-10" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
{/* Image Counter */}
<div className="absolute top-4 left-1/2 -translate-x-1/2 text-white text-lg font-medium bg-black/50 px-4 py-2 rounded-full">
{lightboxIndex + 1} / {displayImages.length}
</div>
{/* Previous Button */}
<button
onClick={prevImage}
className="absolute left-4 text-white hover:text-gray-300 transition-colors p-2 bg-black/50 rounded-full hover:bg-black/70"
aria-label="Previous image"
>
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
</svg>
</button>
{/* Main Image */}
<div className="relative w-full h-full max-w-6xl max-h-[90vh] mx-4">
<Image
src={displayImages[lightboxIndex]}
alt={`${title} - Image ${lightboxIndex + 1}`}
fill
className="object-contain"
/>
</div>
{/* Next Button */}
<button
onClick={nextImage}
className="absolute right-4 text-white hover:text-gray-300 transition-colors p-2 bg-black/50 rounded-full hover:bg-black/70"
aria-label="Next image"
>
<svg className="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
{/* Thumbnail Strip */}
<div className="absolute bottom-4 left-1/2 -translate-x-1/2 flex gap-2 overflow-x-auto max-w-[90vw] px-4 py-2 bg-black/50 rounded-lg hide-scrollbar">
{displayImages.map((img, idx) => (
<div
key={idx}
onClick={() => setLightboxIndex(idx)}
className={`relative w-20 h-20 flex-shrink-0 rounded-lg overflow-hidden cursor-pointer transition-all ${lightboxIndex === idx ? 'ring-4 ring-white scale-110' : 'opacity-60 hover:opacity-100'
}`}
>
<Image src={img} alt={`Thumbnail ${idx + 1}`} fill className="object-cover" />
</div>
))}
</div>
</div>
)}
</>
);
}