Files
rustycms/scripts/contentful-to-rustycms.mjs

714 lines
30 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* Migriert Contentful-Export (contentful-export.json) nach rustycms content/de/.
* Nur deutsche Locale (en kann später ergänzt werden).
*
* Aufruf: node scripts/contentful-to-rustycms.mjs [Pfad-zum-Export] [--html-only] [--only=quote|iframe|image|image_gallery]
* Default Export-Pfad: ../www.windwiderstand.de/contentful-export.json
* --html-only: nur HTML migrieren
* --only=X: nur Typ X migrieren (mehrfach möglich), X = html|quote|iframe|image|image_gallery|youtube_video
*/
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(__dirname, "..");
const CONTENT_DE = path.join(ROOT, "content", "de");
const argv = process.argv.slice(2);
const ONLY = new Set();
if (argv.includes("--html-only")) ONLY.add("html");
argv.forEach((a) => {
const m = a.match(/^--only=(.+)$/);
if (m) ONLY.add(m[1]);
});
const EXPORT_PATH = argv.filter((a) => a !== "--html-only" && !a.startsWith("--only="))[0] || path.join(ROOT, "..", "www.windwiderstand.de", "contentful-export.json");
// ─── Slug-Normalisierung ─────────────────────────────────────────────────
function slugify(value) {
if (value == null || value === "") return "";
let s = String(value)
.replace(/^\//, "")
.replace(/\//g, "-")
.replace(/[^a-zA-Z0-9_-]+/g, "-")
.replace(/-+/g, "-")
.replace(/^-|-$/g, "");
return s || "untitled";
}
function safeSlug(entry, type) {
const f = entry?.fields || {};
if (type === "page" && f.slug != null) return f.slug === "/" ? "home" : slugify(f.slug);
if (f.id != null) return slugify(f.id);
if (type === "link" && f.slug != null) return slugify(f.slug);
if (entry?.sys?.id) return slugify(entry.sys.id);
return "untitled";
}
// ─── Rekursive Sammlung: alle Entries und Assets ──────────────────────────
function collectNodes(obj, entries, assets) {
if (!obj || typeof obj !== "object") return;
if (Array.isArray(obj)) {
obj.forEach((item) => collectNodes(item, entries, assets));
return;
}
const sys = obj.sys;
const fields = obj.fields;
if (sys?.type === "Asset" && fields?.file) {
const id = sys.id;
if (!assets.has(id)) assets.set(id, { sys, fields });
return;
}
const contentTypeId = sys?.contentType?.sys?.id || sys?.contentType?.id;
if (sys?.type === "Entry" && contentTypeId) {
const id = sys.id;
if (!entries.has(id)) {
entries.set(id, { sys: { ...sys, contentType: { id: contentTypeId } }, fields: fields || {} });
if (fields && typeof fields === "object") {
Object.values(fields).forEach((v) => collectNodes(v, entries, assets));
}
}
return;
}
Object.values(obj).forEach((v) => collectNodes(v, entries, assets));
}
// ─── JSON5-ähnlich ausgeben (gültiges JSON, 2 Leerzeichen) ────────────────
function writeJson5(filePath, obj) {
const dir = path.dirname(filePath);
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
const str = JSON.stringify(obj, null, 2);
fs.writeFileSync(filePath, str + "\n", "utf8");
}
// ─── Main ───────────────────────────────────────────────────────────────
function main() {
if (!fs.existsSync(EXPORT_PATH)) {
console.error("Export-Datei nicht gefunden:", EXPORT_PATH);
process.exit(1);
}
console.log("Lese Export:", EXPORT_PATH);
const data = JSON.parse(fs.readFileSync(EXPORT_PATH, "utf8"));
const byType = data.byType || {};
const entries = new Map();
const assets = new Map();
Object.values(byType).forEach((group) => {
if (group?.items) group.items.forEach((item) => collectNodes(item, entries, assets));
});
console.log("Einträge:", entries.size, "Assets:", assets.size);
const idToSlug = new Map();
const SUPPORTED_ROW_COMPONENTS = new Set([
"markdown", "html", "componentLinkList", "fullwidthBanner", "componentPostOverview", "componentSearchableText",
"quoteComponent", "iframe", "image", "imageGallery", "youtubeVideo",
]);
function getSlug(entryOrId, contentType) {
const entry = typeof entryOrId === "string" ? entries.get(entryOrId) : entryOrId;
if (!entry) return null;
const id = entry.sys?.id;
const type = contentType || entry.sys?.contentType?.id || entry.sys?.contentType?.sys?.id;
if (idToSlug.has(id)) return idToSlug.get(id);
// Assets: bereits in idToSlug aus Schritt 1
if (entry.sys?.type === "Asset") return idToSlug.get(id) || slugify(entry.fields?.title || id);
const slug = safeSlug(entry, type);
let finalSlug = slug;
let n = 0;
const used = new Set(idToSlug.values());
while (used.has(finalSlug)) {
n++;
finalSlug = slug + "-" + n;
}
idToSlug.set(id, finalSlug);
return finalSlug;
}
function refToSlug(ref) {
if (ref == null) return null;
if (typeof ref === "string") return idToSlug.get(ref) || ref;
if (ref.sys?.type === "Entry") return getSlug(ref, ref.sys?.contentType?.id);
if (ref.sys?.type === "Asset") return getSlug(ref, "img");
return null;
}
const run = (key) => !ONLY.size || ONLY.has(key);
// Bei --only=image/image_gallery: nur Asset-Slugs in idToSlug eintragen (für refToSlug), ohne img-Dateien zu schreiben
if (ONLY.size && (ONLY.has("image") || ONLY.has("image_gallery"))) {
assets.forEach((asset, id) => {
const slug = slugify(asset.fields?.title || id);
const uniq = Array.from(idToSlug.values()).includes(slug) ? slug + "-" + id.slice(0, 6) : slug;
idToSlug.set(id, uniq);
});
}
if (run("img")) {
// ─── 1) Assets → img ───────────────────────────────────────────────────
assets.forEach((asset, id) => {
const slug = slugify(asset.fields?.title || id);
const uniq = Array.from(idToSlug.values()).includes(slug) ? slug + "-" + id.slice(0, 6) : slug;
idToSlug.set(id, uniq);
const file = asset.fields?.file || {};
let url = file.url || "";
if (url && !url.startsWith("http")) url = "https:" + url;
const out = {
_slug: uniq,
title: asset.fields?.title ?? "",
description: asset.fields?.description ?? "",
file: {
url,
fileName: file.fileName,
contentType: file.contentType,
details: file.details,
},
};
writeJson5(path.join(CONTENT_DE, "img", uniq + ".json5"), out);
});
console.log("img:", assets.size);
}
if (run("tag")) {
// ─── 2) Tag ────────────────────────────────────────────────────────────
(byType.tag?.items || []).forEach((entry) => {
const slug = getSlug(entry, "tag");
const f = entry.fields || {};
writeJson5(path.join(CONTENT_DE, "tag", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
});
});
console.log("tag:", (byType.tag?.items || []).length);
}
if (run("link")) {
// ─── 3) Link ───────────────────────────────────────────────────────────
(byType.link?.items || []).forEach((entry) => {
const slug = getSlug(entry, "link");
const f = entry.fields || {};
writeJson5(path.join(CONTENT_DE, "link", slug + ".json5"), {
_slug: slug,
name: f.linkName ?? slug,
internal: slug,
linkName: f.linkName ?? "",
url: f.url ?? "",
newTab: f.newTab ?? false,
external: f.externalLink ?? false,
description: f.description ?? "",
alt: f.alt ?? "",
showText: f.showText !== false,
author: f.author ?? "",
date: f.date ?? "",
source: f.source ?? "",
});
});
console.log("link:", (byType.link?.items || []).length);
}
if (run("markdown")) {
// ─── 4) Markdown ────────────────────────────────────────────────────────
function extractMarkdown(entry) {
const slug = getSlug(entry, "markdown");
const f = entry.fields || {};
const layout = f.layout?.fields || {};
writeJson5(path.join(CONTENT_DE, "markdown", slug + ".json5"), {
_slug: slug,
name: f.id ?? slug,
content: f.content ?? "",
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
alignment: f.alignment ?? "left",
});
return slug;
}
function ensureMarkdown(entry) {
if (!entry || entry.sys?.contentType?.id !== "markdown") return null;
if (!idToSlug.has(entry.sys.id)) extractMarkdown(entry);
return idToSlug.get(entry.sys.id);
}
(byType.markdown?.items || []).forEach(extractMarkdown);
entries.forEach((entry) => {
if (entry.sys?.contentType?.id === "markdown" && !idToSlug.has(entry.sys.id)) extractMarkdown(entry);
});
console.log("markdown:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "markdown").length);
}
// ─── 4b) HTML (html) ────────────────────────────────────────────────────
if (run("html")) {
function extractHtml(entry) {
const slug = getSlug(entry, "html");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "html", slug + ".json5"), {
_slug: slug,
name: f.id ?? slug,
html: f.html ?? "",
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
});
return slug;
}
(byType.html?.items || []).forEach(extractHtml);
entries.forEach((entry) => {
if (entry.sys?.contentType?.id === "html" && !idToSlug.has(entry.sys.id)) extractHtml(entry);
});
console.log("html:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "html").length);
}
// ─── 4c) Quote (quoteComponent) ─────────────────────────────────────────
if (run("quote")) {
(byType.quoteComponent?.items || []).forEach((entry) => {
const slug = getSlug(entry, "quoteComponent");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "quote", slug + ".json5"), {
_slug: slug,
quote: f.quote ?? "",
author: f.author ?? "",
variant: f.variant ?? "left",
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
});
});
entries.forEach((e) => {
if (e.sys?.contentType?.id === "quoteComponent" && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "quoteComponent");
const f = e.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "quote", slug + ".json5"), {
_slug: slug,
quote: f.quote ?? "",
author: f.author ?? "",
variant: f.variant ?? "left",
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
});
}
});
console.log("quote:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "quoteComponent").length);
}
// ─── 4d) Iframe ────────────────────────────────────────────────────────
if (run("iframe")) {
(byType.iframe?.items || []).forEach((entry) => {
const slug = getSlug(entry, "iframe");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "iframe", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
content: f.content ?? "",
iframe: f.iframe ?? "",
overlayImage: refToSlug(f.overlayImage) ?? undefined,
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
});
});
entries.forEach((e) => {
if (e.sys?.contentType?.id === "iframe" && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "iframe");
const f = e.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "iframe", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
content: f.content ?? "",
iframe: f.iframe ?? "",
overlayImage: refToSlug(f.overlayImage) ?? undefined,
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
});
}
});
console.log("iframe:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "iframe").length);
}
// ─── 4e) Image ───────────────────────────────────────────────────────────
if (run("image")) {
(byType.image?.items || []).forEach((entry) => {
const slug = getSlug(entry, "image");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "image", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
image: refToSlug(f.image) ?? "",
caption: f.caption ?? "",
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
...(f.maxWidth != null && { maxWidth: f.maxWidth }),
...(f.aspectRatio != null && { aspectRatio: f.aspectRatio }),
});
});
entries.forEach((e) => {
if (e.sys?.contentType?.id === "image" && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "image");
const f = e.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "image", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
image: refToSlug(f.image) ?? "",
caption: f.caption ?? "",
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
...(f.maxWidth != null && { maxWidth: f.maxWidth }),
...(f.aspectRatio != null && { aspectRatio: f.aspectRatio }),
});
}
});
console.log("image:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "image").length);
}
// ─── 4f) ImageGallery ───────────────────────────────────────────────────
if (run("image_gallery")) {
(byType.imageGallery?.items || []).forEach((entry) => {
const slug = getSlug(entry, "imageGallery");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
const imageSlugs = (f.images || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "image_gallery", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
images: imageSlugs,
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
...(f.description != null && f.description !== "" && { description: f.description }),
});
});
entries.forEach((e) => {
if ((e.sys?.contentType?.id === "imageGallery" || e.sys?.contentType?.id === "imgGallery") && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "imageGallery");
const f = e.fields || {};
const layout = f.layout?.fields || f.layout || {};
const imageSlugs = (f.images || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "image_gallery", slug + ".json5"), {
_slug: slug,
name: f.name ?? slug,
images: imageSlugs,
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
...(f.description != null && f.description !== "" && { description: f.description }),
});
}
});
console.log("image_gallery:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "imageGallery" || e.sys?.contentType?.id === "imgGallery").length);
}
// ─── 4g) YoutubeVideo ───────────────────────────────────────────────────
if (run("youtube_video")) {
(byType.youtubeVideo?.items || []).forEach((entry) => {
const slug = getSlug(entry, "youtubeVideo");
const f = entry.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "youtube_video", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
youtubeId: f.youtubeId ?? "",
...(f.params != null && f.params !== "" && { params: f.params }),
...(f.title != null && f.title !== "" && { title: f.title }),
...(f.description != null && f.description !== "" && { description: f.description }),
layout: {
mobile: layout.mobile ?? "12",
tablet: layout.tablet,
desktop: layout.desktop,
spaceBottom: layout.spaceBottom ?? 0,
},
});
});
entries.forEach((e) => {
if (e.sys?.contentType?.id === "youtubeVideo" && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "youtubeVideo");
const f = e.fields || {};
const layout = f.layout?.fields || f.layout || {};
writeJson5(path.join(CONTENT_DE, "youtube_video", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
youtubeId: f.youtubeId ?? "",
...(f.params != null && f.params !== "" && { params: f.params }),
...(f.title != null && f.title !== "" && { title: f.title }),
...(f.description != null && f.description !== "" && { description: f.description }),
layout: { mobile: layout.mobile ?? "12", tablet: layout.tablet, desktop: layout.desktop, spaceBottom: layout.spaceBottom ?? 0 },
});
}
});
console.log("youtube_video:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "youtubeVideo").length);
}
if (ONLY.size) {
console.log("Fertig. Nur migriert:", [...ONLY].sort().join(", "));
return;
}
// ─── 5) Link-List (componentLinkList) ───────────────────────────────────
function writeLinkList(entry) {
const slug = getSlug(entry, "componentLinkList");
const f = entry.fields || {};
const linkSlugs = (f.links || []).map((l) => refToSlug(l)).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "link_list", slug + ".json5"), {
_slug: slug,
headline: f.headline ?? "",
links: linkSlugs,
});
}
(byType.componentLinkList?.items || []).forEach(writeLinkList);
entries.forEach((e) => {
if (e.sys?.contentType?.id === "componentLinkList" && !idToSlug.has(e.sys.id)) writeLinkList(e);
});
console.log("link_list:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "componentLinkList").length);
// ─── 6) FullwidthBanner ────────────────────────────────────────────────
function extractFullwidthBanner(entry) {
const slug = getSlug(entry, "fullwidthBanner");
const f = entry.fields || {};
const img = f.img;
let image = [];
if (img?.fields?.file?.url) {
let u = img.fields.file.url;
if (!u.startsWith("http")) u = "https:" + u;
image = [u];
}
writeJson5(path.join(CONTENT_DE, "fullwidth_banner", slug + ".json5"), {
_slug: slug,
name: f.id ?? slug,
variant: f.variant ?? "light",
headline: f.headline ?? "",
subheadline: f.subheadline ?? "",
text: f.text ?? "",
image,
});
return slug;
}
(byType.fullwidthBanner?.items || []).forEach(extractFullwidthBanner);
entries.forEach((e) => {
if (e.sys?.contentType?.id === "fullwidthBanner" && !idToSlug.has(e.sys.id)) extractFullwidthBanner(e);
});
console.log("fullwidth_banner:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "fullwidthBanner").length);
// ─── 7) PostOverview (componentPostOverview) ────────────────────────────
(byType.componentPostOverview?.items || []).forEach((entry) => {
const slug = getSlug(entry, "componentPostOverview");
const f = entry.fields || {};
const tagSlugs = (f.filterByTag || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "post_overview", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
headline: f.headline ?? "",
allPosts: f.allPosts ?? true,
filterByTag: tagSlugs,
});
});
entries.forEach((e) => {
if (e.sys?.contentType?.id === "componentPostOverview" && !idToSlug.has(e.sys.id)) {
const slug = getSlug(e, "componentPostOverview");
const f = e.fields || {};
const tagSlugs = (f.filterByTag || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "post_overview", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
headline: f.headline ?? "",
allPosts: f.allPosts ?? true,
filterByTag: tagSlugs,
});
}
});
console.log("post_overview:", Array.from(entries.values()).filter((e) => e.sys?.contentType?.id === "componentPostOverview").length);
// ─── 8) TextFragment + SearchableText (optional, falls verwendet) ────────
(byType.textFragment?.items || []).forEach((entry) => {
const slug = getSlug(entry, "textFragment");
const f = entry.fields || {};
const tagSlugs = (f.tags || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "text_fragment", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
title: f.title ?? "",
text: f.text ?? "",
tags: tagSlugs,
});
});
(byType.componentSearchableText?.items || []).forEach((entry) => {
const slug = getSlug(entry, "componentSearchableText");
const f = entry.fields || {};
const fragSlugs = (f.textFragments || []).map(refToSlug).filter(Boolean);
const tagSlugs = (f.tagWhitelist || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "searchable_text", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
textFragments: fragSlugs,
tagWhitelist: tagSlugs,
title: f.title,
description: f.description,
});
});
// ─── 9) Post ───────────────────────────────────────────────────────────
(byType.post?.items || []).forEach((entry) => {
const slug = getSlug(entry, "post");
const f = entry.fields || {};
const row1Content = (f.row1Content || []).map(refToSlug).filter(Boolean);
const obj = {
_slug: slug,
slug: f.slug ?? "/" + slug,
linkName: f.linkName ?? "",
headline: f.headline ?? "",
subheadline: f.subheadline ?? "",
excerpt: f.excerpt ?? "",
...(entry.sys?.createdAt && { created: entry.sys.createdAt }),
postImage: refToSlug(f.postImage) || null,
postTag: (f.postTag || []).map(refToSlug).filter(Boolean),
important: f.important ?? false,
content: f.content ?? "",
showCommentSection: f.showCommentSection !== false,
row1JustifyContent: f.row1JustifyContent ?? "start",
row1AlignItems: f.row1AlignItems ?? "start",
seoTitle: f.seoTitle ?? "",
seoDescription: f.seoDescription ?? "",
seoMetaRobots: f.seoMetaRobots ?? "index, follow",
};
if (obj.postImage == null) delete obj.postImage;
if (row1Content.length) obj.row1Content = row1Content;
writeJson5(path.join(CONTENT_DE, "post", slug + ".json5"), obj);
});
console.log("post:", (byType.post?.items || []).length);
// ─── 10) Page (alle Page-Einträge aus entries, damit auch nur in Nav referenzierte) ───
const pageEntries = Array.from(entries.values()).filter((e) => (e.sys?.contentType?.id || e.sys?.contentType?.sys?.id) === "page");
pageEntries.forEach((entry) => {
const slug = getSlug(entry, "page");
const f = entry.fields || {};
const row1Content = (f.row1Content || [])
.filter((ref) => ref?.sys?.contentType && SUPPORTED_ROW_COMPONENTS.has(ref.sys.contentType.sys?.id || ref.sys.contentType.id))
.map(refToSlug)
.filter(Boolean);
const name = slug === "home" || f.slug === "/" ? "home" : slug;
const pageSlug = f.slug ?? (name === "home" ? "/" : "/" + name);
writeJson5(path.join(CONTENT_DE, "page", slug + ".json5"), {
_slug: slug,
slug: pageSlug,
name,
linkName: f.linkName ?? "",
headline: f.headline ?? "",
subheadline: f.subheadline ?? "",
seoTitle: f.seoTitle ?? "",
seoDescription: f.seoDescription ?? "",
seoMetaRobots: f.seoMetaRobots ?? "index, follow",
row1JustifyContent: f.row1JustifyContent ?? "start",
row1AlignItems: f.row1AlignItems ?? "start",
row1Content,
...(refToSlug(f.topFullwidthBanner) ? { topFullwidthBanner: refToSlug(f.topFullwidthBanner) } : {}),
});
});
console.log("page:", pageEntries.length);
// ─── 11) Footer ────────────────────────────────────────────────────────
(byType.footer?.items || []).forEach((entry) => {
const slug = getSlug(entry, "footer");
const f = entry.fields || {};
const row1Content = (f.row1Content || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "footer", slug + ".json5"), {
_slug: slug,
id: f.id ?? slug,
row1JustifyContent: f.row1JustifyContent ?? "start",
row1AlignItems: f.row1AlignItems ?? "start",
row1Content,
});
});
// ─── 12) Navigation ─────────────────────────────────────────────────────
(byType.navigation?.items || []).forEach((entry) => {
const slug = getSlug(entry, "navigation");
const f = entry.fields || {};
const links = (f.links || []).map((p) => refToSlug(p)).filter(Boolean);
const internal = f.id ?? (slug === "navigation-header" ? "navigation-header" : slug);
writeJson5(path.join(CONTENT_DE, "navigation", (f.id || slug) + ".json5"), {
_slug: f.id || slug,
name: f.id ?? slug,
internal,
links,
});
});
// ─── 13) PageConfig ─────────────────────────────────────────────────────
const pageConfigItems = byType.pageConfig?.items || [];
const defaultFooterText = "© Bürgerinitiative Vachdorf. Alle Rechte vorbehalten.";
pageConfigItems.forEach((entry) => {
const slug = "default";
const f = entry.fields || {};
const logoRef = f.logo;
const logoSlug = logoRef ? (logoRef.sys?.type === "Asset" ? idToSlug.get(logoRef.sys?.id) : null) : null;
writeJson5(path.join(CONTENT_DE, "page_config", slug + ".json5"), {
_slug: slug,
logo: logoSlug ?? "logo",
footerText1: defaultFooterText,
seoTitle: f.seoTitle ?? "Bürgerinitiative Vachdorf / $1",
seoDescription: f.seoDescription ?? "$1 - Bürgerinitiative Vachdorf",
website: f.website ?? "https://www.windwiderstand.de",
});
});
if (pageConfigItems.length === 0) {
writeJson5(path.join(CONTENT_DE, "page_config", "default.json5"), {
_slug: "default",
logo: "logo",
footerText1: defaultFooterText,
seoTitle: "Bürgerinitiative Vachdorf / $1",
seoDescription: "$1 - Bürgerinitiative Vachdorf",
website: "https://www.windwiderstand.de",
});
}
// ─── 14) Campaign ───────────────────────────────────────────────────────
(byType.campaign?.items || []).forEach((entry) => {
const slug = getSlug(entry, "campaign");
const f = entry.fields || {};
writeJson5(path.join(CONTENT_DE, "campaign", slug + ".json5"), {
_slug: slug,
campaignName: f.campaingName ?? f.campaignName ?? slug,
urlPattern: f.urlPatter ?? f.urlPattern ?? "/",
selector: f.selector ?? "body",
insertHtml: f.insertHtml ?? "beforeend",
timeUntil: f.timeUntil ?? "",
html: f.html ?? "",
javascript: f.javascript ?? "",
css: f.css ?? "",
});
});
// ─── 15) Campaigns ─────────────────────────────────────────────────────
(byType.campaigns?.items || []).forEach((entry) => {
const slug = getSlug(entry, "campaigns");
const f = entry.fields || {};
const campaignSlugs = (f.campaings || f.campaigns || []).map(refToSlug).filter(Boolean);
writeJson5(path.join(CONTENT_DE, "campaigns", (f.id || slug) + ".json5"), {
_slug: f.id || slug,
id: f.id ?? slug,
campaigns: campaignSlugs,
enable: f.enable !== false,
});
});
console.log("Fertig. Content in", CONTENT_DE);
}
main();