mirror of
https://github.com/complexcaresolutions/cms.c2sgmbh.git
synced 2026-03-17 22:04:10 +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>
342 lines
7.3 KiB
Markdown
342 lines
7.3 KiB
Markdown
# Bildoptimierung - Dokumentation
|
|
|
|
## Übersicht
|
|
|
|
Die Media Collection nutzt Sharp für automatische Bildoptimierung. Beim Upload werden automatisch optimierte Versionen in verschiedenen Größen und Formaten erstellt.
|
|
|
|
---
|
|
|
|
## Konfiguration
|
|
|
|
### Sharp Integration
|
|
|
|
Sharp ist in der `payload.config.ts` eingebunden:
|
|
|
|
```typescript
|
|
import sharp from 'sharp'
|
|
|
|
export default buildConfig({
|
|
// ...
|
|
sharp,
|
|
// ...
|
|
})
|
|
```
|
|
|
|
### Media Collection
|
|
|
|
Die Bildoptimierung ist in `src/collections/Media.ts` konfiguriert.
|
|
|
|
---
|
|
|
|
## Image Sizes
|
|
|
|
### WebP-Varianten
|
|
|
|
| Name | Breite | Höhe | Verwendung |
|
|
|------|--------|------|------------|
|
|
| `thumbnail` | 150px | 150px | Admin-Übersichten, kleine Vorschauen |
|
|
| `small` | 400px | auto | Cards, Avatare, Icons |
|
|
| `medium` | 800px | auto | Blog-Vorschauen, Testimonials |
|
|
| `large` | 1200px | auto | Hero-Sections, Vollbild |
|
|
| `xlarge` | 1920px | auto | Full-HD Displays |
|
|
| `2k` | 2560px | auto | Retina/HiDPI Displays |
|
|
| `og` | 1200x630px | fix | Social Media / Open Graph |
|
|
|
|
### AVIF-Varianten (beste Kompression)
|
|
|
|
| Name | Breite | Verwendung |
|
|
|------|--------|------------|
|
|
| `medium_avif` | 800px | Blog-Vorschauen (moderne Browser) |
|
|
| `large_avif` | 1200px | Hero-Sections (moderne Browser) |
|
|
| `xlarge_avif` | 1920px | Full-HD (moderne Browser) |
|
|
|
|
---
|
|
|
|
## Qualitätseinstellungen
|
|
|
|
| Format | Size | Qualität |
|
|
|--------|------|----------|
|
|
| WebP | thumbnail | 80% |
|
|
| WebP | small | 80% |
|
|
| WebP | medium | 82% |
|
|
| WebP | large, xlarge, 2k, og | 85% |
|
|
| AVIF | alle | 70% |
|
|
|
|
Die niedrigere AVIF-Qualität (70%) liefert bei gleicher visueller Qualität kleinere Dateien als WebP bei 85%.
|
|
|
|
---
|
|
|
|
## Fit-Modi
|
|
|
|
| Modus | Beschreibung | Verwendung |
|
|
|-------|--------------|------------|
|
|
| `cover` | Füllt die Größe, schneidet überstehende Bereiche ab | thumbnail, og |
|
|
| `inside` | Passt das Bild ein, behält Seitenverhältnis | alle anderen |
|
|
|
|
### withoutEnlargement
|
|
|
|
Alle Sizes außer `thumbnail` und `og` haben `withoutEnlargement: true`. Das verhindert, dass kleine Bilder künstlich vergrößert werden.
|
|
|
|
---
|
|
|
|
## Fokuspunkt
|
|
|
|
Die Media Collection unterstützt Fokuspunkte (`focalPoint: true`). Damit können Redakteure den wichtigsten Bereich eines Bildes markieren, der beim Cropping erhalten bleibt.
|
|
|
|
Im Admin-Panel:
|
|
1. Bild hochladen
|
|
2. Auf das Bild klicken
|
|
3. Fokuspunkt setzen
|
|
|
|
Die Fokuspunkt-Koordinaten werden in `focal_x` und `focal_y` gespeichert.
|
|
|
|
---
|
|
|
|
## Zusätzliche Felder
|
|
|
|
| Feld | Typ | Beschreibung |
|
|
|------|-----|--------------|
|
|
| `alt` | Text | Alt-Text (Pflichtfeld) |
|
|
| `caption` | Text | Bildunterschrift |
|
|
| `credit` | Text | Fotograf/Copyright |
|
|
| `tags` | Text[] | Schlagwörter für Suche |
|
|
|
|
---
|
|
|
|
## API-Response
|
|
|
|
Beim Abruf eines Media-Dokuments werden alle Sizes zurückgegeben:
|
|
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"alt": "Beispielbild",
|
|
"caption": "Eine Bildunterschrift",
|
|
"credit": "Fotograf Name",
|
|
"url": "/media/original.jpg",
|
|
"width": 4000,
|
|
"height": 3000,
|
|
"mimeType": "image/jpeg",
|
|
"filesize": 2500000,
|
|
"focalX": 50,
|
|
"focalY": 50,
|
|
"sizes": {
|
|
"thumbnail": {
|
|
"url": "/media/original-150x150.webp",
|
|
"width": 150,
|
|
"height": 150,
|
|
"mimeType": "image/webp",
|
|
"filesize": 8500
|
|
},
|
|
"small": {
|
|
"url": "/media/original-400x300.webp",
|
|
"width": 400,
|
|
"height": 300,
|
|
"mimeType": "image/webp",
|
|
"filesize": 25000
|
|
},
|
|
"medium": {
|
|
"url": "/media/original-800x600.webp",
|
|
"width": 800,
|
|
"height": 600,
|
|
"mimeType": "image/webp",
|
|
"filesize": 65000
|
|
},
|
|
"large": {
|
|
"url": "/media/original-1200x900.webp",
|
|
"width": 1200,
|
|
"height": 900,
|
|
"mimeType": "image/webp",
|
|
"filesize": 120000
|
|
},
|
|
"medium_avif": {
|
|
"url": "/media/original-800x600.avif",
|
|
"width": 800,
|
|
"height": 600,
|
|
"mimeType": "image/avif",
|
|
"filesize": 35000
|
|
}
|
|
// ... weitere Sizes
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Frontend-Integration
|
|
|
|
### Responsive Images mit srcset
|
|
|
|
```tsx
|
|
function ResponsiveImage({ media }) {
|
|
const { url, alt, sizes } = media
|
|
|
|
return (
|
|
<picture>
|
|
{/* AVIF für moderne Browser */}
|
|
<source
|
|
type="image/avif"
|
|
srcSet={`
|
|
${sizes.medium_avif?.url} 800w,
|
|
${sizes.large_avif?.url} 1200w,
|
|
${sizes.xlarge_avif?.url} 1920w
|
|
`}
|
|
sizes="(max-width: 800px) 100vw, 50vw"
|
|
/>
|
|
{/* WebP Fallback */}
|
|
<source
|
|
type="image/webp"
|
|
srcSet={`
|
|
${sizes.small?.url} 400w,
|
|
${sizes.medium?.url} 800w,
|
|
${sizes.large?.url} 1200w,
|
|
${sizes.xlarge?.url} 1920w,
|
|
${sizes['2k']?.url} 2560w
|
|
`}
|
|
sizes="(max-width: 800px) 100vw, 50vw"
|
|
/>
|
|
{/* Original als Fallback */}
|
|
<img
|
|
src={url}
|
|
alt={alt}
|
|
loading="lazy"
|
|
/>
|
|
</picture>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Next.js Image Component
|
|
|
|
```tsx
|
|
import Image from 'next/image'
|
|
|
|
function OptimizedImage({ media }) {
|
|
return (
|
|
<Image
|
|
src={media.sizes.large?.url || media.url}
|
|
alt={media.alt}
|
|
width={media.sizes.large?.width || media.width}
|
|
height={media.sizes.large?.height || media.height}
|
|
placeholder="blur"
|
|
blurDataURL={media.sizes.thumbnail?.url}
|
|
/>
|
|
)
|
|
}
|
|
```
|
|
|
|
### Thumbnail für Listen
|
|
|
|
```tsx
|
|
function MediaThumbnail({ media }) {
|
|
return (
|
|
<img
|
|
src={media.sizes.thumbnail?.url || media.url}
|
|
alt={media.alt}
|
|
width={150}
|
|
height={150}
|
|
loading="lazy"
|
|
/>
|
|
)
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Social Media / Open Graph
|
|
|
|
Die `og`-Size (1200x630px) ist optimiert für Social Media Sharing:
|
|
|
|
```tsx
|
|
// In Next.js Metadata
|
|
export async function generateMetadata({ params }) {
|
|
const page = await getPage(params.slug)
|
|
|
|
return {
|
|
openGraph: {
|
|
images: [
|
|
{
|
|
url: page.featuredImage?.sizes?.og?.url,
|
|
width: 1200,
|
|
height: 630,
|
|
},
|
|
],
|
|
},
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Dateispeicherung
|
|
|
|
Alle Bildvarianten werden im `/media`-Verzeichnis gespeichert:
|
|
|
|
```
|
|
/media/
|
|
├── original.jpg # Original
|
|
├── original-150x150.webp # thumbnail
|
|
├── original-400x300.webp # small
|
|
├── original-800x600.webp # medium
|
|
├── original-800x600.avif # medium_avif
|
|
├── original-1200x900.webp # large
|
|
├── original-1200x900.avif # large_avif
|
|
├── original-1920x1440.webp # xlarge
|
|
├── original-1920x1440.avif # xlarge_avif
|
|
├── original-2560x1920.webp # 2k
|
|
└── original-1200x630.webp # og
|
|
```
|
|
|
|
---
|
|
|
|
## Kompressionsvergleich
|
|
|
|
Typische Dateigrößen für ein 4000x3000px Foto:
|
|
|
|
| Format/Size | Dateigröße | Ersparnis |
|
|
|-------------|------------|-----------|
|
|
| Original JPEG | 2.5 MB | - |
|
|
| large (WebP) | ~120 KB | 95% |
|
|
| large (AVIF) | ~70 KB | 97% |
|
|
| medium (WebP) | ~65 KB | 97% |
|
|
| medium (AVIF) | ~35 KB | 99% |
|
|
| thumbnail (WebP) | ~8 KB | 99.7% |
|
|
|
|
---
|
|
|
|
## Browser-Kompatibilität
|
|
|
|
### WebP
|
|
- Chrome 17+
|
|
- Firefox 65+
|
|
- Safari 14+
|
|
- Edge 18+
|
|
|
|
### AVIF
|
|
- Chrome 85+
|
|
- Firefox 93+
|
|
- Safari 16.4+
|
|
- Edge 121+
|
|
|
|
Für ältere Browser wird das Original-Format (JPEG/PNG) als Fallback verwendet.
|
|
|
|
---
|
|
|
|
## Datenbank-Tabellen
|
|
|
|
Die Migration `20251130_143000_media_optimization` erstellt:
|
|
|
|
- Spalten für alle Size-Varianten in `media`
|
|
- Tabelle `media_tags` für Schlagwörter
|
|
|
|
---
|
|
|
|
## Changelog
|
|
|
|
### Version 1.0 (30.11.2025)
|
|
|
|
- Sharp-Integration in payload.config.ts
|
|
- 11 Image Sizes definiert (7 WebP + 3 AVIF + OG)
|
|
- Fokuspunkt-Support aktiviert
|
|
- Zusätzliche Felder: caption, credit, tags
|
|
- Migration für Datenbank-Schema
|