mirror of
https://github.com/Since-3/since3-portal.git
synced 2026-10-12 21:41:16 +00:00
80 lines
3.7 KiB
TypeScript
80 lines
3.7 KiB
TypeScript
import { brandName } from "../lib/content"
|
||
import type { FieldDef, ListFieldDef, SectionData, TemplateContent, TemplateDefinition } from "../lib/types"
|
||
|
||
const clean = (value: string) => value.replace(/\*/g, "").replace(/\s*\n\s*/g, " · ").trim()
|
||
|
||
type PageSection = { label: string; fields: (FieldDef | ListFieldDef)[]; data: SectionData | undefined; hidden: boolean }
|
||
|
||
// Feste Sektionen der Vorlage und – im Baukasten – die Bausteine in ihrer Reihenfolge
|
||
function pageSections(def: TemplateDefinition, content: TemplateContent): PageSection[] {
|
||
const fixed = def.sections.map((section) => ({
|
||
label: section.label,
|
||
fields: section.fields,
|
||
data: content.data[section.key],
|
||
hidden: content.hidden.includes(section.key),
|
||
}))
|
||
const library = new Map(def.builder?.library.map((block) => [block.type, block]))
|
||
const blocks = content.blocks.flatMap((block) => {
|
||
const definition = library.get(block.type)
|
||
if (!definition) return []
|
||
const menu = typeof block.data.menu === "string" ? block.data.menu.trim() : ""
|
||
return [{ label: menu || definition.label, fields: definition.fields, data: block.data, hidden: block.hidden }]
|
||
})
|
||
return [...fixed, ...blocks]
|
||
}
|
||
|
||
export function businessName(def: TemplateDefinition, content: TemplateContent) {
|
||
return brandName(content) ?? def.name
|
||
}
|
||
|
||
// Alles, was auf der Webseite steht, als Wissen für die KI – Bilder ausgenommen, ausgeblendete Sektionen auch
|
||
export function buildKnowledge(def: TemplateDefinition, content: TemplateContent) {
|
||
const parts = [`Betrieb: ${businessName(def, content)}`, `Branche: ${def.industry}`]
|
||
|
||
for (const section of pageSections(def, content)) {
|
||
const data = section.data
|
||
if (!data || section.hidden) continue
|
||
|
||
const lines: string[] = []
|
||
for (const field of section.fields) {
|
||
const value = data[field.key]
|
||
if (field.type === "list") {
|
||
if (!Array.isArray(value)) continue
|
||
const items = value
|
||
.map((item) =>
|
||
field.fields
|
||
.filter((sub) => sub.type !== "image" && item[sub.key]?.trim())
|
||
.map((sub) => `${sub.label}: ${clean(item[sub.key])}`)
|
||
.join("; ")
|
||
)
|
||
.filter(Boolean)
|
||
if (items.length) lines.push(`${field.label}:\n${items.map((item) => `- ${item}`).join("\n")}`)
|
||
} else if (field.type !== "image" && typeof value === "string" && value.trim()) {
|
||
lines.push(`${field.label}: ${clean(value)}`)
|
||
}
|
||
}
|
||
if (lines.length) parts.push(`\n## ${section.label}\n${lines.join("\n")}`)
|
||
}
|
||
|
||
if (content.ai.knowledge.trim()) parts.push(`\n## Zusatzwissen\n${content.ai.knowledge.trim()}`)
|
||
return parts.join("\n")
|
||
}
|
||
|
||
// Bild-Links der Variante, z. B. für die Post-Vorschauen im Content-Generator
|
||
export function collectImages(def: TemplateDefinition, content: TemplateContent) {
|
||
const images: string[] = []
|
||
for (const section of pageSections(def, content)) {
|
||
const data = section.data
|
||
if (!data) continue
|
||
for (const field of section.fields) {
|
||
const value = data[field.key]
|
||
if (field.type === "image" && typeof value === "string") images.push(value)
|
||
if (field.type === "list" && Array.isArray(value)) {
|
||
for (const sub of field.fields.filter((f) => f.type === "image")) {
|
||
images.push(...value.map((item) => item[sub.key] ?? ""))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return [...new Set(images.filter((src) => src.startsWith("http")))]
|
||
}
|