/** * Component: Audiobook Grid * Documentation: documentation/frontend/components.md * * Premium grid layout with generous spacing and elegant skeletons */ 'use client'; import React from 'react'; import { AudiobookCard } from './AudiobookCard'; import { Audiobook } from '@/lib/hooks/useAudiobooks'; interface AudiobookGridProps { audiobooks: Audiobook[]; isLoading?: boolean; emptyMessage?: string; onRequestSuccess?: () => void; cardSize?: number; // 1-9, default 5 squareCovers?: boolean; // true = square (1:1), false = rectangle (2:3) } // Grid classes with generous spacing for premium feel // IMPORTANT: Classes must be explicit strings for Tailwind purging function getGridClasses(size: number): string { const sizeMap: Record = { 1: 'grid-cols-4 md:grid-cols-6 lg:grid-cols-8 xl:grid-cols-10', 2: 'grid-cols-3 md:grid-cols-5 lg:grid-cols-7 xl:grid-cols-9', 3: 'grid-cols-3 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8', 4: 'grid-cols-2 md:grid-cols-4 lg:grid-cols-5 xl:grid-cols-7', 5: 'grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5', 6: 'grid-cols-2 md:grid-cols-3 lg:grid-cols-4', 7: 'grid-cols-2 md:grid-cols-3', 8: 'grid-cols-2', 9: 'grid-cols-1', }; return sizeMap[size] || sizeMap[5]; } export function AudiobookGrid({ audiobooks, isLoading = false, emptyMessage = 'No audiobooks found', onRequestSuccess, cardSize = 5, squareCovers = false, }: AudiobookGridProps) { const gridClasses = getGridClasses(cardSize); if (isLoading) { return (
{Array.from({ length: 10 }).map((_, i) => ( ))}
); } if (audiobooks.length === 0) { return (

{emptyMessage}

); } return (
{audiobooks.map((audiobook) => ( ))}
); } // Premium skeleton with shimmer effect function SkeletonCard({ squareCovers = false, index = 0 }: { squareCovers?: boolean; index?: number }) { return (
{/* Cover Skeleton */}
{/* Shimmer overlay */}
{/* Text Skeleton */}
); }