# @ocelot-social/ui - Projektdokumentation > Dieses Dokument dient als zentrale Planungs- und Statusübersicht für das UI-Library Subprojekt. > Es ermöglicht das Pausieren und Wiederaufnehmen der Arbeit zu jedem Zeitpunkt. --- ## Inhaltsverzeichnis ### Schnellzugriff (Status) | Abschnitt | Beschreibung | |-----------|--------------| | [Fortschritt](#fortschritt) | Visuelle Fortschrittsanzeige | | [Aktueller Stand](#aktueller-stand) | Was zuletzt erledigt wurde | | [Meilensteine](#meilensteine) | Phasen 0-5 mit Checklisten | ### Nach Thema **[VISION](#vision)** | # | Abschnitt | |---|-----------| | 1 | [Projektziel & Vision](#1-projektziel--vision) | **[TECHNISCHE GRUNDLAGEN](#technische-grundlagen)** | # | Abschnitt | |---|-----------| | 2 | [Tech-Stack](#2-tech-stack) | | 3 | [Build & Distribution](#3-build--distribution) | | 4 | [Icon-Architektur](#4-icon-architektur) | | 5 | [Design-Token & Branding](#5-design-token--branding) | **[PROZESSE & QUALITÄT](#prozesse--qualität)** | # | Abschnitt | |---|-----------| | 6 | [CI/CD & Release](#6-cicd--release) | | 7 | [Dokumentation & DX](#7-dokumentation--dx) | | 8 | [Migrationsstrategie](#8-migrationsstrategie) | | 9 | [Dokumentationsstrategie](#9-dokumentationsstrategie) | | 10 | [Kompatibilitätstests](#10-kompatibilitätstests) | **[REFERENZ & HISTORIE](#referenz--historie)** | # | Abschnitt | |---|-----------| | 11 | [Entscheidungen](#11-entscheidungen) | | 12 | [Arbeitsprotokoll](#12-arbeitsprotokoll) | | 13 | [Komponenten-Katalog](#13-komponenten-katalog) | | 14 | [Ressourcen & Links](#14-ressourcen--links) | | 15 | [Dokumentationsstrategie (Details)](#15-dokumentationsstrategie-details) | **[ABGRENZUNGEN](#abgrenzungen)** | # | Abschnitt | |---|-----------| | 16 | [Library vs. Webapp](#16-library-vs-webapp) | | 16a | [Webapp ↔ Maintenance Code-Sharing](#16a-webapp--maintenance-code-sharing) | | 16b | [Daten-Entkopplung (ViewModel/Mapper)](#16b-daten-entkopplung-viewmodelmapper-pattern) | | 17 | [Externe Abhängigkeiten](#17-externe-abhängigkeiten) | | 18 | [Kompatibilitätstests (Details)](#18-kompatibilitätstests-details) | | 19 | [Komplexitätsanalyse](#19-komplexitätsanalyse) | --- ### Wie dieses Dokument verwendet wird **Zum Fortsetzen der Arbeit:** > "Lass uns am @ocelot-social/ui Projekt weiterarbeiten" (packages/ui) **Nach jeder Session aktualisieren:** - "Fortschritt" – Balkendiagramme aktualisieren - "Aktueller Stand" – Zuletzt erledigte Aufgaben - "Meilensteine" – Checklisten abhaken - §12 "Arbeitsprotokoll" – Neue Einträge hinzufügen - `KATALOG.md` – Komponenten-Status pflegen --- ## Fortschritt ### Gesamtprojekt ``` Phase 0: ██████████ 100% (6/6 Aufgaben) ✅ Phase 1: ██████████ 100% (6/6 Aufgaben) ✅ Phase 2: ██████████ 100% (26/26 Aufgaben) ✅ Phase 3: ██████████ 100% (24/24 Aufgaben) ✅ - Webapp-Integration komplett Phase 4: ██████░░░░ 63% (17/27 Aufgaben) - Tier 1 ✅, Tier A ✅, Infra ✅, OsBadge ✅, ds-grid ✅, ds-table→HTML ✅, OsNumber ✅ | Tier B (rest), Tier 2-3 ausstehend Phase 5: ░░░░░░░░░░ 0% (0/7 Aufgaben) ─────────────────────────────────────── Gesamt: ████████░░ 82% (79/96 Aufgaben) ``` ### Katalogisierung (Details in KATALOG.md) ``` Webapp: ██████████ 100% (139 Komponenten erfasst) Styleguide: ██████████ 100% (38 Komponenten erfasst) Analyse: ██████████ 100% (Button, Modal, Menu detailiert) ``` ### OsButton Migration (Phase 3) ✅ ``` Scope gesamt: 133 Tags in 79 Webapp-Dateien ├─ Migriert: 133 Buttons (100%) ✅ ├─ : 0 verbleibend in Templates ├─ : 0 verbleibend in Templates └─ Cleanup: Snapshots/Tests müssen aktualisiert werden OsButton Features: ├─ variant: ✅ primary, secondary, danger, warning, success, info, default ├─ appearance: ✅ filled, outline, ghost ├─ size: ✅ sm, md, lg, xl ├─ disabled: ✅ mit hover/active-Override (nur as="button") ├─ icon: ✅ slot-basiert (icon-system-agnostisch) ├─ circle: ✅ rounded-full, größenabhängig (p-1.5 bis p-3) ├─ loading: ✅ animated SVG spinner, aria-busy (Milestone 4b) └─ as: ✅ polymorphes Rendering (button/a/NuxtLink/RouterLink) as-Prop Migration: 15 /-Wrapper in 15 Webapp-Dateien → as="nuxt-link"/as="a" ``` ### OsIcon (Phase 4) ``` OsIcon Features: ├─ name: ✅ System-Icon per Name (check, close, plus) ├─ icon: ✅ Custom Vue-Komponente (hat Vorrang vor name) ├─ size: ✅ xs, sm, md, lg, xl, 2xl (em-basiert) ├─ a11y: ✅ decorative (default) / semantic (mit aria-label) ├─ color: ✅ fill-current (erbt von Parent) └─ svg-plugin: ✅ vite-svg-icon (SVG → Vue Component via ?icon) System-Icons: ├─ check.svg (Checkmark) ├─ close.svg (Close/X) └─ plus.svg (Plus/Add) Ocelot-Icons (separates Entry-Point): └─ 82 Icons (Feature-Icons + Kategorie-Icons aus Webapp migriert) OsSpinner: ├─ size: ✅ xs, sm, md, lg, xl, 2xl (em-basiert) ├─ color: ✅ currentColor (erbt von Parent) ├─ a11y: ✅ role="status", aria-label="Loading" (customizable) ├─ decorative: ✅ aria-hidden="true" suppresses role/aria-label ├─ os-button: ✅ OsButton nutzt OsSpinner als Komponente (decorative) ├─ vue-compat: ✅ h() Render-Function mit isVue2 └─ webapp: ✅ 4 Spinner migriert (DsSpinner + LoadingSpinner → OsSpinner) BaseCard → OsCard Webapp-Migration: ✅ ├─ ~30 Webapp-Dateien: (lokale Imports) ├─ 3 Template-Dateien: #imageColumn/#topMenu Slots → inline Layout mit --columns CSS ├─ 16 Spec-Dateien: wrapper.classes('base-card') → wrapper.classes('os-card') ├─ 4 Story-Dateien: mit Import ├─ 12 Cypress E2E-Dateien: .base-card → .os-card Selektoren ├─ 2 Cypress-Dateien: .hero-image → .os-card__hero-image ├─ BaseCard.vue Komponente gelöscht ├─ base-components.js Plugin gelöscht (keine Base*.vue mehr) ├─ nuxt.config.js, maintenance config, testSetup.js bereinigt ├─ main.scss: .os-card Regeln (title, ds-section, hero-image, --columns Layout) ├─ CSS Fixes: Tailwind p-6 Override (!important), outline statt border (highlight), │ child selectors → descendant selectors (hero-image content wrapper) ├─ ContributionForm: Media-Query Selektoren auf .os-card__content korrigiert ├─ ProfileList: .profile-list.os-card Spezifität erhöht (0,3,0 vs 0,2,0) └─ 0 Template-Nutzungen verbleibend DsSpinner/LoadingSpinner → OsSpinner Webapp-Migration: ✅ ├─ ImageUploader.vue: LoadingSpinner → OsSpinner (size="lg") ├─ pages/profile: ds-spinner → os-spinner (size="lg") ├─ pages/groups: ds-spinner → os-spinner (size="lg") ├─ pages/admin: ds-spinner → os-spinner (size="xl") + ApolloQuery→apollo Option ├─ LoadingSpinner Komponente gelöscht ├─ ds-space centered → div+padding (Bugfix in 3 Seiten) ├─ Admin: ApolloQuery→$apollo.loading (Spinner war wg. SSR-Prefetch unsichtbar) └─ infinite-loading: OsSpinner im spinner-Slot (index, profile, groups) BaseIcon → OsIcon Webapp-Migration: ✅ ├─ 131 in 70+ Dateien → ├─ 82 SVGs in ocelot/icons/svgs/ (inkl. 17 Kategorie-Icons) ├─ vite-svg-icon Plugin erweitert (rect, circle, polygon, polyline, ellipse, line) ├─ Kategorie-Icons: DB-String → toCamelCase() → ocelotIcons Lookup ├─ Jest Mocks: @ocelot-social/ui/ocelot für ocelotIcons in Tests ├─ Tests aktualisiert: 911/939 Tests bestanden (3 pre-existing failures) └─ 0 base-icon/BaseIcon Referenzen verbleibend Tier A ds-* → Plain HTML + CSS: ✅ ├─ 10 triviale Vue-Wrapper-Komponenten durch HTML-Elemente + CSS-Klassen ersetzt ├─ ~450 Nutzungen in ~90 Dateien migriert ├─ _ds-compat.scss: Utility-Klassen für Margins (.ds-mb-*, .ds-mt-*, .ds-my-*), │ Flex (.ds-flex, .ds-flex-item, .ds-flex-gap-*), Centered (.ds-space-centered) ├─ ds-flex/ds-flex-item: JavaScript window.innerWidth → CSS @media Queries │ (kein Layout-Shift bei SSR, bessere Performance) ├─ system.css bleibt geladen — bestehende CSS-Klassen funktionieren weiter ├─ Verbleibend: 8 ds-* Komponenten (Tier B Rest: 1 einfache, Tier C: 6 komplexe → UI-Library) └─ 0 Tier-A ds-* Komponenten-Tags verbleibend ds-number → OsNumber (UI-Library): ✅ ├─ OsNumber Komponente: h() Render-Function, requestAnimationFrame Animation, inheritAttrs: false ├─ Props: count (required), label (optional), animated (optional) ├─ Animation: 1500ms ease-out, watch(count) re-animiert, SSR-safe (onMounted) ├─ Styling: tabular-nums + min-width für stabile Breite, --color-text-soft Label-Farbe ├─ ds-number + CountTo: 5 Dateien → (UserTeaserPopover, TabNavigation, admin, profile, groups) ├─ vue-count-to Dependency entfernt, CountTo.vue gelöscht ├─ CSS-Variable: --color-text-soft in requiredCssVariables + ocelot-ui-variables.scss ├─ 11 Unit-Tests, 5 Stories, 5 Visual Tests + 1 Keyboard Test └─ 0 ds-number/CountTo Nutzungen verbleibend ds-chip + ds-tag → OsBadge (UI-Library): ✅ ├─ OsBadge Komponente: CVA-Varianten, h() Render-Function, inheritAttrs: false ├─ Props: variant (default/primary/danger), size (sm/md/lg), shape (pill/square) ├─ Types: BadgeVariant, BadgeSize, BadgeShape (+ BadgeVariants) ├─ ds-chip: 20 Nutzungen in 5 Dateien → (Formzähler + Gruppen-Metadaten) ├─ ds-tag: 3 Nutzungen in 3 Dateien → (Category, Hashtag) ├─ ARIA: role="status" aria-live="polite" auf Form-Zähler (11 Stellen in 2 Dateien) ├─ CSS-Variable: --color-default + --color-default-contrast (beide in requiredCssVariables) ├─ 18 Unit-Tests, 6 Stories, 5 Visual Tests + 1 Keyboard Test └─ 0 ds-chip/ds-tag Nutzungen verbleibend ``` --- ## Aktueller Stand **Letzte Aktualisierung:** 2026-02-20 (Session 32) **Aktuelle Phase:** Phase 4 - Tier 1 ✅, Tier A ✅, OsBadge ✅, ds-grid ✅, ds-table→HTML ✅, OsNumber ✅ | Tier B (rest), Tier 2-3 ausstehend **Zuletzt abgeschlossen (Session 32 - OsNumber: ds-number + CountTo → OsNumber):** - [x] OsNumber Komponente in packages/ui erstellt (h() Render-Function, requestAnimationFrame Animation) - [x] Props: count (required), label (optional), animated (optional, 1500ms ease-out) - [x] Animation: requestAnimationFrame-Loop, watch(count) re-animiert von oldVal→newVal - [x] Stabile Breite: `tabular-nums` + `min-width: Nch` basierend auf Zielwert-Ziffernanzahl - [x] CSS-Variable `--color-text-soft` in tailwind.preset.ts (requiredCssVariables), Storybook-Theme, ocelot-ui-variables.scss - [x] 5 Webapp-Dateien migriert: UserTeaserPopover (statisch), TabNavigation (animated), admin/index (animated), profile/_slug (animated), groups/_slug (animated) - [x] CountTo.vue gelöscht, `vue-count-to` Dependency aus package.json entfernt - [x] `followedByCountStartValue` / `membersCountStartValue` Pattern entfernt (OsNumber watch-basiert) - [x] ds-number CSS aus `_ds-compat.scss` entfernt - [x] Admin-Dashboard: `.os-number-label { text-transform: uppercase }` per CSS (kein neuer Prop) - [x] Test-Fixes: Fehlende Count-Properties in Mock-Daten (followedByCount, contributionsCount, membersCount etc.) - [x] 11 Unit-Tests, 5 Stories, 5 Visual + A11y Tests **Zuvor abgeschlossen (Session 31 - ds-table → Plain HTML):** - [x] ds-table (7 Nutzungen) → native `` + CSS-Klassen (kein OsTable nötig) - [x] Table-CSS in `_ds-compat.scss`: .ds-table-wrap, .ds-table, .ds-table-col, .ds-table-head-col, .ds-table-bordered, .ds-table-condensed, Alignment-Klassen - [x] `fields()` / `tableFields()` Computed Properties aus allen 7 Dateien entfernt (Labels direkt in `
`) - [x] Alle 16 Tests bestanden (3 Test-Suites: admin/users Snapshots aktualisiert, FiledReportsTable ✅, ReportsTable ✅) **Zuvor abgeschlossen (Session 30 - OsBadge Code-Review Fixes):** - [x] `--color-default-contrast` zu `requiredCssVariables` in tailwind.preset.ts hinzugefügt - [x] Doppelte `--color-default`-Deklaration in ocelot-ui-variables.scss entfernt (softest → softer konsolidiert) - [x] Redundante Ternär-Ausdrücke entfernt: GroupTeaser.vue + groups/_slug.vue (`group ? group.about : ''` → `group.about`) - [x] `BadgeVariant` Typ hinzugefügt und in OsBadge.vue verwendet (statt `NonNullable`) - [x] Exports erweitert: BadgeVariant in index.ts + components/index.ts - [x] GroupForm.vue: `float: right` → `display: flex; flex-direction: column; align-self: flex-end` (konsistentes Flexbox-Layout) - [x] PlaygroundArgs in Stories: `string` → `BadgeVariant | BadgeSize | BadgeShape` (typsichere Story-Args) - [x] WithIcon-Story: Inline-Style `style="margin-right: 4px"` → Tailwind `class="mr-1"` - [x] ARIA Live Regions: `role="status" aria-live="polite"` auf 10 Form-Zähler + `role="alert" aria-live="assertive"` auf 1 Fehler-Badge - [x] `live` Prop entfernt — Standard-ARIA-Attribute werden direkt durchgereicht (attrs) - [x] KATALOG.md: Übersichtstabelle, Tier B Status, Komponenten-Tabelle, Zusammenfassungen aktualisiert **Zuvor abgeschlossen (Session 29 - OsBadge: ds-chip + ds-tag Migration):** - [x] OsBadge Komponente in packages/ui erstellt (CVA-Varianten, h() Render-Function) - [x] Props: variant (default/primary/danger), size (sm/md/lg), shape (pill/square) - [x] ds-chip → OsBadge: 20 Nutzungen in 5 Webapp-Dateien (GroupTeaser, GroupMember, GroupForm, ContributionForm, groups/_slug) - [x] ds-tag → OsBadge: 3 Nutzungen in 3 Webapp-Dateien (Category, Hashtag, PostTeaser CSS) - [x] CSS-Variable --color-default für neutralen Badge-Hintergrund - [x] Unit-Tests (16), Stories (6), Visual Tests (5+1 Keyboard), 100% Coverage - [x] Exports: OsBadge, badgeVariants, BadgeShape, BadgeSize, BadgeVariants **Zuvor abgeschlossen (Session 27 - Tier A: ds-* Komponenten → Plain HTML):** - [x] `_ds-compat.scss` erstellt (Utility-Klassen für Margins, Flex, Centered) - [x] `ds-section` → `
` (5 Dateien) - [x] `ds-placeholder` → `
` (4 Dateien) - [x] `ds-tag` → `` (2 Dateien) - [x] `ds-list` → `