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

323 lines
7.7 KiB
Markdown

# 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;`