Skip to content

fix(dashboard): stop Account Balances and Investments from clipping their own numbers - #159

Merged
KenTaniguchi-R merged 1 commit into
mainfrom
fix/dashboard-widget-clipping
Sep 6, 2026
Merged

fix(dashboard): stop Account Balances and Investments from clipping their own numbers#159
KenTaniguchi-R merged 1 commit into
mainfrom
fix/dashboard-widget-clipping

Conversation

@KenTaniguchi-R

Copy link
Copy Markdown
Owner

Summary

  • Both widgets wrap a scrollable list in overflow-y-auto without constraining the horizontal axis, so a row wider than the card drags a hidden horizontal scrollbar along with it — the Card's own overflow-hidden then clips whatever's past the edge (the leading "-$" on a negative balance, a long ticker/security name).
  • account-balances.tsx: table-fixed + a fixed-width balance column so the amount can never be pushed off-screen.
  • investments-widget.tsx: add the min-w-0 the row was missing, matching the pattern every other dashboard widget already uses.
  • Spending widget's legend/truncation was reviewed too (mock: https://claude.ai/code/artifact/9f2341d9-b961-4f1d-8870-8cfe7d7701a1) but left as-is by request — its existing behavior is a normal ellipsis truncation, not this clipping bug.

Test plan

  • pnpm typecheck passes
  • pnpm lint passes
  • Verified visually against local dev server — no regressions on Account Balances / Investments widgets
  • No automated regression tests added — pure CSS/class fix, no existing component-test convention in this repo to extend

🤖 Generated with Claude Code

…heir own numbers

Both widgets wrap a scrollable list in overflow-y-auto without constraining
the other axis, so a row wider than the card (a long name, or an
auto-layout table column) drags a hidden horizontal scrollbar along with
it -- and the Card's own overflow-hidden then clips whatever's past the
edge, including the balance's leading "-$".

- account-balances.tsx: table-fixed + a fixed-width balance column so the
  amount can never be pushed off-screen.
- investments-widget.tsx: add the min-w-0 the row was missing, matching
  the pattern every other dashboard widget already uses.
@KenTaniguchi-R
KenTaniguchi-R merged commit 4d17504 into main Sep 6, 2026
5 checks passed
@KenTaniguchi-R
KenTaniguchi-R deleted the fix/dashboard-widget-clipping branch September 6, 2026 03:18
KenTaniguchi-R added a commit that referenced this pull request Sep 6, 2026
Ship #157 (exclude investment-account activity from spending/income) and
#159 (dashboard number clipping), which have sat on main since v0.3.0
without a published image — :latest only moves on a v* tag.

Also bumps package.json, which v0.3.0 forgot: /api/health reads its
version from here via APP_VERSION, so the deployed app has been
reporting 0.2.0 while running 0.3.0 code.
KenTaniguchi-R added a commit that referenced this pull request Sep 7, 2026
#159 stopped investment activity counting toward spending, but the list
still rendered those rows at full weight — the arithmetic changed and the
page did not. A day holding a $1,000 brokerage buy read as $1,000 gone
while Reports, Budgets and the dashboard all disagreed.

Transfer rows now take muted text rather than `opacity-60`: opacity is
already spent on `pending`, and stacking the two leaves a pending transfer
barely readable. Muting the amount also drops its `text-positive` green,
which money moved between your own accounts never earned.

Date headers net spending only, and name the two counts apart once a
transfer is present ("2 spending · 2 transfers") — the count and the net
beside it otherwise described different sets of rows with nothing saying so.
KenTaniguchi-R added a commit that referenced this pull request Sep 7, 2026
The widget flattened every account into one undifferentiated table, so an
$18,240 savings balance and a -$8,400 loan read as the same kind of number
with nothing marking which side of the sheet each was on.

Reuses groupAccountsByType — the helper already behind the Accounts page —
rather than adding a second grouping, so the widget and the page it links
to name, order and total their sections identically.

