42a47cd2ab
- 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).
68 lines
1.8 KiB
TypeScript
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)}</>;
|
|
}
|