Files
hms-licht-ton/docs/design-rules.md
T
2026-07-10 23:08:41 +02:00

509 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# HMS Licht & Ton Design-Richtlinien für KI-Agenten
> **VERBINDLICH:** Diese Regeln MÜSSEN bei jeder Erweiterung der Website eingehalten werden.
> Abweichungen sind Fehler. Der freigegebene Prototyp ist die Quelle der Wahrheit.
> Prototyp: `https://webspace.media-on.de/hms-prototype/index.html?v=8`
> Referenz-Dateien: `docs/prototype-app.js`, `docs/prototype-index.html`, `frontend/assets/css/prototype-style.css`
---
## 1. Farbsystem (Dark Theme + Orange Akzent)
### Hauptfarben (Agent Zero Dark Theme Grautöne)
| Token | Hex | Verwendung |
|-------|-----|------------|
| `--bg` | `#131313` | Seiten-Hintergrund |
| `--panel` | `#1a1a1a` | Panels, Cards, Header |
| `--surface` | `#212121` | Input-Felder, Surface-Level |
| `--row` | `#272727` | List-Items, Zwischenebenen |
| `--card` | `#2d2d2d` | Card-Hintergrund |
| `--border` | `#444444a8` | Borders (mit Alpha) |
| `--border-strong` | `#555555` | Strong Borders (Inputs) |
| `--secondary` | `#656565` | Sekundärfarbe, Icons, grauer Text |
| `--primary` | `#737a81` | Primärfarbe (leicht bläuliches Grau) |
| `--text` | `#ffffff` | Haupttext |
| `--text-muted` | `#d4d4d4` | Gedimmter Text |
### Orange Akzent (DEZENT keine großen Flächen!)
| Token | Wert | Verwendung |
|-------|------|------------|
| `--color-accent` | `#EC6925` | Buttons, Badges, Text-Akzente, Logo-Border |
| `--color-accent-hover` | `#d4581a` | Button Hover |
| `--color-accent-light` | `rgba(236, 105, 37, 0.08)` | Badge-Hintergrund, Nav-Active |
| `--color-accent-border` | `rgba(236, 105, 37, 0.25)` | Card Hover Border |
| `--color-accent-dark` | `#b8461a` | Dunkle Variante |
### Status-Farben
| Token | Hex/RGBA | Verwendung |
|-------|----------|------------|
| `--color-success` | `#4ade80` | Erfolg-Meldungen |
| `--color-success-bg` | `rgba(74, 222, 128, 0.08)` | Erfolg-Hintergrund |
| `--color-error` | `#f87171` | Fehler, Pflichtfelder |
| `--color-error-bg` | `rgba(248, 113, 113, 0.08)` | Fehler-Hintergrund |
| `--color-warning` | `#fbbf24` | Warnungen |
| `--color-info` | `#60a5fa` | Info |
### FARB-REGELN
- **Orange NIEMALS als große Fläche** nur für Buttons, Badges, kleine Text-Highlights, Border
- **Hintergründe IMMER Grautöne** (#131313 bis #2d2d2d)
- **Text IMMER `var(--text)` (#ffffff) oder `var(--text-muted)` (#d4d4d4)**
- **Sekundärer Text `var(--secondary)` (#656565)** für sehr gedimmte Infos
- **Inline Styles mit CSS Variablen:** `style="color: var(--text)"`, `style="background: var(--panel)"`
---
## 2. Typography
- **Font Family:** Inter (Google Fonts), Weights: 400, 500, 600, 700, 800
- **Größen:** Tailwind Utilities (`text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`, `text-4xl`, `text-5xl`, `text-6xl`)
- **Headings:** `font-bold` oder `font-semibold`, `leading-tight` für große Headlines
- **Body:** `leading-relaxed` für längere Texte
- **Line Height:** 1.6 (Body), 1.1-1.3 (Headings)
---
## 3. Layout-System
### Container
- **Max-Width:** `max-w-7xl` (1280px)
- **Padding:** `px-4 sm:px-6 lg:px-8`
- **Center:** `mx-auto`
### Sections
- **Vertical Padding:** `py-12 sm:py-16` (Standard), `py-16 sm:py-20` (große Sections), `py-20 sm:py-32` (Hero)
- **Background Alternation:** `var(--bg)``var(--panel)``var(--bg)` für visuelle Trennung
- **Section Dividers:** `.hms-section-divider` (subtiler Gradient)
### Grid
- **Cards Grid:** `grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6`
- **Speaker Grid:** `.hms-speaker-grid` (auto-fill, minmax 160px)
- **Gallery Grid:** `.hms-gallery` (auto-fill, minmax 300px)
- **2-Spalten Layout:** `grid lg:grid-cols-2 gap-8` oder `gap-12`
### Responsive Breakpoints
- `sm:` 640px (Tablet Portrait)
- `md:` 768px (Desktop Nav visible, Mobile Burger hidden)
- `lg:` 1024px (Desktop, 3-4 Column Grids)
- **Mobile-First:** Alle Layouts starten 1-Spalte
---
## 4. CSS Komponenten-Klassen (hms-*)
### ÜBERSICHT: Alle hms-* Klassen aus prototype-style.css
Diese Klassen sind in `assets/css/main.css` definiert und MÜSSEN verwendet werden.
Keine eigenen Klassen erfinden!
### Buttons
```html
<!-- Primary: Orange bg, white text -->
<button class="hms-btn hms-btn-primary">Button Text</button>
<!-- Secondary: Surface bg, muted text, border -->
<button class="hms-btn hms-btn-secondary">Button Text</button>
<!-- Ghost: Transparent, muted text -->
<button class="hms-btn hms-btn-ghost">Button Text</button>
```
- **Padding:** `px-8 py-4` für große Buttons, `px-4 py-2` für kleine, `px-3 py-1.5` für Mini
- **Font:** `font-semibold` oder `font-medium`, `text-sm` für Standard
- **Hover-Effekte:** Primary → box-shadow glow + translateY(-1px); Secondary → border accent
- **Disabled:** `--secondary` bg, `cursor: not-allowed`
### Cards
```html
<div class="hms-card p-6">
<h3 class="text-lg font-semibold mb-2" style="color: var(--text)">Title</h3>
<p class="text-sm leading-relaxed" style="color: var(--text-muted)">Description</p>
</div>
```
- **Background:** `var(--panel)` (#1a1a1a)
- **Border:** `1px solid var(--border)` (#444444a8)
- **Border-Radius:** `4px` (--radius-lg)
- **Hover:** Box-shadow wird stärker, Border wird heller
### Equipment Cards
```html
<div class="hms-eq-card" @click="..." role="article" tabindex="0">
<div class="aspect-[4/3] flex items-center justify-center relative overflow-hidden" style="background: var(--surface)">
<img v-if="item.image" :src="item.image" class="absolute inset-0 w-full h-full object-cover" />
<div v-else class="text-4xl" style="color: var(--secondary)">📦</div>
<span v-if="item.category" class="hms-badge hms-badge-primary absolute top-3 left-3">{{ item.category }}</span>
</div>
<div class="p-4">
<h3 class="font-semibold text-sm mb-1 truncate" style="color: var(--text)">{{ item.name }}</h3>
<p class="text-xs mb-3 line-clamp-2" style="color: var(--secondary)">{{ item.description }}</p>
<div class="flex items-center justify-between">
<span class="text-xs" style="color: var(--secondary)">{{ item.code }}</span>
<button class="hms-btn hms-btn-ghost text-xs px-3 py-1.5" style="color: var(--color-accent)">+ Hinzufügen</button>
</div>
</div>
</div>
```
### Badges
```html
<span class="hms-badge hms-badge-primary">Badge Text</span>
<span class="hms-badge hms-badge-gray">Gray Badge</span>
<span class="hms-badge hms-badge-success">Success</span>
<span class="hms-badge hms-badge-error">Error</span>
```
- **Border-Radius:** `9999px` (pill shape)
- **Primary:** Orange bg (12% alpha), orange text, orange border (20% alpha)
### Inputs
```html
<input class="hms-input" type="text" placeholder="..." />
<input class="hms-input hms-input-error" /> <!-- mit Fehler -->
<select class="hms-input"><option>...</option></select>
<textarea class="hms-input" rows="5"></textarea>
```
- **Background:** `var(--surface)` (#212121)
- **Border:** `1px solid var(--border-strong)` (#555555)
- **Focus:** Orange border + subtle orange box-shadow
- **Error:** Red border + red box-shadow
- **Padding:** `var(--space-md) var(--space-lg)`
### Filter Chips
```html
<button class="hms-chip" :class="{ active: isActive }">Filter</button>
```
- **Inactive:** Surface bg, muted text, border
- **Active:** Orange bg, white text, orange border
### Navigation Buttons
```html
<button class="hms-nav-btn px-4 py-2 rounded-lg text-sm font-medium"
:style="isActive ? { color: 'var(--color-accent)', background: 'var(--color-accent-light)' } : { color: 'var(--text-muted)' }"
:aria-current="isActive ? 'page' : undefined">
Nav Item
</button>
```
- **Hover:** Orange text + accent-light bg + Unterstrich-Animation
- **Active:** Orange text + accent-light bg
### Skeleton Loading
```html
<div class="hms-skeleton h-4 w-3/4"></div>
```
- Shimmer Animation von `prototype-style.css`
### Spinner
```html
<span class="hms-spinner" style="width:18px;height:18px;border-width:2px"></span>
```
### Icon Circle (Service Icons)
```html
<div class="hms-icon-circle mb-4"><span aria-hidden="true">🔊</span></div>
```
- 48x48px, surface bg, border, centered content
### Hero
```html
<section class="hms-hero py-20 sm:py-32">
<div class="hms-hero-bg" style="background-image: url('...')"></div>
<div class="hms-hero-overlay"></div>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<!-- Content -->
</div>
</section>
```
- **hms-hero-bg:** Absolute, background-size cover, opacity 0.35
- **hms-hero-overlay:** Linear gradient von rgba(19,19,19,0.6) zu var(--bg)
- **Content:** `relative z-10` über Overlay
---
## 5. Inline Style Pattern
### REGEL: Inline Styles verwenden IMMER CSS Variablen
```html
<!-- RICHTIG -->
<h1 style="color: var(--text)">Title</h1>
<p style="color: var(--text-muted)">Text</p>
<div :style="{ background: 'var(--panel)', borderColor: 'var(--border)' }">
<!-- FALSCH -->
<h1 style="color: #ffffff">Title</h1>
<p style="color: #d4d4d4">Text</p>
```
### Häufige Inline Styles aus dem Prototyp
- `style="color: var(--text)"` Haupttext
- `style="color: var(--text-muted)"` Gedimmter Text
- `style="color: var(--secondary)"` Sehr gedimmter Text
- `style="color: var(--color-accent)"` Orange Akzent
- `style="background: var(--panel)"` Panel BG
- `style="background: var(--bg)"` Seiten BG
- `style="background: var(--surface)"` Surface BG
- `:style="{ borderColor: 'var(--border)' }"` Border Color
- `:style="{ background: 'var(--color-success-bg)', color: 'var(--color-success)' }"` Success State
---
## 6. Komponenten-Struktur
### Bestehende Komponenten (NICHT neu erfinden)
| Komponente | Datei | Zweck |
|---|---|---|
| HmsLogo | `components/HmsLogo.vue` | Echtes SVG Logo (H + orange Border) |
| SpeakerIcon | `components/SpeakerIcon.vue` | 6 Lautsprecher-Typ SVG Icons |
| AppHeader | `components/AppHeader.vue` | Sticky Header, Nav, Cart, Mobile Burger |
| AppFooter | `components/AppFooter.vue` | 4-Spalten Footer |
| ServiceCard | `components/ServiceCard.vue` | Service Card mit Icon Circle |
| EquipmentCard | `components/EquipmentCard.vue` | Equipment Card mit Badge, Image, Add-to-Cart |
| LoadingSkeleton | `components/LoadingSkeleton.vue` | Skeleton Loading Cards |
| EmptyState | `components/EmptyState.vue` | Empty State mit Icon + Action |
| ErrorState | `components/ErrorState.vue` | Error State mit Retry |
### Neue Komponenten erstellen Checklist
1. CSS Klassen aus `prototype-style.css` verwenden (hms-*)
2. Inline Styles mit CSS Variablen
3. Tailwind Utilities für Layout/Spacing
4. TypeScript mit `lang="ts"`
5. `useHead()` für Meta Tags
6. ARIA Attributes (role, aria-label, aria-current, etc.)
7. Responsive (mobile-first, sm/md/lg breakpoints)
---
## 7. UX States (MUSS in jeder View implementiert)
### Loading State
```html
<loading-skeleton :count="6" />
```
### Empty State
```html
<empty-state icon="🔍" title="Keine Ergebnisse" message="..." action-label="Zurück" @action="..." />
```
### Error State
```html
<error-state title="Fehler" message="..." @retry="..." />
```
### Success State
```html
<div class="text-center py-8" role="status">
<div class="inline-flex items-center justify-center w-16 h-16 rounded-full mb-4"
:style="{ background: 'var(--color-success-bg)', color: 'var(--color-success)' }">
<svg class="w-8 h-8" ...></svg>
</div>
<h3 class="text-lg font-semibold mb-2" style="color: var(--text)">Erfolg</h3>
<p class="text-sm mb-6" style="color: var(--secondary)">Nachricht</p>
</div>
```
### Submitting State
```html
<button :disabled="submitting" class="hms-btn hms-btn-primary">
<span v-if="submitting" class="hms-spinner" style="width:18px;height:18px;border-width:2px"></span>
<span v-else>Senden</span>
</button>
```
---
## 8. Accessibility (WCAG 2.1 AA)
### MUSS-Regeln
- **Skip Link:** `<a class="skip-link" href="#main">Zum Inhalt springen</a>` am Seitenanfang
- **Semantic HTML:** `<header>`, `<main>`, `<footer>`, `<nav>`, `<section>`, `<article>`
- **ARIA:** `role`, `aria-label`, `aria-current="page"`, `aria-expanded`, `aria-invalid`, `aria-describedby`, `role="alert"`, `role="status"`
- **Focus Visible:** `*:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }`
- **Form Labels:** Jedes Input hat `<label for="...">`, Pflichtfelder mit `<span style="color: var(--color-error)">*</span>`
- **Heading Hierarchy:** h1 > h2 > h3, keine Levels überspringen
- **Keyboard Navigation:** Alle interaktiven Elemente per Tab erreichbar, `tabindex="0"` auf klickbare Cards
- **Alt Text:** Alle Bilder haben `alt="..."`
- `aria-hidden="true"` auf dekorativen Icons
- `loading="lazy"` auf alle Bilder
---
## 9. Meta Tags & SEO
### MUSS pro Seite
```typescript
useHead({
title: 'Seite HMS Licht & Ton',
meta: [
{ name: 'robots', content: 'noindex, nofollow, noarchive, nosnippet' },
],
});
```
### JSON-LD (nur Home)
- `LocalBusiness` Schema mit Adresse, Öffnungszeiten, Services
### OpenGraph
- `og:type`, `og:title`, `og:description`, `og:locale`, `og:site_name`, `og:url`
### REGELN
- **noindex** auf ALLEN Seiten (Domain nicht öffentlich indexiert)
- **KEINE sitemap.xml**
- Inter Font via Google Fonts preconnect
- `theme-color: #EC6925` (nur im Head, nicht als Design-Fläche!)
---
## 10. Bilder
### Hero Background
- Unsplash Konzert-Bild: `background-image: url('https://images.unsplash.com/photo-1470229722913-7c0e2dbbafd3?w=1920&q=80')`
- **Opacity:** 0.35 (über `.hms-hero-bg`)
- **Overlay:** Linear gradient zu `var(--bg)`
### Referenzen
- 9 echte HMS-Fotos: `img/ref1.jpg` bis `img/ref9.jpg`
- **Hover:** `group-hover:scale-110` (Zoom-Effekt)
- **Gradient Overlay:** `bg-gradient-to-t from-black/50 to-transparent` bei Hover
### Equipment
- Platzhalter `📦` Emoji wenn kein Bild vorhanden
- `loading="lazy"` auf allen Bildern
### About Section
- Unsplash Setup-Bild: `https://images.unsplash.com/photo-1493225457124-a3eb161ffa5f?w=800&q=80`
---
## 11. Spacing & Radius
### Spacing Tokens
| Token | Wert |
|-------|-------|
| `--space-xs` | 0.25rem (4px) |
| `--space-sm` | 0.5rem (8px) |
| `--space-md` | 1rem (16px) |
| `--space-lg` | 1.5rem (24px) |
| `--space-xl` | 2rem (32px) |
| `--space-2xl` | 3rem (48px) |
| `--space-3xl` | 4rem (64px) |
| `--space-4xl` | 6rem (96px) |
### Border Radius (MINIMAL!)
| Token | Wert |
|-------|-------|
| `--radius-sm` | 2px |
| `--radius-md` | 3px |
| `--radius-lg` | 4px |
| `--radius-xl` | 4px |
| `--radius-full` | 9999px (nur Badges, Pills) |
### Shadows
| Token | Wert |
|-------|-------|
| `--shadow-sm` | `0 1px 2px 0 rgb(0 0 0 / 0.3)` |
| `--shadow-md` | `0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3)` |
| `--shadow-lg` | `0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.3)` |
| `--shadow-xl` | `0 20px 25px -5px rgb(0 0 0 / 0.5), 0 8px 10px -6px rgb(0 0 0 / 0.3)` |
---
## 12. Transitions
| Token | Dauer |
|-------|-------|
| `--transition-fast` | 150ms ease |
| `--transition-base` | 250ms ease |
| `--transition-slow` | 400ms ease |
---
## 13. Build & Test
### Frontend
```bash
cd frontend && npm run build # Build (MUSS 0 errors)
cd frontend && npx vitest run # Unit Tests (MUSS alle pass)
cd frontend && npx playwright test --grep 'Pattern' # E2E Tests
curl -s http://localhost:3000/ # Smoke Test
```
### Backend
```bash
cd backend && python -m pytest tests/ -v --cov=app # Tests (MUSS alle pass)
curl -s http://localhost:8000/api/health # Health Check
```
### Deployment
- Server: coolify-01 (46.225.91.159)
- Pfad: `/data/hms-licht-ton/`
- Branch: `feature/T04-rentman-integration` (oder `main` nach Merge)
- Docker Compose: `docker compose up -d`
- Domain: `https://hms.media-on.de` (Traefik + Let's Encrypt)
---
## 14. VERBOTEN
- ❌ Eigene CSS Klassen erfinden (nur `hms-*` verwenden)
- ❌ Generische `.btn-primary` oder `.nav-link` Klassen
- ❌ Hardcoded Hex-Werte in Inline Styles (immer `var(--...)`)
- ❌ Fake-Logo (immer echtes SVG aus `assets/logo.svg`)
- ❌ Große Orange-Flächen
- ❌ Abgerundete Ecken > 4px (außer Badges/Pills = 9999px)
- ❌ Client-only rendering für SSR Pages (`/mietkatalog`, `/mietkatalog/**`)
- ❌ Fehlende ARIA Attributes
- ❌ Fehlende UX States (Loading, Empty, Error, Success)
- ❌ Fehlendes `noindex` Meta Tag
- ❌ Eigene Templates die nicht dem Prototyp entsprechen
---
## 15. Referenz-Dateien
| Datei | Zweck |
|---|---|
| `docs/prototype-app.js` | Original Vue 3 SPA Prototyp (761 Zeilen, 19 Komponenten) |
| `docs/prototype-index.html` | Original HTML mit Meta Tags, JSON-LD |
| `frontend/assets/css/prototype-style.css` | Original CSS mit allen hms-* Klassen (13KB) |
| `frontend/assets/css/main.css` | Aktive CSS (enthält prototype-style.css + Tailwind directives) |
| `frontend/assets/logo.svg` | Echtes HMS Logo (503 bytes, weißes H + orange Border) |
| `frontend/public/logo.svg` | Static copy für Nuxt public dir |
| `docs/ui_design.md` | Original UI Design Dokumentation |
| `docs/design-rules.md` | DIES DATEI Design Richtlinien für KI-Agenten |
---
## 16. Schnell-Referenz: Neue Seite erstellen
```vue
<template>
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
<h1 class="text-3xl sm:text-4xl font-bold mb-2" style="color: var(--text)">Seiten-Titel</h1>
<p class="mb-8" style="color: var(--secondary)">Untertitel</p>
<!-- Loading -->
<loading-skeleton v-if="loading" :count="6" />
<!-- Error -->
<error-state v-else-if="error" title="Fehler" message="..." @retry="loadData" />
<!-- Content -->
<div v-else class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
<div v-for="item in items" :key="item.id" class="hms-card p-6">
<h3 class="text-lg font-semibold mb-2" style="color: var(--text)">{{ item.title }}</h3>
<p class="text-sm leading-relaxed" style="color: var(--text-muted)">{{ item.description }}</p>
<button class="hms-btn hms-btn-primary mt-4">Aktion</button>
</div>
</div>
<!-- Empty -->
<empty-state v-if="!loading && !error && items.length === 0"
icon="🔍" title="Keine Daten" message="..." action-label="Zurück" @action="..." />
</div>
</template>
<script setup lang="ts">
useHead({
title: 'Seite HMS Licht & Ton',
meta: [{ name: 'robots', content: 'noindex, nofollow, noarchive, nosnippet' }],
});
</script>
```
---
*Dieses Dokument ist die verbindliche Design-Richtlinie für alle Erweiterungen der HMS Licht & Ton Website.*