Vitron-Front/app/components/SellerTilesGrid.tsx
Arda Samadi e1c5899002 Add responsive desktop layout for home page
Single responsive tree (Tailwind lg:) — mobile experience unchanged; desktop
chrome is gated to the home route for now.

- DesktopHeader / DesktopFooter components (visible only at lg+), wired to
  real routes with live cart badge and working search
- MyLayout: render desktop header/footer on home, expand container and hide
  mobile bottom nav at lg
- Home: hide mobile top bar at lg, 1320px centered container, desktop hero
  grid (carousel + 2 promos), larger section headers
- SellerTilesGrid: 2-col mobile -> 5-col desktop with name overlay

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 20:07:47 +03:30

116 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Link } from "@remix-run/react";
import { ChevronLeft, Store } from "lucide-react";
import { Skeleton } from "./ui/skeleton";
import { ErrorState } from "./UiProvider";
interface SellerTile {
id?: string;
sellerId?: string;
sellerUsername?: string;
sellerName?: string;
imageUrl?: string;
order?: number;
}
interface SellerTilesGridProps {
sellers: SellerTile[];
isLoading: boolean;
isError: boolean;
refetch: () => void;
showViewAllButton?: boolean;
}
const SellerTilesGrid = ({
sellers,
isLoading,
isError,
refetch,
showViewAllButton = true,
}: SellerTilesGridProps) => {
if (isLoading) {
return <SellerTilesSkeleton />;
}
if (isError) {
return (
<div className="px-4">
<ErrorState onRetry={refetch} />
</div>
);
}
if (sellers.length === 0) {
return null;
}
return (
<div className="w-full flex flex-col gap-4 px-4 lg:px-0">
{/* 2x2 on mobile, single row of 5 on desktop */}
<div className="grid grid-cols-2 lg:grid-cols-5 gap-2 lg:gap-4">
{sellers.slice(0, 5).map((seller, index) => (
<Link
key={seller.id || index}
to={`/seller/${seller.sellerUsername}`}
className={`relative aspect-square overflow-hidden rounded-lg group ${
index === 4 ? "hidden lg:block" : ""
}`}
>
{/* Background Image */}
{seller.imageUrl ? (
<img
src={seller.imageUrl}
alt={seller.sellerName || "فروشگاه"}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500"
/>
) : (
<div className="w-full h-full bg-gradient-to-br from-gray-200 to-gray-300 flex items-center justify-center">
<Store size={48} className="text-gray-400" />
</div>
)}
{/* Desktop-only name overlay (matches the desktop design) */}
{seller.sellerName ? (
<>
<div className="hidden lg:block absolute inset-0 bg-gradient-to-t from-black/60 to-transparent" />
<div className="hidden lg:flex absolute inset-x-0 bottom-0 p-4 items-end">
<span className="text-white font-bold text-[15px] truncate">
{seller.sellerName}
</span>
</div>
</>
) : null}
</Link>
))}
</div>
{/* View All Button */}
{showViewAllButton && (
<Link
to="/sellers"
className="flex items-center justify-center gap-2 w-full py-3 border border-black rounded-none hover:bg-black hover:text-white transition-colors duration-300"
>
<span className="text-B14 font-bold">مشاهده همه فروشگاهها</span>
<ChevronLeft size={18} />
</Link>
)}
</div>
);
};
const SellerTilesSkeleton = () => {
return (
<div className="w-full flex flex-col gap-4 px-4">
<div className="grid grid-cols-2 gap-2">
{Array(4)
.fill(1)
.map((_, index) => (
<Skeleton key={index} className="aspect-square rounded-lg" />
))}
</div>
<Skeleton className="w-full h-12 rounded-none" />
</div>
);
};
export default SellerTilesGrid;