import React, { useState, useCallback, useEffect } from 'react' const FALLBACK_MD = 'https://files.skinbase.org/default/missing_md.webp' const FALLBACK_LG = 'https://files.skinbase.org/default/missing_lg.webp' const FALLBACK_XL = 'https://files.skinbase.org/default/missing_xl.webp' export default function ArtworkHero({ artwork, presentMd, presentLg, presentXl, mediaWidth = null, mediaHeight = null, mediaKey = 'cover', onOpenViewer, hasPrev, hasNext, onPrev, onNext }) { const [isLoaded, setIsLoaded] = useState(false) const [mainImageMode, setMainImageMode] = useState('primary') const [previewImageMode, setPreviewImageMode] = useState('primary') const [showBackdrop, setShowBackdrop] = useState(true) const mdSource = presentMd?.url || artwork?.thumbs?.md?.url || null const lgSource = presentLg?.url || artwork?.thumbs?.lg?.url || null const xlSource = presentXl?.url || artwork?.thumbs?.xl?.url || null const md = mdSource || FALLBACK_MD const lg = lgSource || FALLBACK_LG const xl = xlSource || FALLBACK_XL const hasRealArtworkImage = Boolean(mdSource || lgSource || xlSource) const blurBackdropSrc = mdSource || lgSource || xlSource || null const primaryMainSrc = lgSource || xlSource || mdSource || FALLBACK_LG const primaryPreviewSrc = mdSource || lgSource || xlSource || FALLBACK_MD const srcSet = [ mdSource ? `${mdSource} 640w` : null, lgSource ? `${lgSource} 1280w` : null, xlSource ? `${xlSource} 1920w` : null, ].filter(Boolean).join(', ') const resolvedMainSrc = mainImageMode === 'fallback' ? FALLBACK_LG : (mainImageMode === 'hidden' ? null : primaryMainSrc) const resolvedPreviewSrc = previewImageMode === 'fallback' ? FALLBACK_MD : (previewImageMode === 'hidden' ? null : primaryPreviewSrc) const dbWidth = Number(mediaWidth ?? artwork?.width) const dbHeight = Number(mediaHeight ?? artwork?.height) const hasDbDims = dbWidth > 0 && dbHeight > 0 // Natural dimensions — seeded from DB if available, otherwise probed from // the xl thumbnail (largest available, never upscaled past the original). const [naturalDims, setNaturalDims] = useState( hasDbDims ? { w: dbWidth, h: dbHeight } : null ) useEffect(() => { setIsLoaded(false) setMainImageMode('primary') setPreviewImageMode('primary') setShowBackdrop(true) if (hasDbDims) { setNaturalDims({ w: dbWidth, h: dbHeight }) return } setNaturalDims(null) }, [mediaKey, hasDbDims, dbWidth, dbHeight]) // Probe the xl image to discover real dimensions when DB has none useEffect(() => { if (naturalDims || !xlSource) return const img = new Image() img.onload = () => { if (img.naturalWidth > 0 && img.naturalHeight > 0) { setNaturalDims({ w: img.naturalWidth, h: img.naturalHeight }) } } img.onerror = null img.src = xlSource }, [xlSource, naturalDims]) const aspectRatio = naturalDims ? `${naturalDims.w} / ${naturalDims.h}` : '16 / 9' return (
{blurBackdropSrc && showBackdrop && ( <> { event.currentTarget.onerror = null setShowBackdrop(false) }} />
)}
{hasPrev && ( )}
{ if (e.key === 'Enter' || e.key === ' ') { e.preventDefault() onOpenViewer() } } : undefined} > {resolvedPreviewSrc ? ( {artwork?.title { event.currentTarget.onerror = null if (previewImageMode === 'primary') { setPreviewImageMode('fallback') return } setPreviewImageMode('hidden') }} /> ) : null} {resolvedMainSrc ? ( {artwork?.title setIsLoaded(true)} onError={(event) => { event.currentTarget.onerror = null if (mainImageMode === 'primary') { setMainImageMode('fallback') setIsLoaded(false) return } setMainImageMode('hidden') setIsLoaded(true) }} /> ) : null} {onOpenViewer && ( )}
{hasRealArtworkImage && (
)}
{hasNext && ( )}
) }