The raw <table> stays deliberately: shadcn's <Table> wraps itself in an
`overflow-x-auto` container, which is the horizontal scrollbar #159 removed
from this widget. Group headers are ordinary rows of the same table so the
pinned balance column still can't be pushed past the card's edge.
KenTaniguchi-R added a commit that referenced this pull request Sep 7, 2026
…glance (#161)

* feat(transactions): let transfers recede in the list

#159 stopped investment activity counting toward spending, but the list
still rendered those rows at full weight — the arithmetic changed and the
page did not. A day holding a $1,000 brokerage buy read as $1,000 gone
while Reports, Budgets and the dashboard all disagreed.

Transfer rows now take muted text rather than `opacity-60`: opacity is
already spent on `pending`, and stacking the two leaves a pending transfer
barely readable. Muting the amount also drops its `text-positive` green,
which money moved between your own accounts never earned.

Date headers net spending only, and name the two counts apart once a
transfer is present ("2 spending · 2 transfers") — the count and the net
beside it otherwise described different sets of rows with nothing saying so.

* feat(dashboard): show the assets and debts behind net worth

$77,506.89 could be a paid-off house or a leveraged brokerage account.
The hero stated one number and nothing about the position producing it.

getDashboardSummary already summed both sides to produce netWorth and then
threw them away; it now returns them. The pair sits on the figure row
rather than under it, so the hero keeps its height on a page that already
has a lot below it, and it uses BalanceDisplay — the component the Accounts
page totals its groups with — so a debt reads as a debt here without a
second colour convention.

* feat(dashboard): group account balances by type, with subtotals

The widget flattened every account into one undifferentiated table, so an
$18,240 savings balance and a -$8,400 loan read as the same kind of number
with nothing marking which side of the sheet each was on.

Reuses groupAccountsByType — the helper already behind the Accounts page —
rather than adding a second grouping, so the widget and the page it links
to name, order and total their sections identically.

The raw <table> stays deliberately: shadcn's <Table> wraps itself in an
`overflow-x-auto` container, which is the horizontal scrollbar #159 removed
from this widget. Group headers are ordinary rows of the same table so the
pinned balance column still can't be pushed past the card's edge.
KenTaniguchi-R added a commit that referenced this pull request Sep 7, 2026
…for Bills and reconciliation (#165)

* refactor(filters): give the two hand-rolled option lists real keyboard nav

Both built their options from raw `<button>`s inside a `PopoverContent`, so
each option cost a Tab stop and the arrow keys did nothing.

The Type filter is a plain single-select list, so it becomes a
`DropdownMenu` with a `DropdownMenuRadioGroup` — roving focus, typeahead,
`role="menuitem"` and Esc, all from the component. A radio group needs a
value for every row and `null` is not one, so the "All types" row carries an
`ALL_TYPES` sentinel that maps back to null at the boundary.

The date presets could not follow it there. They share their popover with
the custom-range From/To inputs, and Base UI's menu typeahead
(`floating-ui-react/hooks/useTypeahead`) has no guard for typeable targets —
inside a menu, typing a date would move the menu selection instead of
filling the field. They become a vertical `ToggleGroup` instead, which is
also a roving-focus composite: one Tab stop, arrow keys, Home/End, and the
inputs keep working. No typeahead there, which is the honest trade.

Nothing moves visually. Both lists keep `h-8`, `px-2` and the same hover
fill.

* refactor(tables): build Bills and reconciliation from the Table component

Both hand-rolled `<table>` and re-added, by hand, the `overflow-x-auto`
container `ui/table.tsx` already ships — the same scroll wrapper written
twice, in two slightly different ways.

Rows sit a little tighter: `Table` pads cells `p-2` where these files set
`px-3` and `px-4`. Reconciliation keeps its `px-4` because its four columns
have room for it; Bills takes the component's spacing. Both keep their
`min-w-[560px]`, so the mobile fix from the responsive pass still holds —
the scrolling just happens in Table's container now.

`widgets/account-balances.tsx` is deliberately left alone. Its `colgroup`,
`table-fixed` and per-group `tbody` came from #161 and are doing work Table
does not help with; converting it would put the #159 clipping fix at risk
for no gain.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant