cms.c2sgmbh/docs/Prompt phase2 blocks.md
Martin Porwoll a88e4f60d0 test: add E2E and integration tests with documentation
Tests:
- Update frontend.e2e.spec.ts with locale testing
- Add search.e2e.spec.ts for search functionality
- Add i18n.int.spec.ts for localization tests
- Add search.int.spec.ts for search integration
- Update playwright.config.ts

Documentation:
- Add CLAUDE.md with project instructions
- Add docs/ directory with detailed documentation
- Add scripts/ for utility scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 08:19:52 +00:00

7.7 KiB

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.

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.

Felder:
- content: richText (Lexical), required
- width: select (narrow, medium, full), default: medium

src/blocks/ImageTextBlock.ts

Bild und Text nebeneinander.

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.).

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.

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.

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.

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.

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.

Felder:
- style: select (line, space, dots), default: space
- spacing: select (small, medium, large), default: medium

src/blocks/VideoBlock.ts

Video-Einbettung (YouTube/Vimeo).

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:

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:

{
  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:

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:

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:

pnpm add -D prettier

Schritt 3: Generiere Types und formatiere:

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:

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;