import { useEffect, useRef } from 'react'; import { Box, Button, Card, Flex, Grid, Spinner, Stack, Text, } from '@sanity/ui'; import { CheckmarkCircleIcon, ImageIcon } from '@sanity/icons'; import type { LaminaAsset } from '../types.js'; function formatFileSize(bytes: number | null): string { if (bytes == null) return ''; if (bytes < 1024) return `${bytes} B`; if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; } export interface AssetPickerGridProps { assets: LaminaAsset[]; loading: boolean; loadingMore: boolean; hasMore: boolean; columns?: number; emptyMessage?: string; onSelect?: (asset: LaminaAsset) => void; onLoadMore?: () => void; } export function AssetPickerGrid(props: AssetPickerGridProps) { const { assets, loading, loadingMore, hasMore, columns = 3, emptyMessage, onSelect, onLoadMore, } = props; const scrollRef = useRef(null); // Infinite scroll useEffect(() => { const el = scrollRef.current; if (!el || !onLoadMore) return; const handleScroll = () => { const nearBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 200; if (nearBottom && hasMore && !loadingMore) { onLoadMore(); } }; el.addEventListener('scroll', handleScroll); return () => el.removeEventListener('scroll', handleScroll); }, [hasMore, loadingMore, onLoadMore]); if (loading) { return ( ); } if (assets.length === 0) { return ( {emptyMessage ?? 'No Lamina-generated assets yet'} ); } return ( {assets.map((asset) => { const isImage = asset._type === 'sanity.imageAsset'; return ( onSelect(asset) : undefined} > {isImage ? ( {asset.originalFilename ) : asset.mimeType?.startsWith('video/') ? (