From 098ba79c8f701990b02cc2eaa748adc7f911223e Mon Sep 17 00:00:00 2001
From: Marco
Date: Wed, 26 Aug 2026 20:41:21 +0000
Subject: [PATCH] Frontend support for the Hero block; H1 moves out of the
hardcoded wrapper
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
app/[slug]/page.tsx and LivePageContent.tsx no longer render a
hardcoded H1 from page.title — that's now the Hero block's job (see
HeroBlock.ts's own comment on why). Breadcrumb stays, still built
from page.title.
Also backfilled /lebensuhr's already-migrated Pages document with a
Hero block (order 0) carrying its real headline — without it the
page would have lost its H1 entirely once the hardcoded wrapper was
removed.
---
app/[slug]/page.tsx | 6 ------
app/components/LivePageContent.tsx | 11 +++--------
app/components/PageBlocks.tsx | 25 +++++++++++++++++++++++++
app/lib/payload.ts | 11 +++++++++++
4 files changed, 39 insertions(+), 14 deletions(-)
diff --git a/app/[slug]/page.tsx b/app/[slug]/page.tsx
index ec66659..c01c976 100644
--- a/app/[slug]/page.tsx
+++ b/app/[slug]/page.tsx
@@ -76,12 +76,6 @@ export default async function DynamicPage({
›{page.title}
-
- {page.title}
-
diff --git a/app/components/LivePageContent.tsx b/app/components/LivePageContent.tsx
index fb436fc..7f5cbf8 100644
--- a/app/components/LivePageContent.tsx
+++ b/app/components/LivePageContent.tsx
@@ -8,8 +8,9 @@ import { mapPayloadPage, type PayloadPage, type Page } from "../lib/payload";
const PAYLOAD_URL = process.env.NEXT_PUBLIC_PAYLOAD_URL || "https://payload.mk360.de";
-// Live-previewable subset of a Pages document: breadcrumb/H1 and the
-// layout blocks — same "editable subset only" scope as LivePostContent.tsx
+// Live-previewable subset of a Pages document: the breadcrumb and the
+// layout blocks (the H1 now lives in the first block, usually a "hero" —
+// see HeroBlock.ts) — same "editable subset only" scope as LivePostContent.tsx
// (see that file's own comment). `testimonialsRef` blocks are skipped here
// (see renderPageBlockSync's own comment) since they need an async fetch a
// client component can't perform inline; editing that block still shows up
@@ -30,12 +31,6 @@ export function LivePageContent({ initialPage }: { initialPage: Page }) {
›{page.title}
-
- {page.title}
-
diff --git a/app/components/PageBlocks.tsx b/app/components/PageBlocks.tsx
index 0df01c2..48dcf77 100644
--- a/app/components/PageBlocks.tsx
+++ b/app/components/PageBlocks.tsx
@@ -36,6 +36,31 @@ export async function PageBlocks({ blocks }: { blocks: PageBlock[] }) {
// makes for its own author-bio/"Weiterlesen" chrome).
export function renderPageBlockSync(block: PageBlock): React.ReactNode {
switch (block.blockType) {
+ // Same "font-playfair clamp headline" treatment every hand-built page
+ // (/lebensuhr, /3x3-system, /ueber-mich) used for its own H1 before
+ // this block existed — see HeroBlock.ts's own comment on why the
+ // headline moved out of Pages.title and into here.
+ case "hero":
+ return (
+