c2fb82b0de
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>
59 lines
2.1 KiB
TypeScript
59 lines
2.1 KiB
TypeScript
"use client";
|
|
|
|
import { useEffect, useState } from "react";
|
|
import ReactMarkdown from "react-markdown";
|
|
import remarkGfm from "remark-gfm";
|
|
import rehypeSlug from "rehype-slug";
|
|
import { FileText } from "lucide-react";
|
|
import { api } from "@/lib/api-client";
|
|
|
|
// Rendert SPEZIFIKATION.md (via /api/spec) als lesbares Dokument. Das Styling läuft über
|
|
// die Klasse .md-doc in globals.css und folgt damit dem gewählten Farbschema.
|
|
export function SpecView({ anchor }: { anchor?: string | null }) {
|
|
const [markdown, setMarkdown] = useState<string | null>(null);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
api
|
|
.get<{ markdown: string }>("/api/spec")
|
|
.then((data) => setMarkdown(data.markdown))
|
|
.catch((e) => setError(e instanceof Error ? e.message : "Laden fehlgeschlagen."));
|
|
}, []);
|
|
|
|
// Sprungmarke aus einem Rechenweg: erst nach dem Rendern des Markdowns existiert die
|
|
// Überschrift mit der von rehype-slug erzeugten id.
|
|
useEffect(() => {
|
|
if (!anchor || markdown === null) return;
|
|
const el = document.getElementById(anchor);
|
|
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
}, [anchor, markdown]);
|
|
|
|
if (error) return <p className="text-sm text-danger">{error}</p>;
|
|
if (markdown === null) return <p className="text-sm text-muted">Lädt…</p>;
|
|
|
|
return (
|
|
<div className="flex flex-col gap-4">
|
|
<div className="flex items-center gap-2">
|
|
<FileText className="h-5 w-5 text-accent" />
|
|
<h2 className="text-lg font-semibold text-fg">Spezifikation</h2>
|
|
</div>
|
|
<article className="md-doc rounded-xl border border-border bg-surface p-6 shadow-sm lg:p-8">
|
|
<ReactMarkdown
|
|
remarkPlugins={[remarkGfm]}
|
|
rehypePlugins={[rehypeSlug]}
|
|
components={{
|
|
// Breite Tabellen scrollen in ihrem eigenen Container statt die Seite zu dehnen.
|
|
table: ({ children, ...props }) => (
|
|
<div className="md-table-wrap">
|
|
<table {...props}>{children}</table>
|
|
</div>
|
|
),
|
|
}}
|
|
>
|
|
{markdown}
|
|
</ReactMarkdown>
|
|
</article>
|
|
</div>
|
|
);
|
|
}
|