Manifest
Kennung, Regionen, Block-Whitelist, Einstellungen und das optionale Lizenz-Feld.
Das Manifest (src/shared/manifest.ts) beschreibt das Template für Galerie, Prüfung und Barrierefreiheits-Regeln.
Es ist framework-frei (kein React), weil auch die API es lädt. defineTemplateManifest aus dem SDK prüft es sofort
und wirft TemplateManifestError bei Widersprüchen.
import { z } from "zod";
import { defineTemplateManifest, type TemplateManifest, type TemplateSettingsField } from "@patriotconnect/template-sdk";
export const MeinSettings = z
.object({
accent: z.enum(["brand", "cta", "neutral"]).default("brand"),
width: z.enum(["narrow", "wide"]).default("wide"),
})
.strict();
export const MEIN_SETTINGS_FIELDS: readonly TemplateSettingsField[] = [
{ key: "accent", label: "Farbe der Zierlinien", type: "select", defaultValue: "brand",
options: [{ value: "brand", label: "Markenfarbe" }, { value: "cta", label: "Aktionsfarbe" }, { value: "neutral", label: "Neutral" }] },
{ key: "width", label: "Breite des Inhalts", type: "select", defaultValue: "wide",
options: [{ value: "wide", label: "Breit" }, { value: "narrow", label: "Schmal" }] },
];
export const meinTemplateManifest: TemplateManifest = defineTemplateManifest({
id: "mein-template",
version: "0.1.0",
name: "Mein Template",
description: "Ruhige Lesespalte mit Zierlinie.",
previewImage: "data:image/svg+xml,…",
siteKinds: ["org", "portal"],
rendersTitleH1: true,
regions: [
{ id: "main", label: "Hauptinhalt (Blöcke)" },
{ id: "header-main", label: "Hauptnavigation" },
{ id: "footer-1", label: "Footer: Navigation" },
{ id: "footer-2", label: "Footer: Rechtliches" },
],
blockWhitelist: ["rich_text_block", "heading", "image", "feature_card_grid", "cta_banner"],
settingsSchema: MeinSettings,
settingsFields: MEIN_SETTINGS_FIELDS,
// nur für buchbare Templates – siehe unten
license: { catalogKey: "template.mein-template", edition: "enterprise" },
});Felder
| Feld | Bedeutung |
|---|---|
id | Kebab-Case, eindeutig; Wert von Site.template bzw. Page.template. default ist als Alias für standard reserviert. |
version | Semver, gleich der Version in package.json. |
siteKinds | org (Gliederung, Verein), person (Personen-Website), portal. Mindestens eine. |
siteRoles | Nur für Org-Websites: primary, campaign, microsite. Fehlt = alle. |
usage | ["site"], ["page"] oder beides (Standard): Website-Template und/oder Übersteuerung einer Seite. |
rendersTitleH1 | true, wenn das Template den Seitentitel selbst als H1 ausgibt – dann lässt der Editor keinen Block mit eigener H1 zu. |
previewImage | Vorschau in der Galerie: data:image/svg+xml,…, https://… oder /media/…. |
license | Optional: Lizenz-Katalogeintrag (siehe unten). |
Regionen
Regionen sind die Plätze des Templates. Sie erscheinen im Menü-Editor („Menü anzeigen in …“) und bestimmen,
welche Menüs die Render-Funktion erhält (props.menus["header-main"]).
mainist Pflicht und nimmt die Blöcke der Seite auf.- Üblich:
header-main,footer-1,footer-2. Eigene Plätze (z. B.header-meta) sind erlaubt. - Fehlt ein Menü, rendert die Region nichts – eine leere Region ist kein Fehler.
- Deklarieren Sie nur Regionen, die das Template auch zeigt.
Blöcke
Ein Template rendert keine Block-Inhalte selbst, sondern ruft props.renderBlock(block) auf. blockWhitelist
bestimmt die Palette im Seiten-Editor; fehlt das Feld, sind alle Blöcke erlaubt. Gibt das Template den Titel als H1
aus, gehören Seitenkopf-Blöcke mit eigener H1 nicht in die Whitelist.
Einstellungen
Schema (settingsSchema, Zod) und Formular (settingsFields) müssen deckungsgleich sein:
- jedes Feld hat einen Default –
schema.parse({})muss gelingen, .strict()– unbekannte Schlüssel werden abgelehnt,- Farben nur als Auswahl von Theme-Token-Varianten (
brand,cta,neutral), nie als freier Farbwert, - Controls:
text,textarea,select,toggle,number,color,image,url.
Lizenz-Feld
Templates können ein Eintrag im Lizenz-Katalog sein (ADR-0107):
license: { catalogKey: "template.mein-template", edition: "enterprise" },| Teil | Regel |
|---|---|
catalogKey | Kleinbuchstaben, Ziffern, Punkt, Bindestrich, Unterstrich; 2–80 Zeichen; beginnt mit einem Buchstaben. |
edition | Optional, 1–40 Zeichen: kleinste Edition, ab der das Template enthalten ist. Fehlt = jede Edition mit diesem Eintrag. |
Ohne license-Feld ist ein Template lizenzfrei und in jeder Edition wählbar – so wie template-beispiel. Das
Template prüft die Lizenz nie selbst; das übernimmt die Plattform (siehe
Freischaltung und Lizenz).