diff --git a/app/[slug]/page.tsx b/app/[slug]/page.tsx new file mode 100644 index 0000000..ec66659 --- /dev/null +++ b/app/[slug]/page.tsx @@ -0,0 +1,96 @@ +import type { Metadata } from "next"; +import Link from "next/link"; +import { notFound } from "next/navigation"; +import { draftMode } from "next/headers"; +import { Reveal } from "../components/Reveal"; +import { Footer } from "../components/Footer"; +import { PageBlocks } from "../components/PageBlocks"; +import { LivePageContent } from "../components/LivePageContent"; +import { getPageBySlug, getCompanySettings } from "../lib/payload"; +import { buildWebPageSchema } from "../lib/structuredData"; + +// First generic catch-all content route in this repo — every other page +// (blog posts excepted, which have their own [slug]) is its own static +// directory under app/. Powers Payload's new Pages collection (the page +// builder): a doc's `layout` blocks field renders via PageBlocks.tsx, +// structurally parallel to how RichText.tsx renders Posts.content's own +// (differently-shaped) Blocks. Next.js resolves any matching static route +// (e.g. app/lebensuhr/page.tsx) before ever reaching this catch-all, so a +// Pages document only actually serves a URL once the static file for that +// slug, if any, is removed. +export async function generateMetadata({ + params, +}: { + params: Promise<{ slug: string }>; +}): Promise { + const { slug } = await params; + const page = await getPageBySlug(slug); + if (!page) return { title: "Seite nicht gefunden" }; + + const title = page.seoTitle || page.title; + const description = page.seoDescription ?? undefined; + + return { + title, + description, + alternates: { canonical: `/${page.slug}` }, + openGraph: { + title, + description, + url: `/${page.slug}`, + type: "website", + images: page.seoImage ? [{ url: page.seoImage }] : undefined, + }, + twitter: { + title, + description, + images: page.seoImage ? [page.seoImage] : undefined, + }, + }; +} + +export default async function DynamicPage({ + params, +}: { + params: Promise<{ slug: string }>; +}) { + const { slug } = await params; + const { isEnabled: isPreview } = await draftMode(); + const page = await getPageBySlug(slug, { draft: isPreview }); + if (!page) notFound(); + + const seller = await getCompanySettings(); + const pageSchema = buildWebPageSchema(page, seller); + + return ( + <> +