Desktop fixes: product seller + actions, collection cover, masonry skeleton
- product: show seller (logo + name) in the desktop info column (was missing after hiding the mobile header); action icons (save/share/collection/AI) are now circular bordered buttons on desktop instead of a bare icon row - collection detail: cover constrained to a 360px portrait column with object-cover (fixes over-long image + side margins); tighter spacing - masonry: only render the loading skeleton while actively fetching (removes the persistent grey block before the footer); sentinel moved above it Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
60d6a2a6e4
commit
fa65db8804
@ -194,8 +194,8 @@ const MondrianProductList = ({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{hasNextPage && <MondrianSkeleton isMini={true} />}
|
||||
<div ref={loadMoreRef} className="h-px w-full" />
|
||||
{isFetchingNextPage && <MondrianSkeleton isMini={true} />}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -160,53 +160,58 @@ export const ProductActions = ({ productId }: { productId: string }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const actionBtn =
|
||||
"flex items-center justify-center cursor-pointer transition-colors lg:w-10 lg:h-10 lg:rounded-full lg:border lg:border-WHITE3 lg:hover:bg-WHITE2";
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="flex w-full mt-4 px-4 justify-between">
|
||||
<div className="flex gap-8">
|
||||
{isCheckingBookmark ? (
|
||||
<Skeleton className="h-6 w-6 rounded-full" />
|
||||
) : isBookmarked ? (
|
||||
<>
|
||||
{isDeletingBookmark ? (
|
||||
<div className="flex w-full mt-4 px-4 justify-between lg:mt-0 lg:px-0">
|
||||
<div className="flex gap-8 lg:gap-2.5">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleBookmark}
|
||||
aria-label="ذخیره"
|
||||
className={actionBtn}
|
||||
>
|
||||
{isCheckingBookmark ? (
|
||||
<Skeleton className="h-6 w-6 rounded-full" />
|
||||
) : isBookmarked ? (
|
||||
isDeletingBookmark ? (
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
) : (
|
||||
<Bookmark
|
||||
size={20}
|
||||
className="text-PRIMARY fill-current cursor-pointer"
|
||||
onClick={handleBookmark}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{isBookmarking ? (
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
) : (
|
||||
<BookmarkMinus
|
||||
size={20}
|
||||
className="cursor-pointer"
|
||||
onClick={handleBookmark}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Share2
|
||||
size={20}
|
||||
className="cursor-pointer"
|
||||
<Bookmark size={20} className="text-PRIMARY fill-current" />
|
||||
)
|
||||
) : isBookmarking ? (
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
) : (
|
||||
<BookmarkMinus size={20} />
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setIsShareDrawerOpen(true)}
|
||||
/>
|
||||
<Layers
|
||||
size={20}
|
||||
className="cursor-pointer"
|
||||
aria-label="اشتراکگذاری"
|
||||
className={actionBtn}
|
||||
>
|
||||
<Share2 size={20} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAddToSet}
|
||||
/>
|
||||
aria-label="افزودن به ست"
|
||||
className={actionBtn}
|
||||
>
|
||||
<Layers size={20} />
|
||||
</button>
|
||||
<div className="relative">
|
||||
<Sparkles
|
||||
size={20}
|
||||
className="cursor-pointer animate-pulse text-PRIMARY"
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleOpenAIModal}
|
||||
/>
|
||||
aria-label="پرو با هوش مصنوعی"
|
||||
className={actionBtn}
|
||||
>
|
||||
<Sparkles size={20} className="animate-pulse text-PRIMARY" />
|
||||
</button>
|
||||
{showAIFeatureTooltip && (
|
||||
<div className="absolute bottom-full right-0 mb-2 z-50 animate-bounce">
|
||||
<div className="relative bg-gradient-to-r from-purple-600 to-pink-500 text-WHITE px-3 py-2 rounded-lg shadow-xl whitespace-nowrap border border-white/20">
|
||||
|
||||
@ -16,6 +16,7 @@ import { Button } from "../ui/button";
|
||||
import { useNavigate, Link } from "@remix-run/react";
|
||||
import { useSimilarProductsInfinite } from "~/requestHandler/use-product-hooks";
|
||||
import MondrianProductList from "../MondrianProductList";
|
||||
import SellerLogo from "../SellerLogo";
|
||||
|
||||
interface ProductDetailViewProps {
|
||||
product: ProductDetailType;
|
||||
@ -243,6 +244,22 @@ export const ProductDetailView = memo(function ProductDetailView({
|
||||
|
||||
{/* Info */}
|
||||
<div className="flex flex-col">
|
||||
{/* Seller (desktop) */}
|
||||
{!isOwner && product.seller?.username ? (
|
||||
<Link
|
||||
to={`/seller/${product.seller.username}`}
|
||||
className="hidden lg:flex items-center gap-2.5 mb-1"
|
||||
>
|
||||
<SellerLogo
|
||||
size="sm"
|
||||
src={product.seller?.storeLogo}
|
||||
alt="seller"
|
||||
/>
|
||||
<span className="font-bold text-[15px]">
|
||||
{product.seller.username}
|
||||
</span>
|
||||
</Link>
|
||||
) : null}
|
||||
{/* Inactive Product Status */}
|
||||
{!productActiveStatus && isOwner ? (
|
||||
<div className="flex gap-1 px-4 w-full justify-between items-center mt-2 lg:px-0">
|
||||
|
||||
@ -141,14 +141,14 @@ export default function CollectionDetail() {
|
||||
{/* Content */}
|
||||
<div className="flex flex-col lg:max-w-[1320px] lg:mx-auto lg:w-full lg:px-8 lg:pt-6">
|
||||
{/* Collection Header */}
|
||||
<div className="flex flex-col gap-4 p-4 border-b border-inner-border lg:grid lg:grid-cols-[1.3fr_1fr] lg:gap-8 lg:items-center lg:p-0 lg:py-8 lg:border-0">
|
||||
<div className="flex flex-col gap-4 p-4 border-b border-inner-border lg:grid lg:grid-cols-[360px_1fr] lg:gap-8 lg:items-start lg:p-0 lg:py-6 lg:border-0">
|
||||
{/* Cover Image */}
|
||||
<div className="relative overflow-hidden rounded-xl w-full mx-auto h-[65vh] bg-gray-100 lg:h-auto lg:aspect-[3/4] lg:bg-WHITE2">
|
||||
<div className="relative overflow-hidden rounded-xl w-full mx-auto h-[65vh] bg-gray-100 lg:h-auto lg:aspect-[3/4]">
|
||||
{collection.coverImageUrl ? (
|
||||
<img
|
||||
src={collection.coverImageUrl}
|
||||
alt={collection.title || "Collection"}
|
||||
className="w-full h-full object-cover lg:object-contain"
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full flex items-center justify-center bg-WHITE2">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user