crossSell: match der-eine's/blog's own "Passt dazu" card style
ProductCard (price, wishlist heart, add-to-cart button) read as a commerce grid, too busy for a single lightweight recommendation slot — der-eine's own hand-coded PasstDazu.tsx (and the blog's "Passend dazu" card) already had the right, more editorial look: bordered card, thumbnail + name + description + "Entdecken" arrow, no price/buy button. Reused that exact markup here instead, stacked rather than a grid. getWishlistEnabled/ProductCard now unused in this file, removed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013Eg6h91yngXmSnM51wxXM8
This commit is contained in:
@@ -8,7 +8,6 @@ import {
|
||||
getTestimonials,
|
||||
getProducts,
|
||||
getProductsByIds,
|
||||
getWishlistEnabled,
|
||||
} from "../lib/payload";
|
||||
import { formatPrice, discountPercent } from "../lib/format";
|
||||
import { effectiveTaxRate } from "../lib/cartTotals";
|
||||
@@ -17,7 +16,6 @@ import { ProductName } from "./ProductName";
|
||||
import { RichText } from "./RichText";
|
||||
import { Reveal } from "./Reveal";
|
||||
import { ProductGallery } from "./ProductGallery";
|
||||
import { ProductCard } from "./ProductCard";
|
||||
import { STEP_ICONS } from "./icons/StepIcons";
|
||||
import { renderPageBlockSync } from "./PageBlocks";
|
||||
import { TestimonialsGrid } from "./TestimonialsGrid";
|
||||
@@ -38,11 +36,10 @@ const CROSS_SELL_COUNT = 3;
|
||||
// need the live product/shipping/tax context that a generic content page
|
||||
// doesn't have.
|
||||
export async function ProductBlocks({ product }: { product: Product }) {
|
||||
const [shipping, defaultTaxRate, kleinunternehmer, wishlistEnabled] = await Promise.all([
|
||||
const [shipping, defaultTaxRate, kleinunternehmer] = await Promise.all([
|
||||
getShippingSettings(),
|
||||
getDefaultTaxRatePercent(),
|
||||
getKleinunternehmer(),
|
||||
getWishlistEnabled(),
|
||||
]);
|
||||
const ctx: ProductBlockContext = { product, shipping, taxRate: effectiveTaxRate(product, defaultTaxRate), kleinunternehmer };
|
||||
|
||||
@@ -68,23 +65,44 @@ export async function ProductBlocks({ product }: { product: Product }) {
|
||||
if (block.blockType === "crossSell") {
|
||||
const recommended = await getCrossSellProducts(block, product);
|
||||
if (recommended.length === 0) return null;
|
||||
// Same bordered "Passt dazu" card as der-eine's own hand-coded
|
||||
// PasstDazu.tsx (and the blog's "Passend dazu" card) — thumbnail +
|
||||
// name + description + "Entdecken" arrow, no price/wishlist/buy
|
||||
// button. Reads as editorial, not a commerce grid; ProductCard
|
||||
// (price, wishlist heart, add-to-cart) was too busy here
|
||||
// (reported 2026-08-29). Stacked, not a grid — PasstDazu's own
|
||||
// design was always a single full-width card; this just allows
|
||||
// more than one recommendation without losing that feel.
|
||||
return (
|
||||
<div key={block.id} className="w-full px-[var(--layout-padding-x)] py-8 sm:py-12">
|
||||
<p className="font-semibold text-h-small text-text-primary mb-6" style={{ fontFamily: "var(--font-lora)" }}>
|
||||
Das passt dazu
|
||||
</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
||||
{recommended.map((p) => (
|
||||
<ProductCard
|
||||
key={p.id}
|
||||
product={p}
|
||||
defaultTaxRate={defaultTaxRate}
|
||||
kleinunternehmer={kleinunternehmer}
|
||||
wishlistEnabled={wishlistEnabled}
|
||||
wishlistRevealOnHover
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div key={block.id} className="w-full px-[var(--layout-padding-x)] py-8 sm:py-12 flex flex-col gap-4 max-w-[48rem] mx-auto">
|
||||
{recommended.map((p) => (
|
||||
<Link
|
||||
key={p.id}
|
||||
href={p.href ?? `/${p.id}`}
|
||||
className="group flex items-center gap-4 sm:gap-6 border border-border rounded-md px-5 py-5 sm:px-9 sm:py-7 hover:border-brand transition-colors"
|
||||
>
|
||||
<div className="relative w-16 h-[4.6875rem] shrink-0 rounded-sm overflow-hidden">
|
||||
<Image src={p.image} alt="" fill sizes="64px" className="object-cover" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0 flex flex-col gap-2.5">
|
||||
<p className="font-bold text-[0.8125rem] text-brand">Passt dazu:</p>
|
||||
<div className="flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4 w-full">
|
||||
<div className="flex flex-col gap-2 items-start w-full sm:w-[19rem] sm:shrink-0">
|
||||
<p className="font-semibold text-[1.375rem] text-text-primary sm:whitespace-nowrap" style={{ fontFamily: "var(--font-lora)" }}>
|
||||
{p.name}
|
||||
</p>
|
||||
<p className="text-[0.9375rem] text-text-muted leading-[1.45]">{p.descriptionText}</p>
|
||||
</div>
|
||||
<span className="flex items-center gap-1.5 font-bold text-[0.875rem] text-text-primary whitespace-nowrap mt-1 sm:mt-0">
|
||||
Entdecken
|
||||
<svg viewBox="0 0 20 20" className="size-3.5 transition-transform duration-200 group-hover:translate-x-1" fill="none" aria-hidden="true">
|
||||
<path d="M4 10h12m0 0-5-5m5 5-5 5" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user