DigitalDB / frontend /src /components /ImageGallery.js
Mr-Thop's picture
Add files
3db086d
Raw
History Blame Contribute Delete
6.05 kB
import React, { useState } from 'react';
import { FaChevronLeft, FaChevronRight, FaTimes, FaExpand } from 'react-icons/fa';
import { getImageUrl, getPlaceholderImage } from '../utils/imageUtils';
const ImageGallery = ({ images = [], title = "Gallery" }) => {
const [currentIndex, setCurrentIndex] = useState(0);
const [isModalOpen, setIsModalOpen] = useState(false);
if (!images || images.length === 0) {
return (
<div className="bg-gray-100 dark:bg-slate-700 rounded-lg p-8 text-center">
<div className="text-4xl text-gray-400 mb-2">📷</div>
<p className="text-gray-600 dark:text-gray-400">No images available</p>
</div>
);
}
const nextImage = () => {
setCurrentIndex((prev) => (prev + 1) % images.length);
};
const prevImage = () => {
setCurrentIndex((prev) => (prev - 1 + images.length) % images.length);
};
const openModal = (index) => {
setCurrentIndex(index);
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
};
return (
<div className="space-y-4">
{/* Main Image */}
<div className="relative bg-white dark:bg-slate-800 rounded-xl shadow-lg overflow-hidden">
<div className="aspect-video relative">
<img
src={getImageUrl(images[currentIndex]?.file_url, images[currentIndex]?.media_id, images[currentIndex]?.plant_name) || getPlaceholderImage(600, 400, 'Plant Image')}
alt={`${title} ${currentIndex + 1}`}
className="w-full h-full object-cover cursor-pointer"
onClick={() => openModal(currentIndex)}
onError={(e) => {
e.target.src = getPlaceholderImage(600, 400, 'Image Not Available');
}}
/>
{/* Expand Button */}
<button
onClick={() => openModal(currentIndex)}
className="absolute top-4 right-4 bg-black bg-opacity-50 text-white p-2 rounded-full hover:bg-opacity-70 transition-all"
>
<FaExpand />
</button>
{/* Navigation Arrows */}
{images.length > 1 && (
<>
<button
onClick={prevImage}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white p-3 rounded-full hover:bg-opacity-70 transition-all"
>
<FaChevronLeft />
</button>
<button
onClick={nextImage}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white p-3 rounded-full hover:bg-opacity-70 transition-all"
>
<FaChevronRight />
</button>
</>
)}
{/* Image Counter */}
{images.length > 1 && (
<div className="absolute bottom-4 left-4 bg-black bg-opacity-50 text-white px-3 py-1 rounded-full text-sm">
{currentIndex + 1} / {images.length}
</div>
)}
</div>
</div>
{/* Thumbnail Strip */}
{images.length > 1 && (
<div className="flex space-x-2 overflow-x-auto pb-2">
{images.map((image, index) => (
<button
key={index}
onClick={() => setCurrentIndex(index)}
className={`flex-shrink-0 w-16 h-16 rounded-lg overflow-hidden border-2 transition-all ${
index === currentIndex
? 'border-emerald-500 ring-2 ring-emerald-200'
: 'border-gray-300 dark:border-gray-600 hover:border-emerald-400'
}`}
>
<img
src={getImageUrl(image.file_url, image.media_id, image.plant_name)}
alt={`Thumbnail ${index + 1}`}
className="w-full h-full object-cover"
onError={(e) => {
e.target.src = getPlaceholderImage(64, 64, '');
}}
/>
</button>
))}
</div>
)}
{/* Fullscreen Modal */}
{isModalOpen && (
<div className="fixed inset-0 bg-black bg-opacity-90 z-50 flex items-center justify-center">
<div className="relative max-w-7xl max-h-full p-4">
<img
src={getImageUrl(images[currentIndex]?.file_url, images[currentIndex]?.media_id, images[currentIndex]?.plant_name)}
alt={`${title} ${currentIndex + 1}`}
className="max-w-full max-h-full object-contain"
/>
{/* Close Button */}
<button
onClick={closeModal}
className="absolute top-4 right-4 bg-black bg-opacity-50 text-white p-3 rounded-full hover:bg-opacity-70 text-xl"
>
<FaTimes />
</button>
{/* Modal Navigation */}
{images.length > 1 && (
<>
<button
onClick={prevImage}
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white p-4 rounded-full hover:bg-opacity-70 text-xl"
>
<FaChevronLeft />
</button>
<button
onClick={nextImage}
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-black bg-opacity-50 text-white p-4 rounded-full hover:bg-opacity-70 text-xl"
>
<FaChevronRight />
</button>
</>
)}
{/* Modal Counter */}
<div className="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-black bg-opacity-50 text-white px-4 py-2 rounded-full">
{currentIndex + 1} / {images.length}
</div>
</div>
</div>
)}
</div>
);
};
export default ImageGallery;