'use client' import { memo, useCallback, useEffect, useMemo, useState } from 'react' import { cn } from '@djangocfg/ui-core/lib' import { useVirtualList } from '../../hooks/useVirtualList' import type { GalleryThumbnailsProps } from '../../types' import { normalizeImageUrl } from '../../utils' import { ImageSpinner } from '../shared' const SIZES = { sm: { width: 56, height: 40 }, md: { width: 80, height: 56 }, lg: { width: 96, height: 72 }, } as const /** * GalleryThumbnailsVirtual - Virtualized thumbnail strip for large galleries * Only renders visible thumbnails + buffer for optimal performance */ export const GalleryThumbnailsVirtual = memo(function GalleryThumbnailsVirtual({ images, currentIndex, onSelect, size = 'md', className, }: GalleryThumbnailsProps) { const dimensions = SIZES[size] const { containerRef, totalWidth, virtualItems, scrollToIndex } = useVirtualList({ itemCount: images.length, itemWidth: dimensions.width, gap: 8, overscan: 3, }) // Scroll active thumbnail into view useEffect(() => { scrollToIndex(currentIndex) }, [currentIndex, scrollToIndex]) // Handle thumbnail click const handleClick = useCallback( (index: number) => { onSelect(index) }, [onSelect] ) if (images.length <= 1) return null return (
{/* Spacer for total scroll width */}
{virtualItems.map((virtualItem) => { const image = images[virtualItem.index] const isActive = virtualItem.index === currentIndex return ( ) })}
) }) // Extracted virtual thumbnail component interface VirtualThumbnailProps { image: { id: string; src: string; thumbnail?: string; alt?: string } index: number isActive: boolean left: number width: number height: number onClick: (index: number) => void } const VirtualThumbnail = memo(function VirtualThumbnail({ image, index, isActive, left, width, height, onClick, }: VirtualThumbnailProps) { const [isLoaded, setIsLoaded] = useState(false) // Reset loading state when image source changes const imageSrc = useMemo(() => image?.thumbnail || image?.src, [image?.thumbnail, image?.src]) useEffect(() => { setIsLoaded(false) }, [imageSrc]) const handleClick = useCallback(() => { onClick(index) }, [onClick, index]) const handleLoad = useCallback(() => { setIsLoaded(true) }, []) return ( ) })