UI Theming Skill
One-time UI theming skill. Sets up design system (theme, tokens, typography). Run ONCE at project start before implementing features.
From byt8npx claudepluginhub byteagenten/byteagenten-marketplace --plugin byt8This skill uses the workspace's default tool permissions.
theme-showcase.pdfthemes/arctic-frost.mdthemes/botanical-garden.mdthemes/desert-rose.mdthemes/forest-canopy.mdthemes/golden-hour.mdthemes/midnight-galaxy.mdthemes/modern-minimalist.mdthemes/ocean-depths.mdthemes/sunset-boulevard.mdthemes/tech-innovation.mdUI Theming Skill
Initialize the design system. This skill should be run ONCE at project start to set up:
- Color theme selection
- Design token generation
- Typography system
- SCSS structure
Usage
/ui-theming
Workflow
Step 0: Check Existing Design System
Before creating files, check if a design system already exists:
ls frontend/src/styles/tokens/ 2>/dev/null
If directory exists with files, show:
⚠️ Design System bereits vorhanden!
Gefundene Dateien:
- _colors.scss
- _typography.scss
- [weitere Dateien...]
Optionen:
1. Abbrechen (bestehende Dateien behalten)
2. Überschreiben (Theme neu generieren)
3. Nur Theme-Preview generieren (keine Änderungen)
Wie möchten Sie fortfahren?
- Option 1: Exit skill, no changes
- Option 2: Continue with Step 1 (files will be overwritten)
- Option 3: Skip to Step 7 (Theme-Auswahl + Preview generieren, keine SCSS-Änderungen)
If directory does not exist: Continue with Step 1.
Step 1: Theme Selection
Present the available themes:
Available Themes:
1. Ocean Depths - Professional maritime (Blue/Teal)
2. Sunset Boulevard - Warm vibrant (Orange/Pink)
3. Forest Canopy - Natural earth tones (Green/Brown)
4. Modern Minimalist - Clean grayscale (Gray/Black)
5. Golden Hour - Rich autumnal (Gold/Orange)
6. Arctic Frost - Cool crisp winter (Light Blue/White)
7. Desert Rose - Soft sophisticated (Pink/Beige)
8. Tech Innovation - Bold modern tech (Blue/Purple) [RECOMMENDED]
9. Botanical Garden - Fresh organic (Green/Cream)
10. Midnight Galaxy - Dramatic cosmic (Dark Purple/Blue)
Which theme would you like for your project?
Step 2: Read Selected Theme
After user selects a theme, read the theme file:
Read: ${CLAUDE_PLUGIN_ROOT}/skills/ui-theming/themes/[selected-theme].md
Extract:
- Primary color
- Secondary color
- Font family
- Font weights
Step 3: Farbvarianten berechnen
Aus den Theme-Farben (Primary + Accent) die Light/Dark-Varianten ableiten.
Algorithmus (HSL-Farbraum):
| Variante | Berechnung |
|---|---|
primary-light | Lightness +20%, Saturation -10% |
primary-dark | Lightness -20%, Saturation +5% |
accent-light | Lightness +20%, Saturation -10% |
accent-dark | Lightness -20%, Saturation +5% |
Beispiel: Primary #0066ff (HSL: 216°, 100%, 50%)
→ Light: HSL(216°, 90%, 70%) = #5c9aff
→ Dark: HSL(216°, 100%, 30%) = #003d99
Contrast-Farbe: Weiß (#ffffff) wenn Lightness < 50%, sonst Schwarz (#000000).
Dark-Mode Semantic Colors (fest definiert):
| Token | Light Mode | Dark Mode |
|---|---|---|
| success | #4caf50 | #81c784 |
| warning | #ff9800 | #ffb74d |
| error | #f44336 | #e57373 |
| info | #2196f3 | #64b5f6 |
Step 4: Create Token Files
Create the following modular structure in frontend/src/styles/tokens/:
frontend/src/styles/
├── tokens/
│ ├── _colors.scss # Color palette + light/dark mode
│ ├── _typography.scss # Font system as CSS Custom Properties
│ ├── _spacing.scss # 8pt grid + semantic aliases
│ ├── _elevation.scss # Material elevation shadows
│ ├── _breakpoints.scss # Responsive breakpoints + mixins
│ └── _index.scss # Central export (@forward + theme mixins)
└── styles.scss # Root file (@use tokens)
tokens/_colors.scss
// Color System - CSS Custom Properties
// Generated by /ui-theming
// Theme: [Selected Theme]
@mixin colors-light {
// Brand Colors (from selected theme)
--color-primary: [primary-hex];
--color-primary-light: [primary-light-hex];
--color-primary-dark: [primary-dark-hex];
--color-primary-contrast: #ffffff;
--color-accent: [accent-hex];
--color-accent-light: [accent-light-hex];
--color-accent-dark: [accent-dark-hex];
--color-accent-contrast: #ffffff;
// Semantic Colors
--color-success: #4caf50;
--color-warning: #ff9800;
--color-error: #f44336;
--color-info: #2196f3;
// Neutral Palette
--color-gray-50: #fafafa;
--color-gray-100: #f5f5f5;
--color-gray-200: #eeeeee;
--color-gray-300: #e0e0e0;
--color-gray-400: #bdbdbd;
--color-gray-500: #9e9e9e;
--color-gray-600: #757575;
--color-gray-700: #616161;
--color-gray-800: #424242;
--color-gray-900: #212121;
// Surface & Background
--color-background: #fafafa;
--color-surface: #ffffff;
--color-surface-variant: #f5f5f5;
// Text
--color-text-primary: rgba(0, 0, 0, 0.87);
--color-text-secondary: rgba(0, 0, 0, 0.6);
--color-text-disabled: rgba(0, 0, 0, 0.38);
--color-text-on-primary: #ffffff;
// Borders
--color-divider: rgba(0, 0, 0, 0.12);
--color-border: rgba(0, 0, 0, 0.23);
}
@mixin colors-dark {
--color-primary: [primary-light-hex];
--color-primary-light: [primary-hex];
--color-primary-dark: [primary-dark-hex];
--color-primary-contrast: #000000;
--color-accent: [accent-light-hex];
--color-accent-contrast: #000000;
--color-success: #81c784;
--color-warning: #ffb74d;
--color-error: #e57373;
--color-info: #64b5f6;
--color-gray-50: #212121;
--color-gray-100: #303030;
--color-gray-200: #424242;
--color-gray-300: #616161;
--color-gray-400: #757575;
--color-gray-500: #9e9e9e;
--color-gray-600: #bdbdbd;
--color-gray-700: #e0e0e0;
--color-gray-800: #eeeeee;
--color-gray-900: #fafafa;
--color-background: #121212;
--color-surface: #1e1e1e;
--color-surface-variant: #2c2c2c;
--color-text-primary: rgba(255, 255, 255, 0.87);
--color-text-secondary: rgba(255, 255, 255, 0.6);
--color-text-disabled: rgba(255, 255, 255, 0.38);
--color-text-on-primary: #000000;
--color-divider: rgba(255, 255, 255, 0.12);
--color-border: rgba(255, 255, 255, 0.23);
}
tokens/_typography.scss
// Typography System - CSS Custom Properties
// Generated by /ui-theming
@mixin typography {
// Font Families (from selected theme)
--font-family-base: '[theme-font]', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-family-mono: 'Roboto Mono', 'Consolas', monospace;
// Font Sizes (Modular Scale 1.25)
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-size-5xl: 3rem;
// Font Weights
--font-weight-light: 300;
--font-weight-regular: 400;
--font-weight-medium: 500;
--font-weight-bold: 700;
// Line Heights
--line-height-tight: 1.25;
--line-height-base: 1.5;
--line-height-relaxed: 1.75;
// Letter Spacing
--letter-spacing-tight: -0.025em;
--letter-spacing-normal: 0;
--letter-spacing-wide: 0.025em;
// Semantic Typography Tokens
--font-heading-1: var(--font-weight-light) var(--font-size-5xl) / var(--line-height-tight) var(--font-family-base);
--font-heading-2: var(--font-weight-light) var(--font-size-4xl) / var(--line-height-tight) var(--font-family-base);
--font-heading-3: var(--font-weight-regular) var(--font-size-3xl) / var(--line-height-tight) var(--font-family-base);
--font-heading-4: var(--font-weight-regular) var(--font-size-2xl) / var(--line-height-base) var(--font-family-base);
--font-heading-5: var(--font-weight-medium) var(--font-size-xl) / var(--line-height-base) var(--font-family-base);
--font-heading-6: var(--font-weight-medium) var(--font-size-lg) / var(--line-height-base) var(--font-family-base);
--font-body-1: var(--font-weight-regular) var(--font-size-base) / var(--line-height-base) var(--font-family-base);
--font-body-2: var(--font-weight-regular) var(--font-size-sm) / var(--line-height-base) var(--font-family-base);
--font-caption: var(--font-weight-regular) var(--font-size-xs) / var(--line-height-base) var(--font-family-base);
}
tokens/_spacing.scss
// Spacing System - 8pt Grid
// Generated by /ui-theming
@mixin spacing {
// Base Scale
--spacing-0: 0;
--spacing-1: 0.25rem; // 4px
--spacing-2: 0.5rem; // 8px
--spacing-3: 0.75rem; // 12px
--spacing-4: 1rem; // 16px
--spacing-5: 1.25rem; // 20px
--spacing-6: 1.5rem; // 24px
--spacing-8: 2rem; // 32px
--spacing-10: 2.5rem; // 40px
--spacing-12: 3rem; // 48px
--spacing-16: 4rem; // 64px
// Semantic Aliases
--spacing-page-x: var(--spacing-6);
--spacing-page-y: var(--spacing-8);
--spacing-section: var(--spacing-8);
--spacing-card: var(--spacing-4);
--spacing-inline: var(--spacing-2);
// Border Radius
--radius-none: 0;
--radius-sm: 0.125rem;
--radius-md: 0.25rem;
--radius-lg: 0.5rem;
--radius-xl: 1rem;
--radius-full: 9999px;
// Component Tokens
--card-padding: var(--spacing-4);
--card-radius: var(--radius-md);
--button-padding-x: var(--spacing-4);
--button-padding-y: var(--spacing-2);
--button-radius: var(--radius-md);
--input-padding-x: var(--spacing-4);
--input-padding-y: var(--spacing-2);
--input-radius: var(--radius-md);
--table-cell-padding: var(--spacing-3) var(--spacing-4);
--toolbar-height: 4rem;
--sidenav-width: 16rem;
}
tokens/_elevation.scss
// Elevation & Shadows
// Generated by /ui-theming
@mixin elevation {
// Material Design Elevation
--elevation-0: none;
--elevation-1: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
--elevation-2: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
--elevation-4: 0 2px 4px -1px rgba(0,0,0,.2), 0 4px 5px 0 rgba(0,0,0,.14), 0 1px 10px 0 rgba(0,0,0,.12);
--elevation-8: 0 5px 5px -3px rgba(0,0,0,.2), 0 8px 10px 1px rgba(0,0,0,.14), 0 3px 14px 2px rgba(0,0,0,.12);
--elevation-16: 0 8px 10px -5px rgba(0,0,0,.2), 0 16px 24px 2px rgba(0,0,0,.14), 0 6px 30px 5px rgba(0,0,0,.12);
// Semantic Aliases
--shadow-card: var(--elevation-1);
--shadow-dropdown: var(--elevation-4);
--shadow-modal: var(--elevation-16);
// Transitions
--transition-fast: 150ms ease-in-out;
--transition-base: 250ms ease-in-out;
--transition-slow: 350ms ease-in-out;
// Z-Index Scale
--z-dropdown: 1000;
--z-sticky: 1020;
--z-fixed: 1030;
--z-modal-backdrop: 1040;
--z-modal: 1050;
--z-popover: 1060;
--z-tooltip: 1070;
}
tokens/_breakpoints.scss
// Responsive Breakpoints
// Generated by /ui-theming
$breakpoint-sm: 600px;
$breakpoint-md: 960px;
$breakpoint-lg: 1280px;
$breakpoint-xl: 1920px;
// Breakpoint Mixins (use in components)
@mixin sm { @media (min-width: $breakpoint-sm) { @content; } }
@mixin md { @media (min-width: $breakpoint-md) { @content; } }
@mixin lg { @media (min-width: $breakpoint-lg) { @content; } }
@mixin xl { @media (min-width: $breakpoint-xl) { @content; } }
@mixin below-sm { @media (max-width: ($breakpoint-sm - 1)) { @content; } }
@mixin below-md { @media (max-width: ($breakpoint-md - 1)) { @content; } }
@mixin below-lg { @media (max-width: ($breakpoint-lg - 1)) { @content; } }
tokens/_index.scss
// Token System Entry Point
// Generated by /ui-theming
// Uses @forward/@use (modern SCSS module system)
@forward 'breakpoints';
@use 'colors';
@use 'typography';
@use 'spacing';
@use 'elevation';
// All tokens combined
@mixin all-tokens {
@include typography.typography;
@include spacing.spacing;
@include elevation.elevation;
}
// Theme: Light (default)
@mixin theme-light {
@include colors.colors-light;
@include all-tokens;
}
// Theme: Dark
@mixin theme-dark {
@include colors.colors-dark;
@include all-tokens;
}
Step 5: Update styles.scss
Ensure frontend/src/styles.scss uses the token system:
@use 'styles/tokens' as tokens;
// Apply light theme by default
:root {
@include tokens.theme-light;
}
// Dark mode support
@media (prefers-color-scheme: dark) {
:root {
@include tokens.theme-dark;
}
}
// Manual dark mode toggle class
.dark-theme {
@include tokens.theme-dark;
}
Step 6: Verify Setup
# Check file structure
ls -la frontend/src/styles/tokens/
# Build to verify no errors
cd frontend && npm run build
Step 7: Generate Theme Preview
7.1: Theme bestimmen
Wenn aus Step 6 kommend (voller Workflow): → Das in Step 1 gewählte Theme verwenden, keine erneute Abfrage.
Wenn direkt zu Step 7 gesprungen (Option 3 aus Step 0): → Theme-Auswahl anzeigen:
Welches Theme möchten Sie in der Preview sehen?
1. Ocean Depths - Professional maritime (Blue/Teal)
2. Sunset Boulevard - Warm vibrant (Orange/Pink)
3. Forest Canopy - Natural earth tones (Green/Brown)
4. Modern Minimalist - Clean grayscale (Gray/Black)
5. Golden Hour - Rich autumnal (Gold/Orange)
6. Arctic Frost - Cool crisp winter (Light Blue/White)
7. Desert Rose - Soft sophisticated (Pink/Beige)
8. Tech Innovation - Bold modern tech (Blue/Purple)
9. Botanical Garden - Fresh organic (Green/Cream)
10. Midnight Galaxy - Dramatic cosmic (Dark Purple/Blue)
Theme-Nummer eingeben:
7.2: Projekt-Elemente analysieren
Scanne das Projekt nach verwendeten UI-Elementen (Material UND native HTML):
# 1. Angular Material Komponenten
grep -roh "mat-[a-z-]*" frontend/src/app --include="*.html" | sort | uniq -c | sort -rn
# 2. Native HTML Elemente
grep -roE "<(table|form|input|select|textarea|button|ul|ol|nav|header|footer|aside|dialog|details|summary)[^>]*>" frontend/src/app --include="*.html" | sort | uniq -c | sort -rn
# 3. Custom Components (app-*)
grep -roh "app-[a-z-]*" frontend/src/app --include="*.html" | sort | uniq -c | sort -rn
Beispiel-Output:
=== Angular Material ===
45 mat-button
34 mat-form-field
12 mat-table
=== Native HTML ===
28 <table
56 <input
23 <select
15 <button
12 <ul
8 <nav
4 <dialog
=== Custom Components ===
18 app-user-card
9 app-status-badge
5 app-data-grid
Element-Mapping für Preview:
| Element (Material ODER Native) | Preview-Sektion |
|---|---|
mat-table ODER <table> | Datentabelle |
mat-form-field ODER <input>/<select> | Formular |
mat-button ODER <button> | Buttons |
mat-card ODER <article>/<section> | Cards |
mat-chip ODER .badge/.tag | Chips/Tags |
mat-tab ODER Custom Tabs | Tabs |
<ul>/<ol> | Listen |
<nav> | Navigation |
<dialog> ODER mat-dialog | Dialoge |
mat-progress-bar ODER <progress> | Loading States |
<details>/<summary> | Accordions |
Ergebnis speichern:
Gefundene UI-Elemente für Preview:
Material Components:
- [X] mat-button (45x)
- [X] mat-form-field (34x)
- [X] mat-table (12x)
Native HTML:
- [X] <table> (28x)
- [X] <input> (56x)
- [X] <ul> Listen (12x)
- [X] <nav> Navigation (8x)
- [ ] <dialog> (nicht verwendet)
Custom Components:
- [X] app-user-card (18x) → Card-Variante
- [X] app-status-badge (9x) → Chip/Badge-Variante
7.3: Theme-Datei lesen (nur bei Option 3)
Read: ${CLAUDE_PLUGIN_ROOT}/skills/ui-theming/themes/[selected-theme].md
Extrahiere Primary und Accent Color, berechne Light/Dark-Varianten (wie in Step 3).
7.4: Preview HTML erstellen (nur gefundene Komponenten)
Create wireframes/theme-preview-[theme-name].html - a standalone HTML file for instant visual feedback:
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Theme Preview - [Theme Name]</title>
<link href="https://fonts.googleapis.com/css2?family=[theme-font]:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
/* ========== GENERATED TOKENS (from _colors.scss) ========== */
:root {
/* Brand Colors */
--color-primary: [primary-hex];
--color-primary-light: [primary-light-hex];
--color-primary-dark: [primary-dark-hex];
--color-accent: [accent-hex];
/* Semantic */
--color-success: #4caf50;
--color-warning: #ff9800;
--color-error: #f44336;
--color-info: #2196f3;
/* Neutrals */
--color-gray-100: #f5f5f5;
--color-gray-200: #eeeeee;
--color-gray-300: #e0e0e0;
--color-gray-600: #757575;
--color-gray-800: #424242;
--color-gray-900: #212121;
/* Surface */
--color-background: #fafafa;
--color-surface: #ffffff;
--color-text-primary: rgba(0,0,0,0.87);
--color-text-secondary: rgba(0,0,0,0.6);
--color-divider: rgba(0,0,0,0.12);
/* Typography */
--font-family-base: '[theme-font]', sans-serif;
/* Spacing */
--spacing-2: 0.5rem;
--spacing-3: 0.75rem;
--spacing-4: 1rem;
--spacing-6: 1.5rem;
--radius-md: 0.25rem;
/* Elevation */
--elevation-1: 0 2px 1px -1px rgba(0,0,0,.2), 0 1px 1px 0 rgba(0,0,0,.14), 0 1px 3px 0 rgba(0,0,0,.12);
--elevation-2: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
}
.dark-theme {
--color-primary: [primary-light-hex];
--color-background: #121212;
--color-surface: #1e1e1e;
--color-text-primary: rgba(255,255,255,0.87);
--color-text-secondary: rgba(255,255,255,0.6);
--color-divider: rgba(255,255,255,0.12);
--color-gray-100: #303030;
--color-gray-200: #424242;
--color-gray-300: #616161;
}
/* ========== BASE STYLES ========== */
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: var(--font-family-base);
background: var(--color-background);
color: var(--color-text-primary);
padding: var(--spacing-6);
transition: background 0.3s, color 0.3s;
}
.container { max-width: 1200px; margin: 0 auto; }
h1 { font-size: 2.25rem; font-weight: 300; margin-bottom: var(--spacing-6); }
h2 { font-size: 1.5rem; font-weight: 400; margin: var(--spacing-6) 0 var(--spacing-4); color: var(--color-text-secondary); }
h3 { font-size: 1.25rem; font-weight: 500; margin-bottom: var(--spacing-3); }
/* ========== THEME TOGGLE ========== */
.theme-toggle {
position: fixed; top: 1rem; right: 1rem;
background: var(--color-surface); border: 1px solid var(--color-divider);
padding: var(--spacing-2) var(--spacing-4); border-radius: var(--radius-md);
cursor: pointer; box-shadow: var(--elevation-1);
}
/* ========== COLOR SWATCHES ========== */
.swatches { display: flex; flex-wrap: wrap; gap: var(--spacing-3); }
.swatch {
width: 100px; height: 80px; border-radius: var(--radius-md);
display: flex; flex-direction: column; justify-content: flex-end;
padding: var(--spacing-2); font-size: 0.75rem; color: white;
box-shadow: var(--elevation-1);
}
.swatch-label { font-weight: 500; }
.swatch-hex { opacity: 0.8; }
/* ========== CARD ========== */
.card {
background: var(--color-surface);
border-radius: var(--radius-md);
box-shadow: var(--elevation-1);
padding: var(--spacing-4);
margin-bottom: var(--spacing-4);
}
/* ========== BUTTONS ========== */
.btn {
display: inline-flex; align-items: center; gap: var(--spacing-2);
padding: var(--spacing-2) var(--spacing-4);
border: none; border-radius: var(--radius-md);
font-family: inherit; font-size: 0.875rem; font-weight: 500;
cursor: pointer; transition: all 0.2s;
}
.btn-primary { background: var(--color-primary); color: white; }
.btn-primary:hover { filter: brightness(1.1); }
.btn-secondary { background: transparent; color: var(--color-primary); border: 1px solid var(--color-divider); }
.btn-danger { background: var(--color-error); color: white; }
.btn-icon { padding: var(--spacing-2); min-width: auto; }
/* ========== TABLE ========== */
.table { width: 100%; border-collapse: collapse; }
.table th, .table td {
padding: var(--spacing-3) var(--spacing-4);
text-align: left; border-bottom: 1px solid var(--color-divider);
}
.table th { font-weight: 500; color: var(--color-text-secondary); font-size: 0.75rem; text-transform: uppercase; }
.table tr:hover { background: var(--color-gray-100); }
.table-actions { display: flex; gap: var(--spacing-2); }
/* ========== FORM ========== */
.form-group { margin-bottom: var(--spacing-4); }
.form-label { display: block; font-size: 0.875rem; color: var(--color-text-secondary); margin-bottom: var(--spacing-2); }
.form-input {
width: 100%; padding: var(--spacing-3) var(--spacing-4);
border: 1px solid var(--color-divider); border-radius: var(--radius-md);
font-family: inherit; font-size: 1rem;
background: var(--color-surface); color: var(--color-text-primary);
}
.form-input:focus { outline: 2px solid var(--color-primary); border-color: transparent; }
.form-select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23757575' d='M6 8L1 3h10z'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 1rem center; }
.form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-4); }
.form-actions { display: flex; gap: var(--spacing-3); justify-content: flex-end; margin-top: var(--spacing-6); }
/* ========== CHIPS ========== */
.chip {
display: inline-flex; align-items: center; gap: var(--spacing-2);
padding: var(--spacing-1, 0.25rem) var(--spacing-3);
border-radius: 9999px; font-size: 0.75rem; font-weight: 500;
}
.chip-success { background: #e8f5e9; color: #2e7d32; }
.chip-warning { background: #fff3e0; color: #e65100; }
.chip-error { background: #ffebee; color: #c62828; }
/* ========== GRID LAYOUT ========== */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--spacing-6); }
@media (max-width: 768px) { .grid-2 { grid-template-columns: 1fr; } }
</style>
</head>
<body>
<button class="theme-toggle" onclick="document.body.classList.toggle('dark-theme')">
<span class="material-icons" style="vertical-align: middle;">dark_mode</span> Toggle Dark Mode
</button>
<div class="container">
<h1>Theme Preview: [Theme Name]</h1>
<!-- ========== IMMER INKLUDIERT ========== -->
<!-- COLOR PALETTE (immer) -->
<h2>Farbpalette</h2>
<div class="swatches">
<div class="swatch" style="background: var(--color-primary);">
<span class="swatch-label">Primary</span>
<span class="swatch-hex">[primary-hex]</span>
</div>
<div class="swatch" style="background: var(--color-primary-light);">
<span class="swatch-label">Primary Light</span>
<span class="swatch-hex">[primary-light-hex]</span>
</div>
<div class="swatch" style="background: var(--color-primary-dark);">
<span class="swatch-label">Primary Dark</span>
<span class="swatch-hex">[primary-dark-hex]</span>
</div>
<div class="swatch" style="background: var(--color-accent);">
<span class="swatch-label">Accent</span>
<span class="swatch-hex">[accent-hex]</span>
</div>
<div class="swatch" style="background: var(--color-success);">
<span class="swatch-label">Success</span>
<span class="swatch-hex">#4caf50</span>
</div>
<div class="swatch" style="background: var(--color-warning);">
<span class="swatch-label">Warning</span>
<span class="swatch-hex">#ff9800</span>
</div>
<div class="swatch" style="background: var(--color-error);">
<span class="swatch-label">Error</span>
<span class="swatch-hex">#f44336</span>
</div>
<div class="swatch" style="background: var(--color-info);">
<span class="swatch-label">Info</span>
<span class="swatch-hex">#2196f3</span>
</div>
</div>
<!-- TYPOGRAPHY (immer) -->
<h2>Typografie</h2>
<div class="card">
<h1 style="margin-bottom: 0.5rem;">Heading 1 - Light 2.25rem</h1>
<h2 style="margin: 0.5rem 0;">Heading 2 - Regular 1.5rem</h2>
<h3 style="margin: 0.5rem 0;">Heading 3 - Medium 1.25rem</h3>
<p style="margin-top: 1rem;">Body Text - Dies ist ein Beispieltext in der Standardschriftgröße. Die Schriftfamilie ist <strong>[theme-font]</strong>.</p>
<p style="font-size: 0.875rem; color: var(--color-text-secondary); margin-top: 0.5rem;">Secondary Text - Kleinere Schrift für weniger wichtige Informationen.</p>
</div>
<!-- ========== BEDINGT: NUR WENN KOMPONENTE GEFUNDEN ========== -->
<div class="grid-2">
<!-- MINI TABLE (wenn mat-table ODER <table> gefunden) -->
<div>
<h2>Datentabelle</h2>
<div class="card" style="padding: 0; overflow: hidden;">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Status</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
<tr>
<td>Max Mustermann</td>
<td><span class="chip chip-success">Aktiv</span></td>
<td class="table-actions">
<button class="btn btn-icon btn-secondary"><span class="material-icons">edit</span></button>
<button class="btn btn-icon btn-danger"><span class="material-icons">delete</span></button>
</td>
</tr>
<tr>
<td>Erika Musterfrau</td>
<td><span class="chip chip-warning">Ausstehend</span></td>
<td class="table-actions">
<button class="btn btn-icon btn-secondary"><span class="material-icons">edit</span></button>
<button class="btn btn-icon btn-danger"><span class="material-icons">delete</span></button>
</td>
</tr>
<tr>
<td>John Doe</td>
<td><span class="chip chip-error">Inaktiv</span></td>
<td class="table-actions">
<button class="btn btn-icon btn-secondary"><span class="material-icons">edit</span></button>
<button class="btn btn-icon btn-danger"><span class="material-icons">delete</span></button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- MINI FORM (wenn mat-form-field ODER <input>/<select> gefunden) -->
<div>
<h2>Formular</h2>
<div class="card">
<h3>Benutzer bearbeiten</h3>
<form style="margin-top: var(--spacing-4);">
<div class="form-row">
<div class="form-group">
<label class="form-label">Vorname</label>
<input type="text" class="form-input" value="Max" />
</div>
<div class="form-group">
<label class="form-label">Nachname</label>
<input type="text" class="form-input" value="Mustermann" />
</div>
</div>
<div class="form-group">
<label class="form-label">E-Mail</label>
<input type="email" class="form-input" value="max@example.com" />
</div>
<div class="form-group">
<label class="form-label">Rolle</label>
<select class="form-input form-select">
<option>Administrator</option>
<option selected>Benutzer</option>
<option>Gast</option>
</select>
</div>
<div class="form-actions">
<button type="button" class="btn btn-secondary">Abbrechen</button>
<button type="submit" class="btn btn-primary">
<span class="material-icons">save</span> Speichern
</button>
</div>
</form>
</div>
</div>
</div>
<!-- BUTTONS (wenn mat-button ODER <button> gefunden) -->
<h2>Buttons</h2>
<div class="card" style="display: flex; gap: var(--spacing-4); flex-wrap: wrap; align-items: center;">
<button class="btn btn-primary"><span class="material-icons">add</span> Primary</button>
<button class="btn btn-secondary">Secondary</button>
<button class="btn btn-danger"><span class="material-icons">delete</span> Danger</button>
<button class="btn btn-primary" disabled style="opacity: 0.5; cursor: not-allowed;">Disabled</button>
</div>
</div>
</body>
</html>
Nach Erstellung:
THEME PREVIEW ERSTELLT: [Theme Name]
Öffnen Sie die Vorschau im Browser:
open wireframes/theme-preview-[theme-name].html
Features:
- [X] Farbpalette mit allen Brand & Semantic Colors (immer)
- [X] Typografie-Beispiele (immer)
- [X] Dark Mode Toggle (immer)
- Projekt-spezifische Elemente (nur wenn im Projekt gefunden):
- [ ] Datentabelle (mat-table ODER <table>)
- [ ] Formular (mat-form-field ODER <input>/<select>)
- [ ] Buttons (mat-button ODER <button>)
- [ ] Listen (<ul>/<ol>)
- [ ] Navigation (<nav>)
- [ ] Cards, Chips, Dialogs, etc.
Nächste Schritte:
- Anderes Theme testen? → /byt8:ui-theming (Option 3)
- Dieses Theme übernehmen? → /byt8:ui-theming (Option 2 mit gleichem Theme)
Output
DESIGN SYSTEM INITIALIZED
Theme: [Selected Theme]
Primary: [primary-hex]
Accent: [accent-hex]
Font: [theme-font]
Files Created:
- [X] frontend/src/styles/tokens/_colors.scss
- [X] frontend/src/styles/tokens/_typography.scss
- [X] frontend/src/styles/tokens/_spacing.scss
- [X] frontend/src/styles/tokens/_elevation.scss
- [X] frontend/src/styles/tokens/_breakpoints.scss
- [X] frontend/src/styles/tokens/_index.scss
- [X] frontend/src/styles.scss (updated)
- [X] wireframes/theme-preview-[theme-name].html (Preview)
Architecture:
- CSS Custom Properties (runtime theming)
- @use/@forward module system (no @import)
- Light/Dark mode support
- 8pt spacing grid with semantic aliases
- Material Design elevations
- Responsive breakpoint mixins
Preview:
open wireframes/theme-preview-[theme-name].html
Next Steps:
1. Preview öffnen und Theme prüfen (Light + Dark Mode)
2. Falls Theme nicht passt: /byt8:ui-theming erneut ausführen
3. Falls Theme passt: /byt8:full-stack-feature starten
4. In Components: var(--token-name) verwenden
When to Run
- ONCE at project start
- When changing the project theme
- When updating design system tokens
Prerequisites
- Frontend project initialized (
npm installcomplete)