| "use client"; |
|
|
| import * as React from "react"; |
| import { SearchX, FileStack } from "lucide-react"; |
| import { PaperCard, PaperCardProps } from "@/components/molecules/PaperCard"; |
| import { Icon } from "@/components/atoms/Icon"; |
| import { Spinner } from "@/components/atoms/Spinner"; |
| import { cn } from "@/lib/utils"; |
|
|
| interface PaperGridProps { |
| papers: PaperCardProps[]; |
| isLoading?: boolean; |
| onAddPaper?: (paper: PaperCardProps) => void; |
| className?: string; |
| } |
|
|
| |
| |
| |
| |
| |
| export function PaperGrid({ |
| papers, |
| isLoading, |
| onAddPaper, |
| className |
| }: PaperGridProps) { |
| |
| |
| if (isLoading) { |
| return ( |
| <div className={cn("grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3", className)}> |
| {[...Array(6)].map((_, i) => ( |
| <div |
| key={i} |
| className="h-[220px] animate-pulse rounded-lg border bg-muted/20" |
| /> |
| ))} |
| <div className="col-span-full flex justify-center py-12"> |
| <Spinner size={32} className="text-primary/40" /> |
| </div> |
| </div> |
| ); |
| } |
|
|
| |
| if (papers.length === 0) { |
| return ( |
| <div className={cn( |
| "flex flex-col items-center justify-center rounded-xl border-2 border-dashed bg-muted/5 py-24 text-center", |
| className |
| )}> |
| <div className="rounded-full bg-muted p-4 mb-4"> |
| <Icon icon={SearchX} size={32} className="text-muted-foreground" /> |
| </div> |
| <h3 className="text-lg font-semibold text-foreground">No papers found</h3> |
| <p className="max-w-[300px] text-sm text-muted-foreground mt-1"> |
| Try adjusting your search query or filters to find what you're looking for. |
| </p> |
| </div> |
| ); |
| } |
|
|
| |
| return ( |
| <div className={cn( |
| "grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3", |
| className |
| )}> |
| {papers.map((paper, index) => ( |
| <PaperCard |
| key={paper.doi || `${paper.title}-${index}`} |
| {...paper} |
| onAdd={() => onAddPaper?.(paper)} |
| className="h-full" // Ensures cards in the same row have equal height |
| /> |
| ))} |
| </div> |
| ); |
| } |
|
|