UI-Gesamtumbau: Du-Form, Inspector-Panel, Onboarding-Assistent, Tour, Palette
Deploy App / deploy (push) Successful in 1m1s
Deploy App / deploy (push) Successful in 1m1s
Rein an der Oberflaeche -- Berechnung, Datenmodell und API-Semantik unveraendert (103 Tests unveraendert gruen). Paket A (Fundament): - durchgehend Du-Form und echte Umlaute in allen sichtbaren Texten, inkl. API-Fehlermeldungen (vorher Mix aus Sie/Du und ae/oe/ue) - neue UI-Primitiven (ui.tsx): Button, Modal mit ESC/Fokus-Falle/Animation, Bestaetigungs-Dialog statt window.confirm, Toasts statt alert, Skeleton-Loader, EmptyState - eigene Attention-Farbe (Amber) fuer offene Entscheide, getrennt vom Akzent - Micro-Interactions mit prefers-reduced-motion-Fallback Paket B (Onboarding, Roadmap Nr. 10): - gefuehrter Plan-Assistent in 5 Schritten; Einkommen bewusst pro Person (raeumt die 9.9-AHV-Falle aus); reine Orchestrierung bestehender Endpunkte - Beispielplan mit einem Klick; Uebergaenge absichtlich offen - interaktive Tour ueber die Planansicht (localStorage, jederzeit neu startbar) - abgeleitete "Naechste Schritte"-Karte (offene Entscheide, fehlende Elemente, fehlende Pensionsphase, Ruin -> Einflussfaktoren) Paket C (Struktur): - Inspector-Panel rechts statt Modals fuer alle Einzel-Bearbeitungen; Matrix bleibt sichtbar, Zellklick wechselt den Inhalt - Phasenkopf auf vier Kern-Infos entschlackt (Rest in der 0.11-Detailansicht) - Matrix mit eigenem Scrollbereich, Koepfe beidachsig fixiert - Sidebar-Gruppen "Meine Plaene" / "Wissen"; "So rechnet FPT" statt SPEZIFIKATION; "Szenario-Profil" statt "Plan-Einstellungen" - Aktions-Icons ohne Hover sichtbar (Touch) Paket D (Extras): - Sparklines je Element-Zeile aus den 0.11-Verlaufswerten - Befehls-Palette (Ctrl/Cmd+K) - Ruin-Banner verlinkt auf die Einflussfaktoren Nebenbei: der ProfileMenu-Lint-Fehler und der Selection-Rest (9.17) sind behoben -- npm run lint laeuft erstmals fehlerfrei. SPEZIFIKATION auf 0.13: neue Kapitel 3.2.8, 3.7.6-3.7.9, 9.23, 9.24; 3.6.3 und 3.7.1 ueberarbeitet, 9.17 bereinigt. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -30,18 +30,18 @@ import type {
|
||||
// --- Wasserfall ---------------------------------------------------------------------------
|
||||
// Bewusst NICHT mit Recharts, sondern als eigene HTML/CSS-Darstellung. Ein Wasserfall lebt
|
||||
// von drei Dingen, die Recharts hier nicht hergibt: Verbindungslinien zwischen den Balken
|
||||
// (ohne sie sieht man nicht, dass jeder Balken dort ansetzt, wo der vorherige aufhoert),
|
||||
// Wertbeschriftung an jedem Balken, und eine klare optische Trennung von Zwischenstaenden
|
||||
// und Veraenderungen.
|
||||
// (ohne sie sieht man nicht, dass jeder Balken dort ansetzt, wo der vorherige aufhört),
|
||||
// Wertbeschriftung an jedem Balken, und eine klare optische Trennung von Zwischenständen
|
||||
// und Veränderungen.
|
||||
//
|
||||
// Liegend statt stehend: Die Beschriftungen sind lang ("Wertsteigerung Immobilie"), stehend
|
||||
// muessten sie gedreht werden. Liegend ist es ausserdem konsistent zum Tornado.
|
||||
// müssten sie gedreht werden. Liegend ist es ausserdem konsistent zum Tornado.
|
||||
|
||||
interface WaterfallItem {
|
||||
label: string;
|
||||
value: number;
|
||||
total?: boolean; // Zwischen-/Endsumme: absoluter Stand statt Veraenderung
|
||||
section?: string; // optionale Abschnitts-Ueberschrift VOR diesem Eintrag
|
||||
total?: boolean; // Zwischen-/Endsumme: absoluter Stand statt Veränderung
|
||||
section?: string; // optionale Abschnitts-Überschrift VOR diesem Eintrag
|
||||
}
|
||||
|
||||
interface WaterfallRow {
|
||||
@@ -130,7 +130,7 @@ function Waterfall({ items }: { items: WaterfallItem[] }) {
|
||||
}}
|
||||
title={`${r.label}: ${formatChf(r.value)}`}
|
||||
/>
|
||||
{/* Verbindungslinie zum naechsten Balken: auf dem Stand NACH diesem Schritt */}
|
||||
{/* Verbindungslinie zum nächsten Balken: auf dem Stand NACH diesem Schritt */}
|
||||
{!isLast && (
|
||||
<div
|
||||
className="absolute border-l border-dotted border-faint"
|
||||
@@ -155,8 +155,8 @@ function Waterfall({ items }: { items: WaterfallItem[] }) {
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Zahlen mit laufendem Zwischenstand -- bei stark unterschiedlichen Groessenordnungen
|
||||
ist die Tabelle der Grafik ueberlegen. */}
|
||||
{/* Zahlen mit laufendem Zwischenstand -- bei stark unterschiedlichen Grössenordnungen
|
||||
ist die Tabelle der Grafik überlegen. */}
|
||||
<details className="mt-2">
|
||||
<summary className="cursor-pointer text-[11px] text-muted hover:text-fg">Zahlen mit Zwischenstand anzeigen</summary>
|
||||
<div className="mt-2 overflow-x-auto rounded-lg border border-border">
|
||||
@@ -190,9 +190,9 @@ function Waterfall({ items }: { items: WaterfallItem[] }) {
|
||||
);
|
||||
}
|
||||
|
||||
// Kontrollgroesse: Ist die Zerlegung vollstaendig, muss die Differenz zwischen Endwert und
|
||||
// Kontrollgrösse: Ist die Zerlegung vollständig, muss die Differenz zwischen Endwert und
|
||||
// der Summe der Schritte 0 sein. Sichtbar machen statt verstecken -- ein Wasserfall, der
|
||||
// nicht aufgeht, ist ein Fehler und kein Schoenheitsproblem.
|
||||
// nicht aufgeht, ist ein Fehler und kein Schönheitsproblem.
|
||||
function ResidualNote({ residual }: { residual: number }) {
|
||||
if (Math.abs(residual) <= 2) return null;
|
||||
return (
|
||||
@@ -367,7 +367,7 @@ export function ElementDetailDialog({
|
||||
onClose: () => void;
|
||||
onOpenSpec?: (anchor: string) => void;
|
||||
}) {
|
||||
// Verlauf ueber ALLE Phasen zusammensetzen.
|
||||
// Verlauf über ALLE Phasen zusammensetzen.
|
||||
const points = useMemo(() => {
|
||||
const out: ElementYearPoint[] = [];
|
||||
for (const ph of computed.phases) {
|
||||
@@ -479,7 +479,7 @@ export function ElementDetailDialog({
|
||||
// --- Phasen-Detailansicht ------------------------------------------------------------------
|
||||
|
||||
const ASSET_CATS: ElementCategory[] = ["PENSION_FUND", "PILLAR_3A", "REAL_ESTATE", "OTHER_ASSET"];
|
||||
const ALLOC_PALETTE = ["#4f46e5", "#0ea5e9", "#16a34a", "#d97706", "#dc2626", "#7c3aed"];
|
||||
const ALLOC_PALETTE = ["#4f46e5", "#0ea5e9", "#16a34a", "#d97706", "#dc2626", "#7c3äd"];
|
||||
|
||||
export function PhaseDetailDialog({
|
||||
phase,
|
||||
@@ -504,7 +504,7 @@ export function PhaseDetailDialog({
|
||||
[phase]
|
||||
);
|
||||
|
||||
const uebersicht = (
|
||||
const übersicht = (
|
||||
<>
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-4">
|
||||
<Kpi label="Typ" text={phase.type === "ERWERB" ? "Erwerb" : phase.type === "PENSION" ? "Pension" : "Misch"} />
|
||||
@@ -578,7 +578,7 @@ export function PhaseDetailDialog({
|
||||
subtitle={`Lebensphase ${phase.sequenceNumber} · ${phase.durationYears} Jahre`}
|
||||
onClose={onClose}
|
||||
tabs={[
|
||||
{ key: "uebersicht", label: "Übersicht", content: uebersicht },
|
||||
{ key: "übersicht", label: "Übersicht", content: übersicht },
|
||||
{ key: "wasserfall", label: "Wasserfall", content: wasserfall },
|
||||
{ key: "rechenweg", label: "Rechenweg", content: rechenweg },
|
||||
]}
|
||||
|
||||
Reference in New Issue
Block a user