import { forwardRef, useState, type HTMLAttributes } from "react" import { TableVirtuoso, type TableComponents } from "react-virtuoso" import { LoaderCircleIcon } from "lucide-react" import { CloudImage } from "@/components/common/cloud-image" import { Checkbox } from "@/components/ui/checkbox" import { Skeleton } from "@/components/ui/skeleton" import { TableCell, TableHead, TableRow } from "@/components/ui/table" import { cn } from "@/lib/utils" export type AlbumListItem = { id: number imgUrl: string originImgUrl?: string alt?: string name: string type: string typeName?: string collection: string sizeMb: number date: string isVideo?: boolean } export type AlbumListLabels = { name: string type: string size: string date: string } type AlbumListProps = { items: AlbumListItem[] selectedIds: Set onSelect: ( id: number, modifier?: { shiftKey: boolean metaKey: boolean ctrlKey: boolean } ) => void onToggleSelection: (id: number, checked?: boolean) => void onPreviewOpen: (id: number) => void onToggleAll: () => void formatSize: (sizeMb: number) => string scrollParent: HTMLElement | null labels: AlbumListLabels selectAllLabel: string clearSelectionLabel: string previewLabel: string onEndReached?: () => void isLoadingMore?: boolean } type AlbumListContext = { selectedIds: Set onSelect: ( id: number, modifier?: { shiftKey: boolean metaKey: boolean ctrlKey: boolean } ) => void onToggleSelection: (id: number, checked?: boolean) => void onPreviewOpen: (id: number) => void formatSize: (sizeMb: number) => string previewLabel: string } const AlbumTable = forwardRef>( ({ className, children, ...props }, ref) => ( {children}
) ) AlbumTable.displayName = "AlbumTable" const AlbumTableHead = forwardRef< HTMLTableSectionElement, HTMLAttributes >(({ className, ...props }, ref) => ( )) AlbumTableHead.displayName = "AlbumTableHead" const AlbumTableBody = forwardRef< HTMLTableSectionElement, HTMLAttributes >(({ className, ...props }, ref) => ( )) AlbumTableBody.displayName = "AlbumTableBody" const albumTableComponents: TableComponents = { Table: AlbumTable, TableHead: AlbumTableHead, TableBody: AlbumTableBody, TableRow: ({ item, context, ...props }) => { const isSelected = context.selectedIds.has(item.id) return ( { context.onSelect(item.id, { shiftKey: event.shiftKey, metaKey: event.metaKey, ctrlKey: event.ctrlKey }) }} className="cursor-pointer" /> ) }, } function AlbumListThumbnail({ imgUrl, alt, isVideo, onClick, label, type, }: { imgUrl: string alt: string isVideo?: boolean onClick: () => void label: string type?: string }) { const [isLoaded, setIsLoaded] = useState(false) return ( ) } export function AlbumList({ items, selectedIds, onSelect, onToggleSelection, onPreviewOpen, onToggleAll, formatSize, scrollParent, labels, selectAllLabel, clearSelectionLabel, previewLabel, onEndReached, isLoadingMore = false, }: AlbumListProps) { const selectedCount = items.reduce( (count, item) => count + Number(selectedIds.has(item.id)), 0 ) const isAllSelected = items.length > 0 && selectedCount === items.length const isIndeterminate = selectedCount > 0 && !isAllSelected const headerChecked = isAllSelected ? true : isIndeterminate ? "indeterminate" : false const headerLabel = isAllSelected ? clearSelectionLabel : selectAllLabel const tableContext: AlbumListContext = { selectedIds, onSelect, onToggleSelection, onPreviewOpen, formatSize, previewLabel, } return (
item.id} endReached={onEndReached} fixedHeaderContent={() => (
onToggleAll()} /> {labels.name}
{labels.type} {labels.size} {labels.date}
)} itemContent={(_, item, context) => ( <>
event.stopPropagation()} className="shrink-0" > context.onToggleSelection(item.id, checked === true) } />
context.onPreviewOpen(item.id)} label={context.previewLabel} type={item.type} />
{item.name}
{/* TODO(v3-post-launch): Restore collection subtitle when Collections feature returns.
{item.collection}
*/}
{item.typeName || item.type} {context.formatSize(item.sizeMb)} {item.date} )} /> {isLoadingMore && items.length > 0 ? (
) : null}
) }