375 lines
15 KiB
Markdown
375 lines
15 KiB
Markdown
# Design-System-Fundament Implementation Plan
|
|
|
|
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
|
|
**Goal:** Legt die technische und visuelle Basis für das TeamWallet-Redesign: Design-Tokens, ein eigenes Material-3-Theme (fintech-modern, Indigo/Grün), ein konsistentes Icon-System und ein bereinigtes Notification-System — ohne die bestehenden Bildschirme inhaltlich umzubauen (das folgt in Folge-Plänen für Public-Übersicht, Dashboard/Team-Workspace, Auth-Flows).
|
|
|
|
**Architecture:** Zwei neue SCSS-Partials (`src/styles/_tokens.scss`, `src/styles/_theme.scss`) werden aus `src/styles.scss` eingebunden. Die Angular-Material-Theming-API (`mat.define-theme`, installiert in `node_modules/@angular/material/core/theming/_definition.scss`) erzeugt das Theme aus vordefinierten M3-Paletten (`mat.$blue-palette` als Primary, `mat.$spring-green-palette` als Tertiary) statt des Stock-Themes `azure-blue`. Reine CSS-Custom-Properties (nicht Sass-Variablen) tragen Spacing/Radius/Elevation/Balance-Farben, damit sie direkt in Komponenten-Templates/-Styles nutzbar sind, auch außerhalb von Sass-Kontext.
|
|
|
|
**Tech Stack:** Angular 18.1, Angular Material 18.1 (M3-Theming-API), SCSS, Angular CLI Builder (`@angular-devkit/build-angular:browser`), Karma/Jasmine.
|
|
|
|
## Global Constraints
|
|
|
|
- Kein Dark Mode in diesem Plan — Tokens müssen aber so benannt/strukturiert sein, dass ein späteres Dark-Theme sie überschreiben kann (semantische Namen, keine rohen Paletten-Referenzen in Komponenten).
|
|
- Keine neuen Abhängigkeiten hinzufügen; stattdessen wird die ungenutzte Abhängigkeit `@ngxpert/hot-toast` entfernt.
|
|
- Bestehende deutsche UI-Texte bleiben unverändert (i18n-Audit ist ein separater Folge-Plan).
|
|
- Nach jedem Task muss `npm run build` (aus `myteamwallet_frontend/`) fehlerfrei durchlaufen.
|
|
- Angular Material 18 M3-Theming bietet **keine** Funktion, aus einem beliebigen Hex-Wert eine Palette zu generieren (verifiziert: `_palettes.scss` enthält nur die zwölf vordefinierten Paletten `red/green/blue/yellow/cyan/magenta/orange/chartreuse/spring-green/azure/violet/rose`). Primary/Tertiary werden daher aus diesen vordefinierten Paletten gewählt, nicht aus Wunsch-Hexcodes.
|
|
|
|
---
|
|
|
|
### Task 1: Design-Tokens (Spacing, Radius, Elevation, Balance-Farben)
|
|
|
|
**Files:**
|
|
- Create: `myteamwallet_frontend/src/styles/_tokens.scss`
|
|
- Modify: `myteamwallet_frontend/src/styles.scss`
|
|
|
|
**Interfaces:**
|
|
- Produces: CSS-Custom-Properties auf `:root` — `--tw-space-{1,2,3,4,6,8}`, `--tw-radius-{sm,md,lg}`, `--tw-elevation-{1,2}`, `--tw-balance-positive`, `--tw-balance-negative`, `--tw-balance-neutral`, `--tw-surface-bg`, `--tw-surface-card`. Alle Folge-Tasks/-Pläne referenzieren ausschließlich diese Namen, nie rohe Hex-Werte.
|
|
|
|
- [ ] **Step 1: `_tokens.scss` anlegen**
|
|
|
|
```scss
|
|
// myteamwallet_frontend/src/styles/_tokens.scss
|
|
:root {
|
|
// Spacing (8px-Grid)
|
|
--tw-space-1: 4px;
|
|
--tw-space-2: 8px;
|
|
--tw-space-3: 12px;
|
|
--tw-space-4: 16px;
|
|
--tw-space-6: 24px;
|
|
--tw-space-8: 32px;
|
|
|
|
// Radius
|
|
--tw-radius-sm: 8px;
|
|
--tw-radius-md: 12px;
|
|
--tw-radius-lg: 16px;
|
|
|
|
// Elevation (ersetzt die bisher wiederholte box-shadow-Deklaration)
|
|
--tw-elevation-1: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 3px rgba(15, 23, 42, 0.1);
|
|
--tw-elevation-2: 0 2px 4px rgba(15, 23, 42, 0.06), 0 4px 8px rgba(15, 23, 42, 0.1);
|
|
|
|
// Semantische Saldo-Farben (fintech-modern: gedämpftes Grün/Rot statt Signalfarben)
|
|
--tw-balance-positive: #1b8a5a;
|
|
--tw-balance-negative: #c4351c;
|
|
--tw-balance-neutral: #64748b;
|
|
|
|
// Flächen
|
|
--tw-surface-bg: #f7f8fa;
|
|
--tw-surface-card: #ffffff;
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 2: In `styles.scss` einbinden und bestehende Hardcodes ersetzen**
|
|
|
|
In `myteamwallet_frontend/src/styles.scss` ganz oben ergänzen:
|
|
|
|
```scss
|
|
@use './styles/tokens';
|
|
```
|
|
|
|
Danach folgende bestehende Stellen in derselben Datei ersetzen:
|
|
|
|
```scss
|
|
// vorher: body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; background-color: #fafafa;}
|
|
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; background-color: var(--tw-surface-bg); }
|
|
```
|
|
|
|
```scss
|
|
// vorher in .card:
|
|
// box-shadow: 0 2px 1px -1px #0003, 0 1px 1px #00000024, 0 1px 3px #0000001f;
|
|
.card {
|
|
padding: var(--tw-space-3);
|
|
box-shadow: var(--tw-elevation-1);
|
|
margin: var(--tw-space-1);
|
|
background-color: var(--tw-surface-card);
|
|
border-radius: var(--tw-radius-md);
|
|
|
|
&.flat {
|
|
background-color: transparent;
|
|
box-shadow: none;
|
|
outline: #ddd solid 1px;
|
|
}
|
|
}
|
|
```
|
|
|
|
```scss
|
|
// vorher: background-color: rgb(148, 16, 16) !important;
|
|
.snackbar_error > .mdc-snackbar__surface {
|
|
background-color: var(--tw-balance-negative) !important;
|
|
|
|
.mat-mdc-snack-bar-label {
|
|
color: white !important;
|
|
}
|
|
}
|
|
```
|
|
|
|
- [ ] **Step 3: Build verifizieren**
|
|
|
|
Run: `cd myteamwallet_frontend && npm run build`
|
|
Expected: Build erfolgreich, keine Sass-/Compile-Fehler.
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add myteamwallet_frontend/src/styles/_tokens.scss myteamwallet_frontend/src/styles.scss
|
|
git commit -m "feat(design): add design tokens and wire into global styles"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 2: Eigenes Material-3-Theme statt Stock-Theme
|
|
|
|
**Files:**
|
|
- Create: `myteamwallet_frontend/src/styles/_theme.scss`
|
|
- Modify: `myteamwallet_frontend/src/styles.scss`
|
|
- Modify: `myteamwallet_frontend/angular.json:35` (build-Styles), `myteamwallet_frontend/angular.json:125` (test-Styles)
|
|
- Modify: `myteamwallet_frontend/src/index.html`
|
|
|
|
**Interfaces:**
|
|
- Consumes: nichts aus Task 1 direkt (unabhängiges Partial), wird aber in derselben `styles.scss` eingebunden.
|
|
- Produces: Sass-Variable `theme.$teamwallet-theme`, die alle Material-Komponentenstyles erzeugt. Spätere Pläne fügen hier bei Bedarf `mat.theme-overrides()` hinzu, ändern aber nicht den Namen `$teamwallet-theme`.
|
|
|
|
- [ ] **Step 1: `_theme.scss` anlegen**
|
|
|
|
```scss
|
|
// myteamwallet_frontend/src/styles/_theme.scss
|
|
@use '@angular/material' as mat;
|
|
|
|
$teamwallet-theme: mat.define-theme((
|
|
color: (
|
|
theme-type: light,
|
|
primary: mat.$blue-palette,
|
|
tertiary: mat.$spring-green-palette,
|
|
),
|
|
typography: (
|
|
brand-family: 'Inter, Roboto, "Helvetica Neue", sans-serif',
|
|
plain-family: 'Inter, Roboto, "Helvetica Neue", sans-serif',
|
|
),
|
|
density: (
|
|
scale: 0,
|
|
),
|
|
));
|
|
```
|
|
|
|
- [ ] **Step 2: Theme in `styles.scss` einbinden (ersetzt Stock-Theme-Import)**
|
|
|
|
Am Anfang von `myteamwallet_frontend/src/styles.scss` ergänzen (vor den bestehenden Regeln):
|
|
|
|
```scss
|
|
@use '@angular/material' as mat;
|
|
@use './styles/theme';
|
|
|
|
@include mat.core();
|
|
@include mat.all-component-themes(theme.$teamwallet-theme);
|
|
```
|
|
|
|
- [ ] **Step 3: Stock-Theme aus `angular.json` entfernen**
|
|
|
|
In `myteamwallet_frontend/angular.json` im `build`-Target die Zeile entfernen:
|
|
|
|
```json
|
|
"@angular/material/prebuilt-themes/azure-blue.css",
|
|
```
|
|
|
|
Im `test`-Target die Zeile entfernen:
|
|
|
|
```json
|
|
"@angular/material/prebuilt-themes/cyan-orange.css",
|
|
```
|
|
|
|
In beiden Targets bleibt `"src/styles.scss"` als einziger globaler Stylesheet-Eintrag stehen.
|
|
|
|
- [ ] **Step 4: Google-Font auf Inter umstellen**
|
|
|
|
In `myteamwallet_frontend/src/index.html` die bestehende Roboto-Zeile ersetzen:
|
|
|
|
```html
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
```
|
|
|
|
- [ ] **Step 5: Build und Tests verifizieren**
|
|
|
|
Run: `cd myteamwallet_frontend && npm run build`
|
|
Expected: Build erfolgreich, Material-Komponenten (Buttons, Toolbar, Cards) werden aus dem neuen Theme gestylt statt aus `azure-blue.css`.
|
|
|
|
Run: `cd myteamwallet_frontend && npm test -- --watch=false`
|
|
Expected: Bestehende Karma-Suite läuft weiterhin durch (keine Test-Regression durch den Theme-Wechsel).
|
|
|
|
- [ ] **Step 6: Commit**
|
|
|
|
```bash
|
|
git add myteamwallet_frontend/src/styles/_theme.scss myteamwallet_frontend/src/styles.scss myteamwallet_frontend/angular.json myteamwallet_frontend/src/index.html
|
|
git commit -m "feat(design): replace stock Material azure-blue theme with custom M3 theme"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 3: Icon-System auf Material Symbols umstellen, PNG-Icon-Klassen entfernen
|
|
|
|
**Files:**
|
|
- Modify: `myteamwallet_frontend/src/index.html`
|
|
- Modify: `myteamwallet_frontend/src/app/app.component.ts`
|
|
- Modify: `myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.ts`
|
|
- Modify: `myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.html`
|
|
- Modify: `myteamwallet_frontend/src/styles.scss`
|
|
- Delete: `myteamwallet_frontend/src/assets/edit.png`, `myteamwallet_frontend/src/assets/dashboard.png`, `myteamwallet_frontend/src/assets/tacho.png`
|
|
|
|
**Interfaces:**
|
|
- Consumes: nichts.
|
|
- Produces: `<mat-icon>`-basierte Icons überall; keine PNG-Icon-Klassen (`icon`, `icon_edit`, `icon_dashboard`, `icon_tacho`) mehr im Code. Verifiziert: diese Klassen werden ausschließlich in `dashboard.component.html` verwendet (`icon_tacho`, `icon_edit`; `icon_dashboard` ist bereits toter Code).
|
|
|
|
- [ ] **Step 1: Material Symbols statt Material Icons laden**
|
|
|
|
In `myteamwallet_frontend/src/index.html` die Material-Icons-Zeile ersetzen:
|
|
|
|
```html
|
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap" rel="stylesheet">
|
|
```
|
|
|
|
- [ ] **Step 2: Default-Fontset der App auf Material Symbols umstellen**
|
|
|
|
In `myteamwallet_frontend/src/app/app.component.ts`:
|
|
|
|
```ts
|
|
import { Component } from '@angular/core';
|
|
import { TranslateService } from '@ngx-translate/core';
|
|
import { environment } from './../environments/environment';
|
|
import { SwUpdate } from '@angular/service-worker';
|
|
import { MatIconRegistry } from '@angular/material/icon';
|
|
|
|
@Component({
|
|
selector: 'app-root',
|
|
templateUrl: './app.component.html',
|
|
styleUrls: ['./app.component.scss']
|
|
})
|
|
export class AppComponent {
|
|
version = environment.appVersion;
|
|
|
|
constructor(translate: TranslateService, updates: SwUpdate, iconRegistry: MatIconRegistry) {
|
|
iconRegistry.setDefaultFontSetClass('material-symbols-outlined');
|
|
translate.setDefaultLang('de');
|
|
translate.use('de');
|
|
this.update(updates);
|
|
}
|
|
// ... rest unverändert
|
|
```
|
|
|
|
(Restlichen Methodenkörper `update()` unverändert lassen.)
|
|
|
|
- [ ] **Step 3: Dashboard-Icons auf `mat-icon` umstellen**
|
|
|
|
In `myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.ts` `MatIconModule` importieren:
|
|
|
|
```ts
|
|
import { MatIconModule } from '@angular/material/icon';
|
|
// ...
|
|
@Component({
|
|
selector: 'app-dashboard',
|
|
templateUrl: './dashboard.component.html',
|
|
styleUrls: ['./dashboard.component.scss'],
|
|
standalone: true,
|
|
imports: [ CommonModule, TranslateModule, MatButtonModule, MatIconModule ]
|
|
})
|
|
```
|
|
|
|
In `myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.html` ersetzen:
|
|
|
|
```html
|
|
<!-- vorher -->
|
|
<div class="icons">
|
|
<div class="icon icon_tacho" matRipple (click)="onTeamClick(p.team)"></div>
|
|
<div class="icon icon_edit" matRipple (click)="onTeamClick(p.team)"></div>
|
|
</div>
|
|
```
|
|
|
|
```html
|
|
<!-- nachher -->
|
|
<div class="icons">
|
|
<button mat-icon-button (click)="onTeamClick(p.team)" aria-label="Team-Details öffnen">
|
|
<mat-icon>speed</mat-icon>
|
|
</button>
|
|
<button mat-icon-button (click)="onTeamClick(p.team)" aria-label="Team bearbeiten">
|
|
<mat-icon>edit</mat-icon>
|
|
</button>
|
|
</div>
|
|
```
|
|
|
|
- [ ] **Step 4: Tote Icon-Klassen aus `styles.scss` entfernen**
|
|
|
|
In `myteamwallet_frontend/src/styles.scss` den gesamten Block entfernen:
|
|
|
|
```scss
|
|
.icon { ... }
|
|
.icon_edit { ... }
|
|
.icon_dashboard { ... }
|
|
.icon_tacho { ... }
|
|
```
|
|
|
|
(Alle vier Regeln inkl. der `.icon:hover`-Verschachtelung löschen — keine andere Datei referenziert diese Klassen mehr.)
|
|
|
|
- [ ] **Step 5: Ungenutzte PNG-Assets löschen**
|
|
|
|
```bash
|
|
git rm myteamwallet_frontend/src/assets/edit.png myteamwallet_frontend/src/assets/dashboard.png myteamwallet_frontend/src/assets/tacho.png
|
|
```
|
|
|
|
- [ ] **Step 6: Build verifizieren und visuell prüfen**
|
|
|
|
Run: `cd myteamwallet_frontend && npm run build`
|
|
Expected: Build erfolgreich, keine fehlenden Asset-Referenzen.
|
|
|
|
Run: `cd myteamwallet_frontend && npm start`, Dashboard im Browser öffnen (`http://localhost:4200/dashboard`, eingeloggt).
|
|
Expected: Statt der beiden PNG-Icons erscheinen die Material-Symbols-Icons „speed“ und „edit“, klickbar wie zuvor.
|
|
|
|
- [ ] **Step 7: Commit**
|
|
|
|
```bash
|
|
git add myteamwallet_frontend/src/index.html myteamwallet_frontend/src/app/app.component.ts myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.ts myteamwallet_frontend/src/app/modules/home/dashboard/dashboard.component.html myteamwallet_frontend/src/styles.scss
|
|
git commit -m "feat(design): migrate to Material Symbols, remove PNG icon classes"
|
|
```
|
|
|
|
---
|
|
|
|
### Task 4: Notification-System bereinigen
|
|
|
|
**Files:**
|
|
- Modify: `myteamwallet_frontend/package.json`
|
|
|
|
**Interfaces:**
|
|
- Consumes: `--tw-balance-negative`-Token aus Task 1 (bereits in `.snackbar_error` verdrahtet).
|
|
- Produces: keine neuen Symbole — reine Bereinigung.
|
|
|
|
Verifiziert: `@ngxpert/hot-toast` ist in `package.json` als Abhängigkeit deklariert, wird aber im gesamten `src/`-Verzeichnis nirgends importiert (`HotToastService`/`@ngxpert/hot-toast` liefert null Treffer). Es gibt also kein zweites, konkurrierendes Toast-System im Code — nur eine tote Abhängigkeit. Die tatsächliche Benachrichtigung läuft ausschließlich über `MatSnackBar` (3 Aufrufstellen, alle in `team-details.component.ts`), deren Fehler-Variante bereits in Task 1 auf den neuen Token umgestellt wurde.
|
|
|
|
- [ ] **Step 1: Ungenutzte Abhängigkeit entfernen**
|
|
|
|
In `myteamwallet_frontend/package.json` die Zeile aus `dependencies` entfernen:
|
|
|
|
```json
|
|
"@ngxpert/hot-toast": "3.0.0",
|
|
```
|
|
|
|
- [ ] **Step 2: Lockfile aktualisieren**
|
|
|
|
Run: `cd myteamwallet_frontend && npm install`
|
|
Expected: `package-lock.json` aktualisiert sich, `@ngxpert/hot-toast` verschwindet aus dem Dependency-Baum, keine anderen Pakete werden unerwartet verändert.
|
|
|
|
- [ ] **Step 3: Build verifizieren**
|
|
|
|
Run: `cd myteamwallet_frontend && npm run build`
|
|
Expected: Build weiterhin erfolgreich (bestätigt, dass das Paket wirklich ungenutzt war).
|
|
|
|
- [ ] **Step 4: Commit**
|
|
|
|
```bash
|
|
git add myteamwallet_frontend/package.json myteamwallet_frontend/package-lock.json
|
|
git commit -m "chore(deps): remove unused @ngxpert/hot-toast dependency"
|
|
```
|
|
|
|
---
|
|
|
|
## Hinweis für Folge-Pläne
|
|
|
|
Die Wrapper-Komponenten-Bibliothek (`BalanceDisplay`, `PageHeader`, `SectionCard`, `EmptyState`, `StatTile` aus dem Gesamtplan) wird bewusst **nicht** in diesem Fundament-Plan gebaut, sondern erst in dem Folge-Plan, der ihren ersten echten Verwendungsort umbaut (Public-Team-Übersicht bzw. Dashboard/Team-Workspace) — YAGNI: eine Komponenten-Bibliothek ohne Konsumenten lässt sich nicht sinnvoll gegen echte Anforderungen entwerfen. Dieser Fundament-Plan liefert die Basis (Tokens, Theme, Icons, saubere Notifications), auf der diese Komponenten aufbauen.
|