Files
website/src/components/RichText.tsx
T
enricobuehler 42a47cd2ab
Build & Deploy unom website / build (push) Successful in 11s
Build & Deploy unom website / deploy (push) Successful in 4s
website: read legal pages + footer from unom-cms
- Add src/lib/cms.ts: REST helpers (findPageBySlug, findFooter, findHeader)
- Add src/components/RichText.tsx: minimal Lexical → React renderer
  (heading h1-h4, paragraph, list, listitem, link, text + linebreaks +
  basic text-format bitflags).
- routes/legal/{imprint,privacy}.tsx now fetch via route loader; meta
  title + description come from the Page's own fields.
- Footer reads the Footer global via the root route's loader using
  getRouteApi('__root__'). Three sections + tagline match the previously
  hardcoded structure (now editable via cms.unom.io/admin).
- Drop react-markdown + src/content/legal/*.md (CMS is the source of truth).
2026-05-26 18:50:10 +02:00

68 lines
1.8 KiB
TypeScript

// Minimal Lexical → React renderer. Only handles the node kinds our CMS
// emits today (heading h1-h4, paragraph, list/listitem, link, text,
// linebreak). Add cases as new node kinds appear.
import type { JSX } from "react";
import type { LexNode, LexRoot } from "@/lib/cms";
function renderNodes(nodes: LexNode[] | undefined): JSX.Element[] {
return (nodes ?? []).map((n, i) => renderNode(n, i));
}
function renderNode(n: LexNode, key: number): JSX.Element {
switch (n.type) {
case "text": {
const format = (n as { format?: number }).format ?? 0;
let el: JSX.Element = <>{n.text}</>;
if (format & 1) el = <strong>{el}</strong>;
if (format & 2) el = <em>{el}</em>;
if (format & 8) el = <u>{el}</u>;
if (format & 16) el = <code>{el}</code>;
return <span key={key}>{el}</span>;
}
case "linebreak":
return <br key={key} />;
case "paragraph":
return <p key={key}>{renderNodes(n.children)}</p>;
case "heading": {
const Tag = (n.tag ?? "h2") as keyof JSX.IntrinsicElements;
return <Tag key={key}>{renderNodes(n.children)}</Tag>;
}
case "list": {
const Tag = (n.tag === "ol" ? "ol" : "ul") as "ol" | "ul";
return <Tag key={key}>{renderNodes(n.children)}</Tag>;
}
case "listitem":
return <li key={key}>{renderNodes(n.children)}</li>;
case "link": {
const url = n.fields?.url ?? "#";
const newTab = Boolean(n.fields?.newTab);
return (
<a
key={key}
href={url}
{...(newTab
? { target: "_blank", rel: "noopener noreferrer" }
: {})}
>
{renderNodes(n.children)}
</a>
);
}
default:
return <span key={key} />;
}
}
export default function RichText({ data }: { data: LexRoot | null | undefined }) {
if (!data?.root) return null;
return <>{renderNodes(data.root.children)}</>;
}