Merge version_2_1777290330734 into main #1

Merged
bender merged 1 commits from version_2_1777290330734 into main 2026-04-27 11:47:08 +00:00
2 changed files with 97 additions and 35 deletions

View File

@@ -17,6 +17,7 @@ type ProductQuantityCardsProps = {
name: string;
price: string;
imageSrc: string;
description?: string;
onAddToCart?: (quantity: number) => void;
}[];
};
@@ -37,6 +38,7 @@ const ProductQuantityCards = ({
name: p.name,
price: p.price,
imageSrc: p.imageSrc,
description: p.description,
onAddToCart: undefined as ((quantity: number) => void) | undefined,
}))
: productsProp;
@@ -90,7 +92,7 @@ const ProductQuantityCards = ({
{(primaryButton || secondaryButton) && (
<div className="flex flex-wrap justify-center gap-3 mt-3">
{primaryButton && <Button text={primaryButton.text} href={primaryButton.href} variant="primary"/>}
{secondaryButton && <Button text={secondaryButton.text} href={secondaryButton.href} variant="secondary"animationDelay={0.1} />}
{secondaryButton && <Button text={secondaryButton.text} href={secondaryButton.href} variant="secondary" animationDelay={0.1} />}
</div>
)}
</div>
@@ -100,42 +102,87 @@ const ProductQuantityCards = ({
{products.map((product) => (
<div
key={product.name}
className="h-full flex flex-col gap-3 xl:gap-4 2xl:gap-5 p-3 xl:p-4 2xl:p-5 card rounded"
className="group perspective-1000 w-full h-full min-h-[420px]"
>
<div className="aspect-square rounded overflow-hidden">
<ImageOrVideo imageSrc={product.imageSrc} />
</div>
<div className="flex flex-col gap-3">
<h3 className="text-xl font-medium truncate">{product.name}</h3>
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-2">
<button
onClick={() => handleDecrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Decrease quantity"
>
<Minus className="size-4" strokeWidth={1.5} />
</button>
<span className="w-fit text-base text-center font-medium">{getQuantity(product.name)}</span>
<button
onClick={() => handleIncrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Increase quantity"
>
<Plus className="size-4" strokeWidth={1.5} />
</button>
<div className="relative w-full h-full transform-style-preserve-3d transition-transform duration-700 group-hover:rotate-y-180">
{/* Front Face */}
<div className="absolute inset-0 backface-hidden flex flex-col gap-3 xl:gap-4 2xl:gap-5 p-3 xl:p-4 2xl:p-5 card rounded">
<div className="aspect-square rounded overflow-hidden shrink-0">
<ImageOrVideo imageSrc={product.imageSrc} />
</div>
<button
onClick={() => product.onAddToCart?.(getQuantity(product.name))}
className="h-8 px-5 rounded primary-button text-base text-primary-cta-text font-medium cursor-pointer"
>
{product.price}
</button>
<div className="flex flex-col gap-3 flex-1 justify-between">
<h3 className="text-xl font-medium truncate">{product.name}</h3>
<div className="flex items-center justify-between gap-3">
<div className="flex items-center gap-2">
<button
onClick={() => handleDecrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Decrease quantity"
>
<Minus className="size-4" strokeWidth={1.5} />
</button>
<span className="w-fit text-base text-center font-medium">{getQuantity(product.name)}</span>
<button
onClick={() => handleIncrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Increase quantity"
>
<Plus className="size-4" strokeWidth={1.5} />
</button>
</div>
<button
onClick={() => product.onAddToCart?.(getQuantity(product.name))}
className="h-8 px-5 rounded primary-button text-base text-primary-cta-text font-medium cursor-pointer"
>
{product.price}
</button>
</div>
</div>
</div>
{/* Back Face */}
<div className="absolute inset-0 backface-hidden rotate-y-180 flex flex-col gap-3 xl:gap-4 2xl:gap-5 p-3 xl:p-4 2xl:p-5 card rounded">
<h3 className="text-xl font-medium">{product.name}</h3>
<div className="flex-1 overflow-y-auto pr-2">
<p className="text-base leading-relaxed opacity-80">
{product.description || "Detailed product information will be displayed here. This includes specifications, materials, and care instructions to help you make an informed decision."}
</p>
</div>
<div className="flex items-center justify-between gap-3 pt-3 border-t border-foreground/10 shrink-0">
<div className="flex items-center gap-2">
<button
onClick={() => handleDecrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Decrease quantity"
>
<Minus className="size-4" strokeWidth={1.5} />
</button>
<span className="w-fit text-base text-center font-medium">{getQuantity(product.name)}</span>
<button
onClick={() => handleIncrement(product.name)}
className="flex items-center justify-center size-8 rounded card cursor-pointer"
aria-label="Increase quantity"
>
<Plus className="size-4" strokeWidth={1.5} />
</button>
</div>
<button
onClick={() => product.onAddToCart?.(getQuantity(product.name))}
className="h-8 px-5 rounded primary-button text-base text-primary-cta-text font-medium cursor-pointer"
>
{product.price}
</button>
</div>
</div>
</div>
</div>
@@ -147,4 +194,4 @@ const ProductQuantityCards = ({
);
};
export default ProductQuantityCards;
export default ProductQuantityCards;

View File

@@ -198,3 +198,18 @@ h6 {
bg, a same-color border is invisible and the button disappears. */
border: 1px solid color-mix(in srgb, var(--color-foreground) 18%, transparent);
}
@layer utilities {
.perspective-1000 {
perspective: 1000px;
}
.transform-style-preserve-3d {
transform-style: preserve-3d;
}
.backface-hidden {
backface-visibility: hidden;
}
.rotate-y-180 {
transform: rotateY(180deg);
}
}