VAT breakdown: left-aligned under Gesamtsumme label, first rate inline

Back to self-start (flush with "Gesamtsumme", not pinned under the total
€ amount). Multi-rate case switched from a stacked flex column to a
3-column CSS grid so the first rate sits on the same line as "enthält
MwSt.:" instead of dropping to its own row — grid auto-sizes each column
to its widest cell across all rows, so the rate column still stays
aligned between single- and double-digit rates without a hardcoded width.
This commit is contained in:
Marco
2026-07-22 23:56:35 +00:00
parent 02c3fef9b2
commit ddf842f910
+20 -22
View File
@@ -1,3 +1,4 @@
import { Fragment } from "react";
import { formatPrice } from "../lib/format";
import type { TaxBreakdownGroup } from "../lib/taxBreakdown";
@@ -6,39 +7,36 @@ import type { TaxBreakdownGroup } from "../lib/taxBreakdown";
// "which %" shown next to each line item elsewhere). One line per rate
// when a cart/order spans more than one; a single line otherwise.
//
// `self-end` (not `w-full`/`flex-1` spacer) — an earlier version
// right-aligned each € amount by spanning the row edge-to-edge across the
// full summary panel, matching the Gesamtsumme total line above it. That
// made this secondary "enthält X% MwSt." hint visually disconnect from
// its own label whenever the panel was wide, dragging the amount far off
// to the right. Sized to its own content instead and pinned to the right
// edge with `self-end`, so the whole block sits directly under the
// Gesamtsumme € amount above it (same right edge) rather than starting
// flush with the panel's left side. No `pl-2` indent on the per-rate rows
// either — since the block itself is now shrink-wrapped to its content
// width, an indent there would misalign the rows against the "enthält
// MwSt:" label sitting right above them; both start at the same x now.
// The rate column is still a fixed width (`w-8`) and right-aligned with
// `tabular-nums` (equal-width digits) so a single-digit rate like "7%"
// lines up with a two-digit one like "19%".
// `self-start` — the block starts flush left, at the same x as
// "Gesamtsumme" on the total row above it, not pinned under the
// amount on the right (tried that, didn't read right against the label).
//
// Multi-rate case is a 3-column CSS grid (label / rate / amount), not a
// flex column — the "enthält MwSt.:" label only occupies row 1's first
// cell (later rows get an empty cell there), so the first rate sits on
// the *same line* as the label instead of dropping to its own row below
// it. Grid (unlike stacked flex rows) sizes each column to the widest
// cell across every row automatically, so the rate column still lines up
// a single-digit rate ("7%") under a two-digit one ("19%") without
// needing an explicit fixed width.
export function VatBreakdown({ groups }: { groups: TaxBreakdownGroup[] }) {
if (groups.length === 0) return null;
if (groups.length === 1) {
const [g] = groups;
return (
<p className="self-end text-label text-text-muted">
<p className="self-start text-label text-text-muted">
enthält {g.rate}% MwSt.: {formatPrice(g.tax)}
</p>
);
}
return (
<div className="self-end flex flex-col gap-0.5">
<p className="text-label text-text-muted">enthält MwSt.:</p>
{groups.map((g) => (
<div key={g.rate} className="flex items-baseline gap-1.5">
<span className="w-8 shrink-0 text-right text-label text-text-muted tabular-nums">{g.rate}%</span>
<div className="self-start grid grid-cols-[auto_auto_auto] items-baseline gap-x-1.5 gap-y-0.5">
{groups.map((g, i) => (
<Fragment key={g.rate}>
<span className="text-label text-text-muted">{i === 0 ? "enthält MwSt.:" : ""}</span>
<span className="text-right text-label text-text-muted tabular-nums">{g.rate}%</span>
<span className="text-label text-text-muted tabular-nums">{formatPrice(g.tax)}</span>
</div>
</Fragment>
))}
</div>
);