# Phase 2: Block-System für flexible Seiteninhalte ## Kontext Du arbeitest im Verzeichnis `/home/payload/payload-cms`. Phase 1 ist abgeschlossen - die Collections Pages, Posts, Categories, SocialLinks sowie die Globals SiteSettings und Navigation existieren. ## Aufgabe Erstelle ein Block-System, das flexible Seitengestaltung im Pages-Editor ermöglicht. Die Blöcke werden als `blocks` Field in der Pages Collection integriert. ## Design-Kontext Die Website porwoll.de ist eine seriöse, professionelle Präsenz mit: - Dunklem Theme - Ernsthafter, vertrauenswürdiger Ausstrahlung - Klarer Typografie - Hochwertigen Bildern ## Zu erstellende Dateien ### 1. Block-Definitionen (`src/blocks/`) Erstelle den Ordner `src/blocks/` und folgende Dateien: #### `src/blocks/HeroBlock.ts` Große Hero-Sektion mit Bild und Text. ```typescript Felder: - backgroundImage: upload (Media) - headline: text, required - subline: textarea - alignment: select (left, center, right), default: center - overlay: checkbox, default: true (dunkles Overlay über Bild) - cta: group - text: text - link: text - style: select (primary, secondary, outline) ``` #### `src/blocks/TextBlock.ts` Einfacher Textblock mit Rich-Text. ```typescript Felder: - content: richText (Lexical), required - width: select (narrow, medium, full), default: medium ``` #### `src/blocks/ImageTextBlock.ts` Bild und Text nebeneinander. ```typescript Felder: - image: upload (Media), required - imagePosition: select (left, right), default: left - headline: text - content: richText (Lexical) - cta: group - text: text - link: text ``` #### `src/blocks/CardGridBlock.ts` Raster aus Karten (für Unternehmen, Projekte, etc.). ```typescript Felder: - headline: text - cards: array, minRows: 1, maxRows: 6 - image: upload (Media) - title: text, required - description: textarea - link: text - linkText: text, default: 'mehr' - columns: select (2, 3, 4), default: 3 ``` #### `src/blocks/QuoteBlock.ts` Hervorgehobenes Zitat. ```typescript Felder: - quote: textarea, required - author: text - role: text - image: upload (Media) (optional, für Autorenbild) - style: select (simple, highlighted, with-image), default: simple ``` #### `src/blocks/CTABlock.ts` Call-to-Action Sektion. ```typescript Felder: - headline: text, required - description: textarea - buttons: array, maxRows: 2 - text: text, required - link: text, required - style: select (primary, secondary, outline), default: primary - backgroundColor: select (dark, light, accent), default: dark ``` #### `src/blocks/ContactFormBlock.ts` Kontaktformular-Einbettung. ```typescript Felder: - headline: text, default: 'Kontakt' - description: textarea - recipientEmail: email, default: 'info@porwoll.de' - showPhone: checkbox, default: true - showAddress: checkbox, default: true - showSocials: checkbox, default: true ``` #### `src/blocks/TimelineBlock.ts` Zeitstrahl für Lebenslauf/Geschichte. ```typescript Felder: - headline: text - events: array, minRows: 1 - year: text, required - title: text, required - description: textarea - image: upload (Media) ``` #### `src/blocks/DividerBlock.ts` Einfacher Trenner zwischen Sektionen. ```typescript Felder: - style: select (line, space, dots), default: space - spacing: select (small, medium, large), default: medium ``` #### `src/blocks/VideoBlock.ts` Video-Einbettung (YouTube/Vimeo). ```typescript Felder: - videoUrl: text, required (YouTube oder Vimeo URL) - caption: text - aspectRatio: select (16:9, 4:3, 1:1), default: 16:9 ``` ### 2. Block-Index (`src/blocks/index.ts`) Exportiere alle Blöcke zentral: ```typescript export { HeroBlock } from './HeroBlock' export { TextBlock } from './TextBlock' export { ImageTextBlock } from './ImageTextBlock' export { CardGridBlock } from './CardGridBlock' export { QuoteBlock } from './QuoteBlock' export { CTABlock } from './CTABlock' export { ContactFormBlock } from './ContactFormBlock' export { TimelineBlock } from './TimelineBlock' export { DividerBlock } from './DividerBlock' export { VideoBlock } from './VideoBlock' ``` ### 3. Pages Collection aktualisieren (`src/collections/Pages.ts`) Ersetze das `content` Feld durch ein `layout` Blocks-Feld: ```typescript { name: 'layout', type: 'blocks', blocks: [ HeroBlock, TextBlock, ImageTextBlock, CardGridBlock, QuoteBlock, CTABlock, ContactFormBlock, TimelineBlock, DividerBlock, VideoBlock, ], } ``` Behalte das bestehende `hero` Feld für die Standard-Hero-Sektion, aber das `layout` Feld ermöglicht flexible Inhalte darunter. ### 4. Posts Collection aktualisieren (`src/collections/Posts.ts`) Füge optional auch Blocks zum Posts-Content hinzu, oder behalte Rich-Text für einfachere Blog-Posts. Empfehlung: Behalte Rich-Text für Posts, da Blog-Artikel primär Text sind. ## Block-Struktur Template Jeder Block sollte dieser Struktur folgen: ```typescript import type { Block } from 'payload' export const BlockName: Block = { slug: 'block-name', labels: { singular: 'Block Name', plural: 'Block Names', }, fields: [ // Felder hier ], } ``` ## Umsetzungsschritte 1. Erstelle `src/blocks/` Verzeichnis 2. Erstelle alle Block-Dateien 3. Erstelle `src/blocks/index.ts` 4. Aktualisiere `src/collections/Pages.ts` mit dem Blocks-Feld 5. Generiere TypeScript-Types (siehe Prettier-Workaround unten) 6. Führe aus: `pnpm payload migrate:create` 7. Führe aus: `pnpm payload migrate` 8. Führe aus: `pnpm build` 9. Starte neu: `pm2 restart payload` ## Prettier-Workaround für generate:types Es gibt ein bekanntes Problem: `pnpm payload generate:types` ignoriert die Projekt-Prettier-Konfiguration und kann zu Konflikten führen (GitHub PR #11124, Stand: offen). ### Lösung: Prettier-Konfiguration anlegen **Schritt 1:** Erstelle eine kompatible `.prettierrc` im Projektroot: ```bash cat > /home/payload/payload-cms/.prettierrc << 'EOF' { "singleQuote": true, "trailingComma": "es5", "tabWidth": 2, "semi": false, "printWidth": 100 } EOF ``` **Schritt 2:** Installiere Prettier falls nicht vorhanden: ```bash pnpm add -D prettier ``` **Schritt 3:** Generiere Types und formatiere: ```bash pnpm payload generate:types pnpm prettier --write src/payload-types.ts ``` ### Alternative bei Fehlern Falls `generate:types` weiterhin fehlschlägt, Types manuell in `src/payload-types.ts` ergänzen: 1. Öffne die bestehende `src/payload-types.ts` 2. Füge die neuen Block-Interfaces hinzu (HeroBlock, TextBlock, etc.) 3. Aktualisiere das `Page` Interface mit dem `layout` Feld Beispiel für manuelle Block-Types: ```typescript export interface HeroBlock { blockType: 'hero-block' backgroundImage?: string | Media | null headline: string subline?: string | null alignment?: 'left' | 'center' | 'right' | null overlay?: boolean | null cta?: { text?: string | null link?: string | null style?: 'primary' | 'secondary' | 'outline' | null } id?: string | null } // ... weitere Block-Interfaces ``` ## Wichtige Hinweise - Nutze `type: 'blocks'` für das Layout-Feld - Alle Blöcke müssen als `Block` Type aus 'payload' importiert werden - Labels auf Deutsch setzen für bessere Admin-UX - Bei Fehlern mit Prettier: Types manuell anpassen wie in Phase 1 ## Erfolgskriterien Nach Abschluss: 1. Im Admin unter Pages → [Seite bearbeiten] erscheint ein "Layout" Feld 2. Das Layout-Feld zeigt alle 10 Block-Typen zur Auswahl 3. Blöcke können hinzugefügt, sortiert und bearbeitet werden 4. Server läuft ohne Fehler ## Test 1. Gehe zu https://pl.c2sgmbh.de/admin 2. Erstelle eine neue Page 3. Scrolle zum "Layout" Bereich 4. Klicke "Add Block" 5. Alle 10 Block-Typen sollten verfügbar sein 6. Füge einen HeroBlock hinzu und speichere 7. Prüfe in der Datenbank: `SELECT * FROM pages;`