mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 19:44:12 +00:00
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>
323 lines
7.7 KiB
Markdown
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;`
|