| 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>
|
|
|
| {}
|
| {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>
|
| )}
|
|
|
| {}
|
| {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; |