import React, { memo, useState, useEffect, useRef } from "react"; import Author from "./Author"; import ImportButton from "./ImportButton"; import DownloadDropdown from "./DownloadDropdown"; import PreviewButton from "./PreviewButton"; import { useGenerator } from "../../context/GeneratorContext"; const EyeIcon = ({ className = "w-5 h-5" }) => ( ); const HeartIcon = ({ filled, className = "w-5 h-5" }) => ( ); function ImageCard({ imageSrc, imageAlt = "Image", previewUrl, author = {}, importUrl, downloadOptions = [], loading = "lazy", providerId, imageId, imageData = {}, providerBadge, variant = "grid", index = 0, gifStillUrl, // Still version of GIF (for Giphy) gifAnimatedUrl, // Animated version of GIF (for Giphy) }) { const { url: authorUrl, avatar, name } = author; const generator = useGenerator(); const selectionMode = generator?.selectionMode ?? false; const isSelected = generator?.isSelected(providerId, imageId) ?? false; const isFavorite = generator?.isFavorite(providerId, imageId) ?? false; const toggleSelection = generator?.toggleSelection; const toggleFavorite = generator?.toggleFavorite; const setPreviewImage = generator?.setPreviewImage; const [imageLoaded, setImageLoaded] = useState(false); const [imageError, setImageError] = useState(false); const [isHovered, setIsHovered] = useState(false); // Determine which image source to use (animated on hover for GIFs, otherwise normal) const currentImageSrc = (gifStillUrl && gifAnimatedUrl) ? (isHovered ? gifAnimatedUrl : gifStillUrl) : imageSrc; const previewImageList = generator?.previewImageList; const setPreviewImageList = generator?.setPreviewImageList; // Register this card's data in the preview list on mount/update const cardData = useRef(null); cardData.current = { imageSrc, imageAlt, previewUrl, author, importUrl, downloadOptions, providerId, imageId, gifStillUrl, gifAnimatedUrl, providerBadge, index }; useEffect(() => { const handleNav = (e) => { const { direction, currentIndex } = e.detail; const list = generator?.previewImageList; if (!list || list.length === 0) return; let nextIdx; if (direction === "next") nextIdx = currentIndex + 1 >= list.length ? 0 : currentIndex + 1; else nextIdx = currentIndex - 1 < 0 ? list.length - 1 : currentIndex - 1; const nextImage = list[nextIdx]; if (nextImage && generator?.setPreviewImage) generator.setPreviewImage({ ...nextImage, index: nextIdx }); }; window.addEventListener("previewNavigate", handleNav); return () => window.removeEventListener("previewNavigate", handleNav); }, [generator]); const handleQuickPreview = (e) => { e.preventDefault(); e.stopPropagation(); if (!setPreviewImage) return; // Use data from previewImageList (which has full-size URLs) if available const list = generator?.previewImageList; if (list && list.length > 0 && index != null) { const listItem = list[index]; if (listItem) { setPreviewImage({ ...listItem, index }); return; } } // Fallback to card props setPreviewImage({ imageSrc, imageAlt, previewUrl, author, importUrl, downloadOptions, providerId, imageId, gifStillUrl, gifAnimatedUrl, providerBadge, index }); }; const handleFavorite = (e) => { e.preventDefault(); e.stopPropagation(); if (toggleFavorite) toggleFavorite(providerId, imageId, { imageSrc, imageAlt, author, importUrl, downloadOptions, previewUrl }); }; const handleToggleSelect = (e) => { e.preventDefault(); e.stopPropagation(); if (toggleSelection) toggleSelection(providerId, imageId, { importUrl, imageSrc, imageAlt, author, previewUrl }); }; const thumbnail = (
{imageAlt}