Frontend support for stepRow subtitle + new icon block
Mirrors the backend schema additions (StepRowBlock.items.subtitle, new IconBlock) needed for the /lebensuhr Pages migration: PageBlock type + mapPayloadPageBlock in payload.ts, a "icon" case in PageBlocks.tsx, and SYMBOLIC_ICONS (the clock face) added alongside STEP_ICONS in StepIcons.tsx — a distinct registry since these icons are standalone, not part of an icon-above-text row.
This commit is contained in:
@@ -5,7 +5,7 @@ import { getTestimonials } from "../lib/payload";
|
||||
import { RichText } from "./RichText";
|
||||
import { Quote } from "./Quote";
|
||||
import { StepArrow } from "./StepArrow";
|
||||
import { STEP_ICONS } from "./icons/StepIcons";
|
||||
import { STEP_ICONS, SYMBOLIC_ICONS } from "./icons/StepIcons";
|
||||
import { TestimonialsGrid } from "./TestimonialsGrid";
|
||||
|
||||
// Renders a Payload Pages document's `layout` blocks field — structurally
|
||||
@@ -42,6 +42,11 @@ export function renderPageBlockSync(block: PageBlock): React.ReactNode {
|
||||
case "quote":
|
||||
return <Quote key={block.id}>{block.text}</Quote>;
|
||||
|
||||
case "icon": {
|
||||
const SymbolIcon = SYMBOLIC_ICONS[block.icon];
|
||||
return SymbolIcon ? <div key={block.id}>{SymbolIcon()}</div> : null;
|
||||
}
|
||||
|
||||
case "image":
|
||||
if (!block.image) return null;
|
||||
return (
|
||||
@@ -114,6 +119,7 @@ export function renderPageBlockSync(block: PageBlock): React.ReactNode {
|
||||
</div>
|
||||
<div className="flex flex-col gap-1 text-center">
|
||||
<p className="font-semibold text-text-primary text-[1rem]">{item.title}</p>
|
||||
{item.subtitle && <p className="font-semibold text-[0.75rem] text-brand">{item.subtitle}</p>}
|
||||
<p className="text-[0.875rem] text-text-muted leading-[1.5]">{item.description}</p>
|
||||
</div>
|
||||
</div>,
|
||||
|
||||
@@ -131,3 +131,29 @@ export const STEP_ICONS: Record<string, () => React.ReactNode> = {
|
||||
trendingUp: IconTrendingUp,
|
||||
shield: IconShield,
|
||||
};
|
||||
|
||||
// Same symbolic clock icon /lebensuhr uses above its "24 Stunden" heading
|
||||
// — purely decorative (no numbers/data), unlike the STEP_ICONS above which
|
||||
// always sit inside an icon-above-text row. Keys MUST match the Payload
|
||||
// IconBlock's `icon` select field options (docker/payload/src/blocks/
|
||||
// IconBlock.ts) exactly.
|
||||
function IconClockSymbol() {
|
||||
return (
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" aria-hidden="true">
|
||||
<circle cx="24" cy="24" r="21" stroke="#f6a701" strokeWidth="2" />
|
||||
{[0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330].map((deg) => {
|
||||
const rad = (deg * Math.PI) / 180;
|
||||
const x1 = 24 + 16 * Math.sin(rad), y1 = 24 - 16 * Math.cos(rad);
|
||||
const x2 = 24 + 18.5 * Math.sin(rad), y2 = 24 - 18.5 * Math.cos(rad);
|
||||
return <line key={deg} x1={x1} y1={y1} x2={x2} y2={y2} stroke="#f6a701" strokeWidth="1.5" strokeLinecap="round" />;
|
||||
})}
|
||||
<line x1="24" y1="24" x2="17" y2="15" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
|
||||
<line x1="24" y1="24" x2="32" y2="15" stroke="#f6a701" strokeWidth="2" strokeLinecap="round" />
|
||||
<circle cx="24" cy="24" r="1.8" fill="#f6a701" />
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
|
||||
export const SYMBOLIC_ICONS: Record<string, () => React.ReactNode> = {
|
||||
clockSymbol: IconClockSymbol,
|
||||
};
|
||||
|
||||
+10
-2
@@ -1294,9 +1294,10 @@ export async function getTrackingCodes(): Promise<TrackingCode[]> {
|
||||
|
||||
export type PageBlock =
|
||||
| { blockType: "richTextSection"; id: string; content: unknown }
|
||||
| { blockType: "stepRow"; id: string; items: { id: string; icon: string; title: string; description: string }[] }
|
||||
| { blockType: "stepRow"; id: string; items: { id: string; icon: string; title: string; subtitle: string | null; description: string }[] }
|
||||
| { blockType: "quote"; id: string; text: string; label: string | null }
|
||||
| { blockType: "image"; id: string; image: string | null; caption: string | null }
|
||||
| { blockType: "icon"; id: string; icon: string }
|
||||
| { blockType: "pillList"; id: string; items: { id: string; label: string }[] }
|
||||
| { blockType: "checklistImage"; id: string; image: string | null; items: { id: string; text: string }[] }
|
||||
| { blockType: "table"; id: string; labelHeader: string; valueHeader: string; rows: { id: string; label: string; value: string }[] }
|
||||
@@ -1317,9 +1318,10 @@ type PayloadPageImageField = { url?: string | null } | number | null;
|
||||
|
||||
type PayloadPageBlock =
|
||||
| { blockType: "richTextSection"; id: string; content: unknown }
|
||||
| { blockType: "stepRow"; id: string; items: { id: string; icon: string; title: string; description: string }[] }
|
||||
| { blockType: "stepRow"; id: string; items: { id: string; icon: string; title: string; subtitle?: string | null; description: string }[] }
|
||||
| { blockType: "quote"; id: string; text: string; label?: string | null }
|
||||
| { blockType: "image"; id: string; image: PayloadPageImageField; caption?: string | null }
|
||||
| { blockType: "icon"; id: string; icon: string }
|
||||
| { blockType: "pillList"; id: string; items: { id: string; label: string }[] }
|
||||
| { blockType: "checklistImage"; id: string; image: PayloadPageImageField; items: { id: string; text: string }[] }
|
||||
| { blockType: "table"; id: string; labelHeader: string; valueHeader: string; rows: { id: string; label: string; value: string }[] }
|
||||
@@ -1350,6 +1352,12 @@ function mapPayloadPageBlock(block: PayloadPageBlock): PageBlock {
|
||||
return { blockType: "quote", id: block.id, text: block.text, label: block.label ?? null };
|
||||
case "ctaCard":
|
||||
return { blockType: "ctaCard", id: block.id, eyebrow: block.eyebrow, title: block.title, description: block.description ?? null, href: block.href };
|
||||
case "stepRow":
|
||||
return {
|
||||
blockType: "stepRow",
|
||||
id: block.id,
|
||||
items: block.items.map((item) => ({ ...item, subtitle: item.subtitle ?? null })),
|
||||
};
|
||||
default:
|
||||
return block;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user