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>
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
- Erstelle
src/blocks/Verzeichnis - Erstelle alle Block-Dateien
- Erstelle
src/blocks/index.ts - Aktualisiere
src/collections/Pages.tsmit dem Blocks-Feld - Generiere TypeScript-Types (siehe Prettier-Workaround unten)
- Führe aus:
pnpm payload migrate:create - Führe aus:
pnpm payload migrate - Führe aus:
pnpm build - 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:
- Öffne die bestehende
src/payload-types.ts - Füge die neuen Block-Interfaces hinzu (HeroBlock, TextBlock, etc.)
- Aktualisiere das
PageInterface mit demlayoutFeld
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
BlockType 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:
- Im Admin unter Pages → [Seite bearbeiten] erscheint ein "Layout" Feld
- Das Layout-Feld zeigt alle 10 Block-Typen zur Auswahl
- Blöcke können hinzugefügt, sortiert und bearbeitet werden
- Server läuft ohne Fehler
Test
- Gehe zu https://pl.c2sgmbh.de/admin
- Erstelle eine neue Page
- Scrolle zum "Layout" Bereich
- Klicke "Add Block"
- Alle 10 Block-Typen sollten verfügbar sein
- Füge einen HeroBlock hinzu und speichere
- Prüfe in der Datenbank:
SELECT * FROM pages;