Kant CMS: Grundgerüst, visueller Editor, Mediathek
Symfony 7.4 / Twig / Doctrine DBAL auf herkömmlichem PHP-Webhosting. Versionierte Blockdokumente (v1-v3) mit unveränderlichen Revisionen, getrennten Entwürfen/Veröffentlichungen und optimistischer Konflikterkennung. Visueller Editor mit Strukturbaum, Live-Vorschau, responsiven Gerätewerten, Abschnittsvorlagen, Bildmediathek, Galerien und Effekten. Öffentliche Ausgabe ohne Editor-JavaScript. Geprüft: 41 PHP-Tests / 155 Assertions, 10 JavaScript-Modelltests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
82b07820bc
87 files changed
+14463
No files matched your search
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Content;
|
||||
|
||||
final class DemoContent
|
||||
{
|
||||
public static function pages(): array
|
||||
{
|
||||
return [
|
||||
'home' => [
|
||||
'schemaVersion' => 1,
|
||||
'title' => 'Kant CMS · Raum für deine Website',
|
||||
'description' => 'Ein eigenes CMS für individuelle Kundenwebsites. Entdecke die technische Grundlage für strukturierte Inhalte, schnelle Seiten und einen visuellen Editor.',
|
||||
'blocks' => [
|
||||
self::section('hero', [
|
||||
self::text('eyebrow', 'KANT CMS / DER ANFANG IST GEMACHT'),
|
||||
self::heading('headline', 'Deine Inhalte.\nDein Gestaltungsspielraum.', 1),
|
||||
self::text('intro', 'Eine Website sollte zu dir passen. Wir entwickeln die Grundlage dafür: klar strukturierte Inhalte, unabhängiges Hosting und einen Editor, der Gestaltung einfach macht.'),
|
||||
self::button('discover', 'Die Grundlage entdecken', '/grundlagen'),
|
||||
]),
|
||||
self::section('principles', [
|
||||
self::text('principles-label', '01 / WAS UNS WICHTIG IST'),
|
||||
self::heading('principles-heading', 'Ein guter Auftritt beginnt\nunter der Oberfläche.', 2),
|
||||
['id' => 'principles-grid', 'type' => 'row', 'children' => [
|
||||
self::card('content', '01 — INHALTE', 'Klar aufgebaut.', 'Texte und Gestaltung bleiben getrennt. Ein versionierter Blockbaum bildet die Grundlage, damit sich Inhalte später weiterentwickeln lassen.'),
|
||||
self::card('delivery', '02 — AUSGABE', 'Direkt lesbar.', 'Der Hauptinhalt kommt als vollständiges HTML beim Browser an. Zum Lesen braucht diese Seite kein JavaScript und keine Editor-Bibliothek.'),
|
||||
self::card('control', '03 — KONTROLLE', 'Bewusst veröffentlicht.', 'Entwurf und Veröffentlichung haben eigene Stände. Eine gespeicherte Änderung erscheint erst dann öffentlich, wenn sie veröffentlicht wird.'),
|
||||
]],
|
||||
], 'mint'),
|
||||
self::section('next', [
|
||||
self::text('next-label', '02 / VON DER GRUNDLAGE ZUM WERKZEUG'),
|
||||
self::heading('next-heading', 'Schritt für Schritt.\nMit einem klaren Ziel.', 2),
|
||||
self::text('next-text', 'Diese Seite ist der erste technische Prototyp von Kant CMS. Als Nächstes entsteht der visuelle Editor mit Strukturbaum, Vorschau und Eigenschaften. Das fertige CMS wächst an einer echten Pilotwebsite.'),
|
||||
self::button('progress', 'Den Projektstand ansehen', '/projektstand'),
|
||||
], 'ink'),
|
||||
],
|
||||
],
|
||||
'grundlagen' => self::article('Die Grundlage · Kant CMS', 'Wie Kant CMS Inhalte als Blöcke speichert und Seiten als HTML ausliefert.', 'Ein Fundament für\nveränderbare Websites.', [
|
||||
['Inhalte mit Struktur', 'Eine Seite besteht aus einem versionierten Dokument. Sektionen, Zeilen und Spalten ordnen Überschriften, Texte, Bilder und Links. Jeder Block hat eine stabile Kennung. Text wird bei der Ausgabe automatisch maskiert; frei ausführbares HTML ist kein Inhaltsformat.'],
|
||||
['Ein Entwurf bleibt ein Entwurf', 'Speichern erzeugt einen eigenen Stand. Die öffentliche Route liest ausschließlich die veröffentlichte Revision. Veraltete Schreibstände werden abgewiesen, damit eine ältere Bearbeitung neue Inhalte nicht unbemerkt überschreibt.'],
|
||||
['PHP-Webhosting als Ziel', 'Der Prototyp nutzt Symfony, Twig und Doctrine. Die lokale Installation verwendet SQLite. Für den späteren Hostingbetrieb ist MySQL oder MariaDB vorgesehen. Der öffentlich erreichbare Dokumentenstamm ist ausschließlich das Verzeichnis public.'],
|
||||
['Qualität von Anfang an', 'Semantische Elemente, sichtbarer Tastaturfokus und ein Sprunglink sind bereits Teil der Ausgabe. Automatische Prüfungen begleiten die Entwicklung. Belastbare Qualitätswerte für Kundenwebsites benötigen repräsentative Inhalte und Messungen auf dem tatsächlichen Hosting.'],
|
||||
]),
|
||||
'projektstand' => self::article('Projektstand · Kant CMS', 'Der aktuelle Entwicklungsstand von Kant CMS und die nächsten Schritte zum visuellen Editor.', 'Der erste Schritt\nist eine solide Basis.', [
|
||||
['Jetzt: technische Grundlage', 'Projektregeln und Entwicklungsplan sind abgelegt. Das Grundgerüst speichert Seiten in einer Datenbank und liefert veröffentlichte Blockdokumente als HTML aus. Diese Demonstrationsinhalte gehören zum Prototyp; sie sind keine Kundenwebsite.'],
|
||||
['Als Nächstes: visuell bearbeiten', 'Geplant sind eine Elementbibliothek, ein synchronisierter Strukturbaum, Live-Vorschau und ein Eigenschaftenpanel. Verschieben, Duplizieren, Löschen und Undo/Redo werden zusammen mit dem Speichern und Laden geprüft.'],
|
||||
['Noch zu konkretisieren', 'Die Pilotwebsite, konkrete UX-Builder-Referenzen und die Ausstattung des PHP-Webhostings stehen noch aus. Anmeldung, Medienverwaltung, Formulare, Templates und Plugins folgen in den dafür vorgesehenen Ausbauschritten.'],
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
private static function article(string $title, string $description, string $heading, array $sections): array
|
||||
{
|
||||
$blocks = [self::section('article-hero', [self::text('article-label', 'KANT CMS / ENTWICKLUNG'), self::heading('article-heading', $heading, 1)], 'mint')];
|
||||
$children = [];
|
||||
foreach ($sections as $i => [$label, $text]) {
|
||||
$children[] = self::heading('heading-'.$i, $label, 2);
|
||||
$children[] = self::text('text-'.$i, $text);
|
||||
}
|
||||
$blocks[] = self::section('article-body', $children, 'paper', 'narrow');
|
||||
|
||||
return ['schemaVersion' => 1, 'title' => $title, 'description' => $description, 'blocks' => $blocks];
|
||||
}
|
||||
|
||||
private static function section(string $id, array $children, string $tone = 'paper', string $width = 'normal'): array
|
||||
{
|
||||
return ['id' => $id, 'type' => 'section', 'layout' => ['tone' => $tone, 'width' => $width], 'children' => $children];
|
||||
}
|
||||
|
||||
private static function heading(string $id, string $text, int $level): array
|
||||
{
|
||||
return ['id' => $id, 'type' => 'heading', 'props' => ['text' => str_replace('\\n', ' ', $text), 'level' => $level]];
|
||||
}
|
||||
|
||||
private static function text(string $id, string $text): array
|
||||
{
|
||||
return ['id' => $id, 'type' => 'text', 'props' => ['text' => $text]];
|
||||
}
|
||||
|
||||
private static function button(string $id, string $text, string $href): array
|
||||
{
|
||||
return ['id' => $id, 'type' => 'button', 'props' => ['text' => $text, 'href' => $href]];
|
||||
}
|
||||
|
||||
private static function card(string $id, string $label, string $title, string $text): array
|
||||
{
|
||||
return ['id' => $id, 'type' => 'column', 'children' => [self::text($id.'-label', $label), self::heading($id.'-heading', $title, 3), self::text($id.'-text', $text)]];
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user