Theming-System
Inhalt
- Die 6 Ebenen
- Ebene 1: Primitive Tokens
- Ebene 2: Semantische Tokens
- Ebene 3: Admin Live-Editor
- Ebene 4: Preset-Themes
- Ebene 5: Custom CSS
- Ebene 6: Layout-Blöcke
- Live-Update-Mechanismus
- Token-Mapping-Beispiel
- Verfügbare Presets
- Logo-Filter-Presets
- Custom-CSS-Tipps
- Hintergrundfarbverlauf auf der Seite
- Schrift-Override
- Karten-Radius anpassen
- Vollbreiter Hero-Hintergrund
ITSWEBER Play besitzt eine 6-Ebenen-Token-Architektur für Live-Theme-Bearbeitung ohne Seitenreloads. Jede visuelle Eigenschaft — Farben, Radien, Schatten, Schriften — durchläuft eine strukturierte Kette vom Rohwert bis zum gerenderten Pixel.
Die 6 Ebenen
Ebene 1: Primitive Tokens
Speicherort: packages/theme/tokens.json
Rohwerte ohne semantische Bedeutung: Farben, Schriftfamilien, Rahmenradien, Schattendefinitionen. Diese bilden das Fundament — sie werden niemals direkt in Komponenten verwendet. Komponenten referenzieren immer semantische Tokens (Ebene 2).
{
"color": {
"gray-900": "#0f0f0f",
"gray-800": "#1a1a1a",
"gray-100": "#f5f5f5",
"brand-500": "#e05c1a",
"brand-600": "#c44f14",
"red-500": "#ef4444",
"yellow-400": "#facc15"
},
"radius": {
"sm": "0.25rem",
"md": "0.5rem",
"lg": "1rem",
"full": "9999px"
},
"shadow": {
"card": "0 2px 8px rgba(0,0,0,0.4)",
"overlay": "0 8px 32px rgba(0,0,0,0.6)"
},
"font": {
"sans": "'Inter', system-ui, sans-serif",
"mono": "'JetBrains Mono', monospace"
}
}
Ebene 2: Semantische Tokens
Speicherort: packages/theme/src/semantic.ts
Semantische Tokens ordnen benannte Rollen — bg, fg, brand, danger, warning — den Primitives zu. Tailwind-Klassen und Komponentenstile referenzieren ausschließlich diese Tokens, niemals rohe Hex-Werte.
| Semantischer Token | Rolle | Zeigt auf (Dark-Standard) |
|---|---|---|
--color-bg |
Seitenhintergrund | color.gray-900 |
--color-surface |
Karten-/Panel-Hintergrund | color.gray-800 |
--color-fg |
Primärer Text | color.gray-100 |
--color-fg-muted |
Sekundärer Text | color.gray-400 |
--color-brand |
Akzent / Interaktiv | color.brand-500 |
--color-brand-hover |
Hover-Zustand | color.brand-600 |
--color-danger |
Fehler, destruktive Aktionen | color.red-500 |
--color-warning |
Warnungen | color.yellow-400 |
--radius-card |
Karten-Eckenradius | radius.md |
--shadow-card |
Karten-Elevation | shadow.card |
// packages/theme/src/semantic.ts (Auszug)
export const semanticDark: SemanticTokens = {
'color-bg': tokens.color['gray-900'],
'color-surface': tokens.color['gray-800'],
'color-fg': tokens.color['gray-100'],
'color-brand': tokens.color['brand-500'],
'color-danger': tokens.color['red-500'],
'radius-card': tokens.radius['md'],
};
Ebene 3: Admin Live-Editor
Pfad: /admin/theme
Eine Colorpicker- und Schieberegler-Oberfläche ermöglicht Admins die Anpassung semantischer Tokens zur Laufzeit. Änderungen werden:
- In der Datenbanktabelle
theme_settings.tokens_overridegespeichert - Per WebSocket an alle verbundenen Clients übertragen
Kein Deployment oder Neustart erforderlich. Siehe Live-Update-Mechanismus weiter unten.
Ebene 4: Preset-Themes
Eingebaute benannte Presets, die den vollständigen Satz semantischer Tokens abdecken. Im Admin-Panel per Klick umschaltbar. Eigene Presets können erstellt und in der Datenbank gespeichert werden.
| Preset | Beschreibung | Ideal für |
|---|---|---|
itsweber-dark |
Standard-Dark-Theme mit orangem Marken-Akzent | Allgemeine Nutzung |
itsweber-light |
Heller Hintergrund, dunkler Text, oranger Akzent | Helle Umgebungen |
high-contrast |
Maximaler Vordergrund-/Hintergrundkontrast | Barrierefreiheit |
retro |
Warme Bernsteintöne, Serif-ähnliche Überschriften | Persönliche/Nischen-Instanzen |
Ebene 5: Custom CSS
Freies CSS-Eingabefeld in der Admin-Sandbox. Wird nach allen Token-Ebenen angewendet und bietet volle Override-Möglichkeit. Merkmale:
- Versioniert: Letzte 20 Revisionen werden gespeichert, jede einzeln wiederherstellbar
- Validiert: Syntax wird vor der Anwendung geprüft; ungültiges CSS wird mit einer Fehlermeldung abgelehnt
- Scoped: Innerhalb eines einzelnen
<style>-Tags angewendet, keine Framework-Klassen erforderlich
Siehe Custom-CSS-Tipps für häufige Muster.
Ebene 6: Layout-Blöcke
Startseite und Landing-Pages setzen sich aus per Drag-and-drop sortierbaren Blöcken im Admin-Panel zusammen. Verfügbare Block-Typen:
| Block | Beschreibung |
|---|---|
| Hero | Vollbreites Banner mit Titel, Untertitel und CTA-Button |
| Category-Chips | Scrollbare Kategoriefilter-Zeile |
| Video-Grid | Konfigurierbares Raster aus aktuellen/hervorgehobenen Videos |
| Channel-Spotlight | Hervorgehobene Kanalkartenzeile |
| CTA-Banner | Call-to-Action-Streifen mit eigenem Text und Link |
| Custom-HTML | Freies HTML-Block (bereinigt) |
Drag-and-drop-Neuordnung wird unterstützt. Änderungen treten sofort ohne Seitenreload in Kraft.
Live-Update-Mechanismus
Wenn ein Admin eine Theme-Änderung speichert, wird die Aktualisierung sofort an alle offenen Browser-Sessions weitergegeben:
Admin-Änderung → tRPC theme.update → DB-Speicherung + WebSocket-Broadcast
Frontend: ersetzt <style id="theme-vars"> mit neuen CSS-Variablen
Ergebnis: Sofortiges Update, kein React-Rerender nötig
Das Frontend lauscht auf einem dedizierten WebSocket-Kanal. Beim Empfang eines theme.updated-Events tauscht es den Inhalt des <style id="theme-vars">-Elements aus. Da CSS-Variablen kaskadieren, aktualisiert sich jedes Element, das diese Variablen verwendet, an Ort und Stelle — ohne Komponenten-State-Änderung, ohne Navigation.
Token-Mapping-Beispiel
// tokens.json (Primitives)
{
"color": {
"brand-500": "#e05c1a"
}
}
// semantic.ts (Semantisches Mapping)
'color-brand': tokens.color['brand-500']
// → erzeugt: --color-brand: #e05c1a
/* Komponentenverwendung */
.btn-primary {
background-color: var(--color-brand);
}
.btn-primary:hover {
background-color: var(--color-brand-hover);
}
Ein Admin, der color-brand im Live-Editor auf #3b82f6 (Blau) ändert, schreibt { "color-brand": "#3b82f6" } in theme_settings.tokens_override, was zur Renderzeit über die Standard-Semantik-Ebene gemergt wird.
Verfügbare Presets
| Name | Beschreibung | Ideal für |
|---|---|---|
itsweber-dark |
Standard-Dark mit orangem Akzent | Allgemeine Nutzung |
itsweber-light |
Hell, klarer Kontrast, oranger Akzent | Helle Umgebungen, Büros |
high-contrast |
Maximaler Kontrast, WCAG-AA-konform | Barrierefreiheit |
retro |
Bernstein-/Erdtöne, warme Typografie | Persönliche oder Nischen-Instanzen |
Logo-Filter-Presets
Das Instanz-Logo unterstützt 10 CSS-Filter-Presets, angewendet über var(--logo-filter). Dies ermöglicht eine Anpassung des Logos an helle/dunkle Hintergründe ohne separate Bild-Assets.
| Preset | CSS-Filter-Wert | Verwendungszweck |
|---|---|---|
| none | none |
Standard — keine Änderung |
| drop-shadow | drop-shadow(0 2px 4px rgba(0,0,0,0.6)) |
Tiefe auf dunklen Hintergründen |
| brightness-up | brightness(1.3) |
Aufhellen für Dark-Themes |
| brightness-down | brightness(0.7) |
Abdunkeln für Light-Themes |
| saturate | saturate(2) |
Farbsättigung verstärken |
| desaturate | saturate(0.3) |
Gedämpfter, monochromer Effekt |
| invert | invert(1) |
Vollständige Farbumkehr |
| grayscale | grayscale(1) |
Schwarz-Weiß-Logo |
| sepia | sepia(0.8) |
Warmer Vintage-Ton |
| contrast | contrast(1.5) |
Höherer Kontrast an Kanten |
Custom-CSS-Tipps
Hintergrundfarbverlauf auf der Seite
body {
background: linear-gradient(135deg, var(--color-bg) 0%, #1a0a00 100%);
}
Schrift-Override
:root {
--font-sans: 'Nunito', system-ui, sans-serif;
}
Karten-Radius anpassen
:root {
--radius-card: 1.5rem;
}
Vollbreiter Hero-Hintergrund
.hero-block {
background-image: url('/api/assets/hero-bg.jpg');
background-size: cover;
background-position: center;
}
Sicherheit: Custom CSS ist auf den eigenen Origin der Instanz beschränkt. @import-Regeln, die auf externe Origins zeigen, werden entfernt. JavaScript innerhalb von <style>-Tags wird nicht ausgeführt. Ungültiges CSS wird vor dem Speichern abgelehnt.
© Benjamin Weber · ITSWEBER — play.itsweber.net · GitHub