Modul-Review 2 Feinschliff: Assistent, Tour, 3-Spalten-Ansicht
Deploy App / deploy (push) Successful in 1m8s
Deploy App / deploy (push) Successful in 1m8s
Sechs Punkte aus der Testrunde: Assistent: - Willkommens-Screen (Gesamtbild der 5 Schritte) + persistente Schritt-Leiste - Rendite-Feld bei PK/3a/Wertschriften ergaenzt (war fest verdrahtet) - Schritt 5: Hypothekarzinsen (falls nicht in Ausgaben) korrekt bei den Ausgaben dazugerechnet; "noch zu verteilen" prominent nach oben; Verteilung nach Gemeinsam/Person A/Person B gruppiert Tour: - Spotlight: Rest abgedunkelt (9999px box-shadow), staerkerer Puls - Karte groesser + springt auf die gegenueberliegende Bildschirmhaelfte - "Ueberspringen"-Knopf Ansicht: - Grundprofil + Zeitachse + Kennzahlen (Endvermoegen nom/real, Ruin) als ein kompakter 3-Spalten-Block (25/50/25%) statt zweier breiter Zeilen - neue Modal-Groesse xwide Kein Eingriff in den Rechenkern; 267 Tests unveraendert. SPEZIFIKATION 0.29. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+44
-31
@@ -58,6 +58,9 @@ export function Tour({ onClose }: { onClose: () => void }) {
|
||||
[]
|
||||
);
|
||||
const [index, setIndex] = useState(0);
|
||||
// Die Karte springt auf die dem Ziel GEGENÜBERliegende Bildschirmhälfte, damit sie das
|
||||
// hervorgehobene Element nie verdeckt.
|
||||
const [cardAtBottom, setCardAtBottom] = useState(true);
|
||||
const step = steps[index];
|
||||
|
||||
useEffect(() => {
|
||||
@@ -66,6 +69,9 @@ export function Tour({ onClose }: { onClose: () => void }) {
|
||||
if (!el) return;
|
||||
el.classList.add("tour-highlight");
|
||||
el.scrollIntoView({ block: "center", behavior: "smooth" });
|
||||
const rect = el.getBoundingClientRect();
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- Position aus der DOM-Lage des Ziels
|
||||
setCardAtBottom(rect.top + rect.height / 2 < window.innerHeight * 0.5);
|
||||
return () => el.classList.remove("tour-highlight");
|
||||
}, [step]);
|
||||
|
||||
@@ -81,15 +87,20 @@ export function Tour({ onClose }: { onClose: () => void }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ui-pop fixed bottom-4 left-1/2 z-40 w-[26rem] max-w-[calc(100vw-2rem)] -translate-x-1/2 rounded-2xl border border-border bg-surface p-4 shadow-2xl">
|
||||
<div
|
||||
key={index}
|
||||
className={`ui-pop fixed left-1/2 z-50 w-[32rem] max-w-[calc(100vw-2rem)] -translate-x-1/2 rounded-2xl border-2 border-accent bg-surface p-5 shadow-2xl ${
|
||||
cardAtBottom ? "bottom-8" : "top-8"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="flex h-7 w-7 items-center justify-center rounded-lg bg-accent-soft text-accent-soft-fg">
|
||||
<Lightbulb className="h-4 w-4" />
|
||||
<div className="flex items-center gap-2.5">
|
||||
<span className="flex h-9 w-9 items-center justify-center rounded-xl bg-accent text-accent-fg shadow-sm">
|
||||
<Lightbulb className="h-5 w-5" />
|
||||
</span>
|
||||
<div>
|
||||
<div className="text-sm font-semibold text-fg">{step.title}</div>
|
||||
<div className="text-[11px] text-faint">
|
||||
<div className="text-base font-semibold text-fg">{step.title}</div>
|
||||
<div className="text-[11px] font-medium uppercase tracking-wide text-accent">
|
||||
Schritt {index + 1} von {steps.length}
|
||||
</div>
|
||||
</div>
|
||||
@@ -103,31 +114,33 @@ export function Tour({ onClose }: { onClose: () => void }) {
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<p className="mt-2 text-sm leading-relaxed text-muted">{step.text}</p>
|
||||
<div className="mt-3 flex items-center justify-between">
|
||||
<div className="flex gap-1">
|
||||
{steps.map((_, i) => (
|
||||
<span
|
||||
key={i}
|
||||
className={`h-1.5 w-1.5 rounded-full ${i === index ? "bg-accent" : "bg-border-strong"}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{index > 0 && (
|
||||
<Button variant="secondary" size="sm" onClick={() => setIndex(index - 1)}>
|
||||
Zurück
|
||||
</Button>
|
||||
)}
|
||||
{index < steps.length - 1 ? (
|
||||
<Button size="sm" onClick={() => setIndex(index + 1)}>
|
||||
Weiter
|
||||
</Button>
|
||||
) : (
|
||||
<Button size="sm" onClick={finish}>
|
||||
Fertig
|
||||
</Button>
|
||||
)}
|
||||
<p className="mt-3 text-sm leading-relaxed text-muted">{step.text}</p>
|
||||
<div className="mt-4 flex items-center justify-between gap-2">
|
||||
<button type="button" onClick={finish} className="text-xs font-medium text-faint hover:text-muted">
|
||||
Überspringen
|
||||
</button>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex gap-1">
|
||||
{steps.map((_, i) => (
|
||||
<span key={i} className={`h-1.5 w-1.5 rounded-full ${i === index ? "bg-accent" : "bg-border-strong"}`} />
|
||||
))}
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{index > 0 && (
|
||||
<Button variant="secondary" size="sm" onClick={() => setIndex(index - 1)}>
|
||||
Zurück
|
||||
</Button>
|
||||
)}
|
||||
{index < steps.length - 1 ? (
|
||||
<Button size="sm" onClick={() => setIndex(index + 1)}>
|
||||
Weiter
|
||||
</Button>
|
||||
) : (
|
||||
<Button size="sm" onClick={finish}>
|
||||
Fertig
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user