'use client' import { useState, useEffect } from 'react' import { createPortal } from 'react-dom' import Image from 'next/image' export default function ImageGallery({ images }: { images: string[] }) { // activeIdx = which thumbnail is highlighted in the strip const [activeIdx, setActiveIdx] = useState(0) // lightboxIdx = null means closed; a number = open at that image const [lightboxIdx, setLightboxIdx] = useState(null) // portal guard: document.body only available client-side const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) }, []) // Keyboard navigation for lightbox (← → Esc) useEffect(() => { if (lightboxIdx === null) return const handler = (e: KeyboardEvent) => { if (e.key === 'ArrowLeft') lbGo((lightboxIdx - 1 + images.length) % images.length) if (e.key === 'ArrowRight') lbGo((lightboxIdx + 1) % images.length) if (e.key === 'Escape') setLightboxIdx(null) } window.addEventListener('keydown', handler) return () => window.removeEventListener('keydown', handler) }, [lightboxIdx, images.length]) // eslint-disable-line react-hooks/exhaustive-deps if (!images.length) return null // Navigate lightbox AND keep strip highlight in sync const lbGo = (idx: number) => { setLightboxIdx(idx); setActiveIdx(idx) } // Strip-only prev/next (highlight moves, lightbox stays closed) const stripPrev = (e: React.MouseEvent) => { e.stopPropagation() setActiveIdx(i => (i - 1 + images.length) % images.length) } const stripNext = (e: React.MouseEvent) => { e.stopPropagation() setActiveIdx(i => (i + 1) % images.length) } // Lightbox arrow handlers const lbPrev = (e: React.MouseEvent) => { e.stopPropagation() if (lightboxIdx !== null) lbGo((lightboxIdx - 1 + images.length) % images.length) } const lbNext = (e: React.MouseEvent) => { e.stopPropagation() if (lightboxIdx !== null) lbGo((lightboxIdx + 1) % images.length) } // ── Lightbox portal ────────────────────────────────────────────────────── // Rendered via createPortal so it escapes the panel's z-50 stacking context. // Sized & positioned identically to the detail panel (w-96 h-full fixed right-0 top-0). const lightbox = lightboxIdx !== null && mounted ? createPortal( // Semi-transparent backdrop — clicking it closes the lightbox
setLightboxIdx(null)} > {/* Inner panel — same w-96 as the detail panel */}
e.stopPropagation()} > {/* Header */}
IMAGE {lightboxIdx + 1} / {images.length}
{/* Full-size image */}
{/* eslint-disable-next-line @next/next/no-img-element */} {`Lot
{/* Footer — arrows + dot indicators */} {images.length > 1 && (
{/* Dot indicators — click to jump */}
{images.map((_, i) => (
)}
, document.body ) : null // ── Thumbnail strip ────────────────────────────────────────────────────── return ( <>
LOT IMAGES
{/* Strip: ‹ [thumbnails] › */}
{images.length > 1 && ( )}
{images.map((src, i) => ( ))}
{images.length > 1 && ( )}
{/* Lightbox rendered at document.body via portal */} {lightbox} ) }