'use client'; /* eslint-disable jsx-a11y/alt-text */ import { BLUR_ENABLED } from '@/site/config'; import { useAppState } from '@/state/AppState'; import { clsx } from 'clsx/lite'; import Image, { ImageProps } from 'next/image'; import { useCallback, useEffect, useRef, useState } from 'react'; import FullscreenButton from '../FullscreenButton'; import Viewer from 'viewerjs'; import 'viewerjs/dist/viewer.css'; export default function ImageWithFallback(props: ImageProps & { blurCompatibilityLevel?: 'none' | 'low' | 'high' imgClassName?: string allowFullscreen?: boolean enableImageActions?: boolean }) { const { className, priority, blurDataURL, blurCompatibilityLevel = 'low', imgClassName = 'object-cover h-full', enableImageActions = false, ...rest } = props; const { shouldDebugImageFallbacks } = useAppState(); const [wasCached, setWasCached] = useState(true); const [isLoading, setIsLoading] = useState(true); const [didError, setDidError] = useState(false); const onLoad = useCallback(() => setIsLoading(false), []); const onError = useCallback(() => setDidError(true), []); const [hideFallback, setHideFallback] = useState(false); const containerRef = useRef(null); const viewerRef = useRef(null); const imgRef = useRef(null); const { isFullscreen } = useAppState(); useEffect(() => { const timeout = setTimeout( () => setWasCached(imgRef.current?.complete ?? false), 100, ); return () => clearTimeout(timeout); }, []); useEffect(() => { if (!isLoading && !didError) { const timeout = setTimeout(() => { setHideFallback(true); }, 1000); return () => clearTimeout(timeout); } }, [isLoading, didError]); useEffect(() => { if (containerRef.current && enableImageActions) { viewerRef.current = new Viewer(containerRef.current, { inline: false, button: true, navbar: false, title: false, toolbar: { zoomIn: 1, zoomOut: 1, reset: 1, play: { show: 0, size: 'large', }, tooltip: 1, }, }); return () => { viewerRef.current?.destroy(); }; } }, [enableImageActions]); const showFallback = !wasCached && !hideFallback; const getBlurClass = () => { switch (blurCompatibilityLevel) { case 'high': // Fix poorly blurred placeholder data generated on client return 'blur-[4px] @xs:blue-md scale-[1.05]'; case 'low': return 'blur-[2px] @xs:blue-md scale-[1.01]'; } }; return ( <>
{(showFallback || shouldDebugImageFallbacks) &&
{(BLUR_ENABLED && blurDataURL) ? :
}
} {enableImageActions && }
); }