49 lines
1.2 KiB
TypeScript
49 lines
1.2 KiB
TypeScript
import React, { useState } from "react";
|
|
import { Squares2X2Icon, Bars3Icon } from "@heroicons/react/24/solid";
|
|
|
|
export type ListViewProps<T> = {
|
|
items: T[];
|
|
layout: "square" | "horizontal";
|
|
renderItem: (item: T, layout: "square" | "horizontal") => React.ReactNode;
|
|
onLoadMore: () => void;
|
|
hasMore: boolean;
|
|
loadingMore: boolean;
|
|
};
|
|
|
|
export function ListView<T>({
|
|
items,
|
|
layout,
|
|
renderItem,
|
|
onLoadMore,
|
|
hasMore,
|
|
loadingMore
|
|
}: ListViewProps<T>) {
|
|
|
|
return (
|
|
<div className="w-full flex flex-col items-center">
|
|
{/* Items */}
|
|
<div
|
|
className={`w-full sm:w-4/5 grid gap-6 ${
|
|
layout === "square"
|
|
? "grid-cols-1 sm:grid-cols-2 lg:grid-cols-4"
|
|
: "grid-cols-1"
|
|
}`}
|
|
>
|
|
{items.map(item => renderItem(item, layout))}
|
|
</div>
|
|
|
|
{/* Load More */}
|
|
{hasMore && (
|
|
<div className="mt-8">
|
|
<button
|
|
className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition disabled:opacity-50"
|
|
disabled={loadingMore}
|
|
onClick={onLoadMore}
|
|
>
|
|
{loadingMore ? "Loading..." : "Load More"}
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|