fix(dashboard): symmetric tile widths, BP back to two tiles

Marc's v1.4.3 feedback:
  - Tiles end up the same height now but uneven widths — they should
    distribute symmetrically across the strip.
  - BP shouldn't be one combined tile; sys + dia should sit side by
    side as two distinct tiles like every other metric.

Two fixes:

1. **Strip wrapper switches from `shrink-0 grow basis-[10rem]` to
   `flex-1 basis-0 min-w-[9rem]`.** With `basis-[10rem]` the floor
   was 160 px, and tiles whose content rendered wider (the combined
   BP tile rendering "117.0/79.0 mmHg" plus a paired avg row) pushed
   past their share, breaking symmetry. `flex-1 basis-0` starts every
   tile from zero, so the row-width gets divided evenly regardless of
   how much text each card contains. `min-w-[9rem]` is the readable
   floor — if the row no longer fits at that width, the parent's
   existing `overflow-x-auto` lets the user swipe instead of wrap.

2. **BP renders as two tiles again.** Reverted the v1.4.3 combined
   `secondary` rendering: the dashboard now pushes a `bp-sys` and
   a `bp-dia` entry, ordered with a 0.001 sub-step so dia stays
   immediately after sys without colliding with the next widget's
   integer order. The `secondary` prop on TrendCard stays in the
   API for callers that *do* want a paired-value tile.

Tests + typecheck green (671/671).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc-André BombeckandClaude Opus 4.7 committed 2026-05-08 22:14:24 +02:00
1 parent 2ff215af7e
commit cbded7c39e
3 files changed
+68 -17

No files matched your search

+16
View File
@@ -1,5 +1,21 @@
# Changelog
## [1.4.4] — 2026-05-08
### Fixed — Dashboard
- **Blood pressure is now two distinct tiles again** (sys + dia next
to each other) — the v1.4.3 attempt at a combined tile read as a
single double-wide entry, which Marc preferred to keep as two
separate tiles for visual rhythm with the other metrics.
- **All tiles share an equal width.** The previous strip used
`shrink-0 grow basis-[10rem]`, which gave each tile a 160 px floor
and let wider content (like the BP tile) push past it. Switched
to `flex-1 basis-0 min-w-[9rem]` — every tile now starts from
zero and gets the same share of the available row width, with a
9 rem floor so they stay readable on narrow viewports. The strip
scrolls horizontally if the row no longer fits.
## [1.4.3] — 2026-05-08
### Fixed — Dashboard
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "healthlog",
"version": "1.4.3",
"version": "1.4.4",
"private": true,
"packageManager": "pnpm@10.31.0",
"scripts": {
+51 -16
View File
@@ -460,20 +460,18 @@ export default function DashboardPage() {
});
}
if (showBpCards) {
// BP renders as ONE tile with paired sys/dia values (e.g. "117/79")
// so the strip width matches the chart strip below — and so the
// tile count stays at 5 instead of 6 with a wrap-around. The
// sparkline/trend arrow follows the systolic value (the common
// primary signal); the colour-banding tooltips cover sys only
// because dia uses a different target range and stuffing both
// into one hint became unreadable on mobile.
// BP is conceptually one signal but visually two tiles (sys + dia)
// so the user sees both numbers side by side at the same size as
// every other tile in the strip. v1.4.3 first attempted a
// combined tile with `secondary` values — Marc preferred two
// distinct tiles with consistent symmetric widths.
trendCards.push({
id: "bp",
id: "bp-sys",
order: widgetOrder("bp"),
node: (
<TrendCard
key="bp"
label={t("dashboard.bloodPressure")}
key="bp-sys"
label={t("dashboard.bloodPressureSys")}
latest={sys?.latest ?? null}
unit="mmHg"
avg7={sys?.avg7 ?? null}
@@ -498,11 +496,42 @@ export default function DashboardPage() {
)}
slope30={sys?.slope30 ?? null}
icon={Heart}
secondary={{
latest: dia?.latest ?? null,
avg7: dia?.avg7 ?? null,
avg30: dia?.avg30 ?? null,
}}
/>
),
});
trendCards.push({
id: "bp-dia",
// Sub-order keeps dia immediately after sys; the +0.001 leaves
// headroom for any future BP-related tile slotted between them.
order: widgetOrder("bp") + 0.001,
node: (
<TrendCard
key="bp-dia"
label={t("dashboard.bloodPressureDia")}
latest={dia?.latest ?? null}
unit="mmHg"
avg7={dia?.avg7 ?? null}
avg30={dia?.avg30 ?? null}
avg7ColorClass={getRangeColorClass(dia?.avg7, {
range: bpDiaRange,
})}
avg30ColorClass={getRangeColorClass(dia?.avg30, {
range: bpDiaRange,
})}
avg7Hint={getRangeHint(
"mmHg",
{ range: bpDiaRange },
t,
fmt.number,
)}
avg30Hint={getRangeHint(
"mmHg",
{ range: bpDiaRange },
t,
fmt.number,
)}
slope30={dia?.slope30 ?? null}
icon={Heart}
/>
),
});
@@ -857,9 +886,15 @@ export default function DashboardPage() {
data-tile-count={trendCards.length}
>
{trendCards.map((entry) => (
// `flex-1 basis-0` distributes the strip width evenly across
// every tile so 5 tiles or 7 tiles both look symmetric — no
// tile claims more horizontal space because its content is
// wider. `min-w-[9rem]` keeps the cells readable on narrow
// viewports; if the row no longer fits, the parent's
// `overflow-x-auto` lets the user swipe instead of wrapping.
<div
key={entry.id}
className="flex shrink-0 grow basis-[10rem] snap-start"
className="flex min-w-[9rem] flex-1 basis-0 snap-start"
>
{entry.node}
</div>