Add /impressum and /datenschutz pages backed by Payload
- lib/payload.ts: getLegalPage(type) alongside the existing
getBlogPosts/getProducts fetchers
- New RichText component: small dependency-free Lexical JSON → JSX
renderer for Payload's richText fields (headings get stable
"section-N" ids for anchor/TOC linking)
- New SectionTOC: generalized from VersandTOC into a reusable
scroll-spy sidebar driven by any {id, title}[] — Datenschutz needs one
built from CMS-authored headings, not a hardcoded array. VersandTOC is
now a thin wrapper around it. Sticky positioning moved from the nav
itself to each page's sidebar wrapper, so a TOC and an extra card
(Impressum/Datenschutz both have one) scroll together as one unit
instead of the card drifting away independently
- TOC clicks set the active item immediately and hold it for ~1s over
the scroll-spy observer, covering both "target already fully visible,
nothing to scroll" and "an unrelated section flickers through the
intersection band mid-scroll"
- Both pages follow the same breadcrumb+H1+TOC-sidebar+content layout
established for /versand
This commit is contained in:
@@ -112,3 +112,38 @@ export async function getProductBySlug(slug: string): Promise<Product | null> {
|
||||
const products = await getProducts();
|
||||
return products.find((p) => p.id === slug) ?? null;
|
||||
}
|
||||
|
||||
export type LegalPageType = "impressum" | "datenschutz" | "agb" | "widerruf";
|
||||
|
||||
export type LegalPage = {
|
||||
type: LegalPageType;
|
||||
title: string;
|
||||
content: unknown;
|
||||
};
|
||||
|
||||
type PayloadLegalPage = {
|
||||
type: LegalPageType;
|
||||
title: string;
|
||||
content: unknown;
|
||||
};
|
||||
|
||||
export async function getLegalPage(type: LegalPageType): Promise<LegalPage | null> {
|
||||
const params = new URLSearchParams({
|
||||
"where[tenant.slug][equals]": TENANT_SLUG,
|
||||
"where[type][equals]": type,
|
||||
limit: "1",
|
||||
});
|
||||
|
||||
const res = await fetch(`${PAYLOAD_URL}/api/legal-pages?${params}`, {
|
||||
next: { revalidate: 60 },
|
||||
});
|
||||
if (!res.ok) {
|
||||
console.error(`getLegalPage: Payload returned ${res.status} ${res.statusText}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
const data: { docs?: PayloadLegalPage[] } = await res.json();
|
||||
const doc = data.docs?.[0];
|
||||
if (!doc) return null;
|
||||
return { type: doc.type, title: doc.title, content: doc.content };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user