From 1330e3e621fbeadf4771c3387c49c7489f262a21 Mon Sep 17 00:00:00 2001
From: Marco
Date: Wed, 26 Aug 2026 22:26:14 +0000
Subject: [PATCH] Show product subline on cards/cart/PDP hero; brand-color
trailing period
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Follows Products.subline (docker/payload commit ad7156e). Cards and cart
line items showed nothing but the bare name — added the subline under it.
der-eine and todo-cards' hero taglines were hardcoded copy nearly
identical to this new field — switched both to read subline instead, so
future edits go through the CMS.
Also adds a shared ProductName component: every hand-written PDP headline
already styled a trailing "." in brand color, but the few places that
render product.name as plain text (cards, cart, the Payload-driven
tasse-die-pause hero) had silently lost that styling. Centralizes it so
it can't drift per call site again.
Co-Authored-By: Claude Sonnet 5
Claude-Session: https://claude.ai/code/session_01J1Hu5bZ1kZUgKhab6yNwCt
---
app/cart/components/CartContent.tsx | 6 ++++--
app/components/ProductCard.tsx | 6 ++++--
app/components/ProductName.tsx | 16 ++++++++++++++++
app/der-eine/components/Hero.tsx | 14 ++++++++------
app/lib/__tests__/cartTotals.test.ts | 1 +
app/lib/payload.ts | 5 +++++
app/tasse-die-pause/components/Hero.tsx | 20 ++++++++++++++------
app/tasse-die-pause/components/Pricing.tsx | 4 +++-
app/todo-cards/components/TodoKartenHero.tsx | 14 ++++++++------
9 files changed, 63 insertions(+), 23 deletions(-)
create mode 100644 app/components/ProductName.tsx
diff --git a/app/cart/components/CartContent.tsx b/app/cart/components/CartContent.tsx
index 27d8469..f6d8c61 100644
--- a/app/cart/components/CartContent.tsx
+++ b/app/cart/components/CartContent.tsx
@@ -14,6 +14,7 @@ import { Reveal } from "../../components/Reveal";
import { VersandModal } from "../../components/VersandModal";
import { VatBreakdown } from "../../components/VatBreakdown";
import { ArrowLeftIcon } from "../../components/ArrowLeftIcon";
+import { ProductName } from "../../components/ProductName";
import { FreeShippingBanner } from "./FreeShippingBanner";
import type { TrustBadge, ShippingSettings } from "../../lib/payload";
@@ -260,7 +261,7 @@ export function CartContent({
className="font-semibold text-h-small text-text-primary hover:text-brand transition-colors"
style={{ fontFamily: "var(--font-lora)" }}
>
- {product.name}
+
{entry.variant ? ` (${entry.variant})` : ""}
) : (
@@ -268,10 +269,11 @@ export function CartContent({
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
>
- {product.name}
+
{entry.variant ? ` (${entry.variant})` : ""}
)}
+ {product.subline && {product.subline}
}
{/* Independent stacked rows, not grid siblings — no
equal-height pressure from neighboring lines, so a
plain conditional line is enough here. */}
diff --git a/app/components/ProductCard.tsx b/app/components/ProductCard.tsx
index f2839a3..5eb98ea 100644
--- a/app/components/ProductCard.tsx
+++ b/app/components/ProductCard.tsx
@@ -5,6 +5,7 @@ import { formatPrice, discountPercent } from "../lib/format";
import { effectiveTaxRate } from "../lib/cartTotals";
import { AddToCartInlineButton } from "./AddToCartInlineButton";
import { WishlistButton } from "./WishlistButton";
+import { ProductName } from "./ProductName";
import type { Product } from "../lib/payload";
// Single shared card markup for every product grid (ProductGrid,
@@ -108,13 +109,14 @@ export function ProductCard({
className="font-semibold text-h4 text-text-primary w-full hover:text-brand transition-colors"
style={{ fontFamily: "var(--font-lora)" }}
>
- {product.name}
+
) : (
- {product.name}
+
)}
+ {product.subline && {product.subline}
}
{discount !== null && (
diff --git a/app/components/ProductName.tsx b/app/components/ProductName.tsx
new file mode 100644
index 0000000..76d4ffe
--- /dev/null
+++ b/app/components/ProductName.tsx
@@ -0,0 +1,16 @@
+// Every hand-written PDP headline styles a trailing "." in brand color
+// (e.g. der-eine/Pricing.tsx's "Der Eine."),
+// matching how every product's own Payload `name` is actually written
+// ("Der Eine.", "Die Pause.", "Einfach anfangen."). Anywhere `product.name`
+// is rendered as plain text instead (cards, cart line items, the one
+// Payload-driven PDP hero) silently lost that styling — this centralizes
+// the same trailing-period split so it can't drift per call site again.
+export function ProductName({ name }: { name: string }) {
+ if (!name.endsWith(".")) return <>{name}>;
+ return (
+ <>
+ {name.slice(0, -1)}
+ .
+ >
+ );
+}
diff --git a/app/der-eine/components/Hero.tsx b/app/der-eine/components/Hero.tsx
index 7d6a229..2141af9 100644
--- a/app/der-eine/components/Hero.tsx
+++ b/app/der-eine/components/Hero.tsx
@@ -63,12 +63,14 @@ export async function Hero() {
>
Der Eine.
-
- Für die eine Sache, die gerade zählt.
-
+ {product?.subline && (
+
+ {product.subline}
+
+ )}
diff --git a/app/lib/__tests__/cartTotals.test.ts b/app/lib/__tests__/cartTotals.test.ts
index 540a408..9e7c141 100644
--- a/app/lib/__tests__/cartTotals.test.ts
+++ b/app/lib/__tests__/cartTotals.test.ts
@@ -6,6 +6,7 @@ const product = (overrides: Partial = {}): Product => ({
id: "todo-karten",
numericId: 1,
name: "ToDo-Karten",
+ subline: null,
description: null,
descriptionText: "",
sku: null,
diff --git a/app/lib/payload.ts b/app/lib/payload.ts
index 867e871..28378f4 100644
--- a/app/lib/payload.ts
+++ b/app/lib/payload.ts
@@ -181,6 +181,9 @@ export type Product = {
// slug-based call site.
numericId: number;
name: string;
+ // Short tagline shown under the name on cards/cart/PDP hero — see
+ // Products.ts's own field comment. null/"" means show nothing extra.
+ subline: string | null;
// Raw Lexical richText JSON — rendered formatted (bold/italic/multiple
// paragraphs) on the PDP via the shared component. Plain-text
// consumers (Passend-dazu cards, JSON-LD) use `descriptionText` below
@@ -271,6 +274,7 @@ export type Product = {
type PayloadProduct = {
id: number;
name: string;
+ subline: string | null;
slug: string;
description: unknown | null;
sku: string | null;
@@ -356,6 +360,7 @@ export function mapPayloadProduct(product: PayloadProduct): Product {
id: product.slug,
numericId: product.id,
name: product.name,
+ subline: product.subline || null,
description: product.description ?? null,
descriptionText: extractPlainText(descriptionRoot),
sku: product.sku || null,
diff --git a/app/tasse-die-pause/components/Hero.tsx b/app/tasse-die-pause/components/Hero.tsx
index 82248fe..9d7a22c 100644
--- a/app/tasse-die-pause/components/Hero.tsx
+++ b/app/tasse-die-pause/components/Hero.tsx
@@ -3,6 +3,7 @@ import Image from "next/image";
import { AddToCartButton } from "../../components/AddToCartButton";
import { Reveal } from "../../components/Reveal";
import { RichText } from "../../components/RichText";
+import { ProductName } from "../../components/ProductName";
import { getProductBySlug, getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer } from "../../lib/payload";
import { formatPrice, discountPercent } from "../../lib/format";
import { effectiveTaxRate } from "../../lib/cartTotals";
@@ -44,12 +45,19 @@ export async function Hero() {
-
- {product?.name ?? "Tasse"}
-
+
+
+ {product ? : "Tasse"}
+
+ {product?.subline && (
+
+ {product.subline}
+
+ )}
+
{product?.description ?
: null}
diff --git a/app/tasse-die-pause/components/Pricing.tsx b/app/tasse-die-pause/components/Pricing.tsx
index 5bab60a..cea47b9 100644
--- a/app/tasse-die-pause/components/Pricing.tsx
+++ b/app/tasse-die-pause/components/Pricing.tsx
@@ -2,6 +2,7 @@ import Image from "next/image";
import { AddToCartButton } from "../../components/AddToCartButton";
import { Reveal } from "../../components/Reveal";
import { RichText } from "../../components/RichText";
+import { ProductName } from "../../components/ProductName";
import { getProductBySlug, getShippingSettings, getDefaultTaxRatePercent, getKleinunternehmer } from "../../lib/payload";
import { formatPrice, discountPercent } from "../../lib/format";
import { effectiveTaxRate } from "../../lib/cartTotals";
@@ -47,8 +48,9 @@ export async function Pricing() {
className="font-semibold text-h-small text-text-primary"
style={{ fontFamily: "var(--font-lora)" }}
>
- {product.name}
+
+ {product.subline &&
{product.subline}
}
{product.description ?
: null}
diff --git a/app/todo-cards/components/TodoKartenHero.tsx b/app/todo-cards/components/TodoKartenHero.tsx
index ca0d74c..7a68556 100644
--- a/app/todo-cards/components/TodoKartenHero.tsx
+++ b/app/todo-cards/components/TodoKartenHero.tsx
@@ -97,12 +97,14 @@ export async function TodoKartenHero() {
>
ToDo-Karten.
-
- Kleine Karten. Große Wirkung.
-
+ {product?.subline && (
+
+ {product.subline}
+
+ )}