Initial commit: ANOUMA website with Payload CMS, WebRTC meetings, and booking system

- Next.js 16 App Router site with the ANOUMA design system
- Payload CMS (PostgreSQL) for offers, events, posts and page content
- WebRTC video-call system with custom signaling server
- SMTP email reminders and booking-request notifications
- Customer accounts, calendar-based availability, and booking workflow
This commit is contained in:
maro
2026-08-25 16:40:51 +02:00
commit 45261a0461
138 changed files with 23263 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
/**
* Minimal builders for Lexical's SerializedEditorState JSON — just enough to
* seed richText fields from plain paragraph/heading strings (see lib/texte.ts).
* Shape verified against node_modules/lexical's Serialized*Node types.
*/
type TextNode = {
type: "text";
version: 1;
text: string;
format: 0;
detail: 0;
mode: "normal";
style: "";
};
type ParagraphNode = {
type: "paragraph";
version: 1;
children: TextNode[];
direction: "ltr";
format: "";
indent: 0;
};
type HeadingNode = {
type: "heading";
tag: "h2" | "h3";
version: 1;
children: TextNode[];
direction: "ltr";
format: "";
indent: 0;
};
function textNode(text: string): TextNode {
return { type: "text", version: 1, text, format: 0, detail: 0, mode: "normal", style: "" };
}
function paragraphNode(text: string): ParagraphNode {
return {
type: "paragraph",
version: 1,
children: [textNode(text)],
direction: "ltr",
format: "",
indent: 0,
};
}
function headingNode(text: string, tag: "h2" | "h3" = "h2"): HeadingNode {
return {
type: "heading",
tag,
version: 1,
children: [textNode(text)],
direction: "ltr",
format: "",
indent: 0,
};
}
function root(children: (ParagraphNode | HeadingNode)[]) {
return {
root: {
type: "root",
children,
direction: "ltr" as const,
format: "" as const,
indent: 0,
version: 1,
},
};
}
export function lexicalFromParagraphs(paragraphs: readonly string[]) {
return root(paragraphs.map((p) => paragraphNode(p)));
}
export function lexicalFromSections(
intro: readonly string[],
sections?: readonly { heading: string; paragraphs: readonly string[] }[],
) {
const children: (ParagraphNode | HeadingNode)[] = intro.map((p) => paragraphNode(p));
if (sections) {
for (const section of sections) {
children.push(headingNode(section.heading));
children.push(...section.paragraphs.map((p) => paragraphNode(p)));
}
}
return root(children);
}