From 824e94a9bdf683d32944eadd6903270162cd086a Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Thu, 3 Sep 2026 18:52:25 +0200 Subject: [PATCH] feat(ui): surface the projected balance and fix interval clipping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PostTable gained a Projected column (both the sm: table and the mobile block markup) so the fold's second balance — what is left after unconfirmed recurring bills — is finally visible, muted so Remaining stays the primary figure. The legend now explains it. RecurringSection's interval input widened from w-14 to w-20 so two-digit values like 28 and 30 no longer collide with the native number spinner. Co-Authored-By: Claude Opus 5 (1M context) --- src/ui/components/PostTable.tsx | 18 ++++++++++++++++-- src/ui/routes/settings/RecurringSection.tsx | 2 +- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/ui/components/PostTable.tsx b/src/ui/components/PostTable.tsx index 66b90b8..0690c38 100644 --- a/src/ui/components/PostTable.tsx +++ b/src/ui/components/PostTable.tsx @@ -38,6 +38,10 @@ interface RowCells { charges: string; remaining: string; remainingTone: string; + /** What is left once unconfirmed recurring bills are counted too. Always + * rendered in the muted ink token, never toned, so `remaining` stays the + * one figure the eye lands on first. */ + projected: string; segments: MeterSegment[]; } @@ -59,6 +63,7 @@ function postRowCells({ figures }: MonthPostRow, fmt: MoneyFormat): RowCells { charges: fmt.amount(figures.charges), remaining: fmt.signedAmount(figures.remaining), remainingTone: figures.remaining < 0 ? "text-overspend" : "", + projected: fmt.signedAmount(figures.projected), segments: carryMeterSegments(figures), }; } @@ -70,7 +75,9 @@ function postRowCells({ figures }: MonthPostRow, fmt: MoneyFormat): RowCells { export function PostTableLegend({ baseCurrency }: { baseCurrency: Currency }) { return ( - All figures in {baseCurrency}. + + All figures in {baseCurrency}. Projected subtracts bills not yet confirmed. + @@ -178,6 +185,7 @@ export function PostTable({ monthId, rows, onChangeRule }: Props) { Allocated Spent Remaining + Projected {/* One tbody per post, holding the figures AND their meter. Multiple @@ -214,11 +222,14 @@ export function PostTable({ monthId, rows, onChangeRule }: Props) { > {cells.remaining} + + {cells.projected} + {/* The meter IS the row divider: tight under its own figures, with the gap below it. */} - + @@ -255,6 +266,9 @@ export function PostTable({ monthId, rows, onChangeRule }: Props) { spent {cells.charges} + + projected {cells.projected} + {/* Pushed to the right end of the line it wraps onto, so six of these down a phone screen read as a quiet affordance rather than as each row's primary action. */} diff --git a/src/ui/routes/settings/RecurringSection.tsx b/src/ui/routes/settings/RecurringSection.tsx index 237ae5a..1917e70 100644 --- a/src/ui/routes/settings/RecurringSection.tsx +++ b/src/ui/routes/settings/RecurringSection.tsx @@ -55,7 +55,7 @@ export function RecurringSection() { return (