10-04-2026
This commit is contained in:
parent
4d6b4930b2
commit
4bb89aad8c
836 changed files with 52961 additions and 5950 deletions
175
public/_cabinet/_docs/b2in-display-implementation.md
Normal file
175
public/_cabinet/_docs/b2in-display-implementation.md
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# B2in Display – Frontend-Implementation
|
||||
|
||||
**Ziel:** Frontend-Webapp für das B2in Schaufenster-Display (9:16 Portrait, 43–55 Zoll).
|
||||
**Pfad:** `public/_cabinet/b2in/index.html`
|
||||
**Konzept-Basis:** `public/_cabinet/_docs/b2in-displays.md`
|
||||
|
||||
---
|
||||
|
||||
## Ist-Zustand
|
||||
|
||||
Es gibt bereits drei Display-Typen unter `public/_cabinet/`:
|
||||
|
||||
| Typ | Pfad | Status | Beschreibung |
|
||||
|-----|------|--------|-------------|
|
||||
| **Video-Display** | `index.html` | Live, stabil | CABINET-Branding. Videos + Footer-Rotation. API: `/api/display/config` |
|
||||
| **Offers** | `offers/index.html` | Entwickelt, nicht live | CABINET-Branding. iFrame-basierte Slide-Rotation mit `config.json` |
|
||||
| **Info-Tablet** | `info/index.html` | Entwickelt | CABINET-Branding. Store-Status/Öffnungszeiten. API: `/api/cabinet-tablet/status` |
|
||||
| **B2in Display** | `b2in/` | **Neu – wird jetzt gebaut** | B2in-Branding. Playlist mit Videos/Bildern + Text. API: `/api/b2in-display/playlist` |
|
||||
|
||||
---
|
||||
|
||||
## Architektur-Übersicht
|
||||
|
||||
```
|
||||
public/_cabinet/b2in/
|
||||
├── index.html ← Haupt-Webapp (Playlist-Engine + UI)
|
||||
├── b2in-styles.css ← Display-spezifische Styles
|
||||
└── (assets/) ← Medien werden per API/URL referenziert, nicht lokal
|
||||
```
|
||||
|
||||
Shared CSS aus `public/_cabinet/shared/cabinet-base.css` wird **nicht** importiert – das B2in-Display hat ein eigenständiges Branding (dunkel, B2in statt CABINET). Es ist ein komplett eigenes Design-System.
|
||||
|
||||
---
|
||||
|
||||
## Schritte
|
||||
|
||||
### Schritt 1: HTML-Grundgerüst + CSS
|
||||
|
||||
**Datei:** `public/_cabinet/b2in/index.html` + `b2in-styles.css`
|
||||
|
||||
Layout gemäß Konzept (Abschnitt 2.1):
|
||||
|
||||
```
|
||||
┌─────────────────────────┐
|
||||
│ HEADER │ ← B2in-Logo (links) + Claim (rechts)
|
||||
│ B2in · Claim │ Fest, immer sichtbar
|
||||
├─────────────────────────┤
|
||||
│ │
|
||||
│ ┌─────────────────┐ │ ← Gradient oben (dunkel → transparent)
|
||||
│ │ VIDEO / BILD │ │ 16:9 Content-Bereich
|
||||
│ │ (16:9 Media) │ │ object-fit: cover
|
||||
│ └─────────────────┘ │ ← Gradient unten (transparent → dunkel)
|
||||
│ │
|
||||
├─────────────────────────┤
|
||||
│ TEXTFELD │ ← Headline (max 40 Zeichen)
|
||||
│ Headline + Subline │ Subline (max 80 Zeichen)
|
||||
├─────────────────────────┤ Wechselt synchron mit Media
|
||||
│ FOOTER │ ← "Marcel Scheibe" + "b2in.de" + QR-Code
|
||||
│ Name · URL · QR │ Fest, immer sichtbar
|
||||
└─────────────────────────┘
|
||||
```
|
||||
|
||||
**Design-Entscheidungen:**
|
||||
- Dunkler Hintergrund (#0a0a0a) – B2in-Branding, nicht CABINET-weiß
|
||||
- 9:16 Aspect Ratio Container (wie bestehende Displays)
|
||||
- Gradient-Overlays oben/unten über dem Media-Bereich
|
||||
- IBM Plex Sans Font (wie alle Cabinet-Displays)
|
||||
- Akzentfarbe: B2in-Blau (wird aus Branding-Guide übernommen)
|
||||
- Kein CABINET-Logo, kein Accent #009FE3
|
||||
|
||||
### Schritt 2: Playlist-Engine (JavaScript)
|
||||
|
||||
**Klasse:** `B2inDisplayApp`
|
||||
|
||||
Kernfunktionalität:
|
||||
1. **API laden** → `GET /api/b2in-display/playlist` (wird später gebaut, erstmal Mock/Fallback)
|
||||
2. **Playlist sortieren** → nach `sort_order`, nur `is_active === true`
|
||||
3. **Gewichtung anwenden** → 70/30 Immobilien/Möbel-Verteilung berechnen
|
||||
4. **Rotation starten** → Item für Item durchspielen
|
||||
|
||||
Item-Wechsel-Logik:
|
||||
- **Video:** Abspielen bis Ende → nächstes Item
|
||||
- **Bild:** `duration_seconds` abwarten → nächstes Item
|
||||
- **Am Ende der Playlist:** Von vorne beginnen
|
||||
|
||||
### Schritt 3: Video-Handling
|
||||
|
||||
Bewährtes Pattern aus dem bestehenden `index.html` übernehmen:
|
||||
- `autoplay muted playsinline` für Browser-Autoplay-Policy
|
||||
- Memory-Management: `src` leeren + `load()` nach jedem Video
|
||||
- Preloading: Nächstes Item im Hintergrund vorladen
|
||||
- Start-Timeout (10s) → bei Timeout überspringen
|
||||
- Watchdog: Prüft alle 5s ob Video noch läuft
|
||||
- Error-Handling: Bei Fehler → Item überspringen, nie schwarzer Screen
|
||||
|
||||
### Schritt 4: Bild-Handling
|
||||
|
||||
- `<img>` Element mit `object-fit: cover`
|
||||
- Duration aus Item oder globaler `default_image_duration`
|
||||
- Ken-Burns-Effekt (optionaler langsamer Zoom per CSS)
|
||||
- Preload via `new Image()` im Hintergrund
|
||||
|
||||
### Schritt 5: Transitions
|
||||
|
||||
Drei Typen (per CMS-Setting steuerbar):
|
||||
|
||||
| Typ | Umsetzung |
|
||||
|-----|-----------|
|
||||
| `fade` | Opacity 1→0, dann 0→1 |
|
||||
| `crossfade` | Neues Element über dem alten einblenden (empfohlen, Standard) |
|
||||
| `slide` | CSS transform translateX |
|
||||
|
||||
Text-Synchronisation:
|
||||
1. Text fade-out (400ms)
|
||||
2. Neuen Text setzen
|
||||
3. Text fade-in (400ms)
|
||||
4. Startet 200ms vor Media-Wechsel
|
||||
|
||||
### Schritt 6: Polling + Stabilität
|
||||
|
||||
Gleicher Ansatz wie Info-Tablet, aber mit 60s Intervall:
|
||||
|
||||
- **Lightweight Check** alle 60s → `GET /api/b2in-display/check`
|
||||
- **Full Fetch** nur bei Timestamp-Änderung
|
||||
- Laufendes Video/Bild wird zu Ende gespielt, dann neue Playlist
|
||||
- localStorage-Cache als Offline-Fallback
|
||||
- Auto-Reload alle 6 Stunden
|
||||
- Connection-Recovery: 3 Fehler → 5 Min Pause → Retry
|
||||
- 30 Min offline → Page-Reload
|
||||
|
||||
### Schritt 7: Standby-Modus
|
||||
|
||||
Wenn `display_active === false`:
|
||||
- Nur B2in-Logo auf dunklem Hintergrund
|
||||
- Kein Content, kein Textfeld, kein Footer-Text
|
||||
- Polling läuft weiter (wartet auf Aktivierung)
|
||||
|
||||
### Schritt 8: Error-Overlay
|
||||
|
||||
Bei kritischen Fehlern (keine Playlist, kein Media):
|
||||
- Dezentes B2in-Logo auf dunklem Hintergrund
|
||||
- Niemals Browser-Fehler oder weißer Screen
|
||||
- Automatischer Retry im Hintergrund
|
||||
|
||||
---
|
||||
|
||||
## API-Abhängigkeit
|
||||
|
||||
Das Frontend wird **zunächst mit Mock-Daten** gebaut. Die API (`/api/b2in-display/playlist` + `/check`) wird als separater Schritt im Backend implementiert. Das Frontend erkennt automatisch, ob die API verfügbar ist, und fällt auf eingebettete Demo-Daten zurück.
|
||||
|
||||
**Mock-Playlist für Entwicklung:**
|
||||
```javascript
|
||||
const MOCK_PLAYLIST = {
|
||||
settings: {
|
||||
display_active: true,
|
||||
footer_name: "Marcel Scheibe",
|
||||
footer_url: "b2in.de",
|
||||
transition: { type: "crossfade", duration_ms: 800 },
|
||||
default_image_duration: 10
|
||||
},
|
||||
items: [
|
||||
// Demo-Items mit Platzhalter-Medien
|
||||
],
|
||||
updated_at: new Date().toISOString()
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Abgrenzung (was NICHT in diesem Schritt passiert)
|
||||
|
||||
- Kein CMS-Backend (Model, Migration, Controller, Admin-UI) → separater Schritt
|
||||
- Kein Media-Upload → Videos/Bilder werden per URL referenziert
|
||||
- Keine Gewichtungs-Logik im Backend → wird im Frontend berechnet
|
||||
- Keine Änderung am bestehenden Video-Display (`index.html`) → bleibt unberührt
|
||||
Loading…
Add table
Add a link
Reference in a new issue