mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
fix(insights): keep charts from crushing the layout in landscape
Fixed-pixel chart bands ate roughly half the screen when a small phone was rotated to landscape. Swap the brittle heights for viewport-relative clamps so the chart envelope holds its previous size on desktop and portrait but shrinks toward a floor on short landscape viewports. Covers the overview trends-row slot and the mood distribution, weekday, and time-of-day charts (with matching skeleton heights). Chart series and styling are untouched; only the container heights flex.
This commit is contained in:
1 parent
fa161f7f12
commit
ba497f4ae8
6 files changed
+27
-9
No files matched your search
@@ -106,7 +106,7 @@ describe("<TrendsRow>", () => {
|
||||
expect(slots.length).toBe(3);
|
||||
});
|
||||
|
||||
it("pins every chart slot to h-[180px] so Recharts mounts with a known size (CLS fix)", () => {
|
||||
it("pins every chart slot to a known responsive height so Recharts mounts with a size (CLS fix)", () => {
|
||||
// v1.4.36 W2 — without an explicit height the Recharts
|
||||
// ResponsiveContainer mounts with width=-1 height=-1 and emits a
|
||||
// console warning per chart. The mood card also drifted taller
|
||||
@@ -119,12 +119,17 @@ describe("<TrendsRow>", () => {
|
||||
// TrendAnnotation row below — visible as text sitting on top of
|
||||
// the chart. 180 px absorbs the full envelope so the three tiles
|
||||
// share one chart-band baseline without overlap.
|
||||
//
|
||||
// v1.22.0 — the slot height became `clamp(140px,32vh,180px)` so a
|
||||
// rotated phone doesn't lose half the screen to the fixed band. The
|
||||
// 180 px envelope still holds on desktop + portrait (where 32vh
|
||||
// clears 180 px); only short landscape viewports shrink to the floor.
|
||||
const html = render(<TrendsRow />);
|
||||
const slots =
|
||||
html.match(/data-slot="trends-row-chart-slot"[^>]*class="[^"]*"/g) ?? [];
|
||||
expect(slots.length).toBe(3);
|
||||
for (const slot of slots) {
|
||||
expect(slot).toMatch(/h-\[180px\]/);
|
||||
expect(slot).toMatch(/h-\[clamp\(140px,32vh,180px\)\]/);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ export function MoodDistributionChart({
|
||||
// v1.15.14 — bounded compact height (was `aspect-[3/2] min-h-[180px]`,
|
||||
// which ballooned the card on a wide viewport). A fixed band keeps this a
|
||||
// tidy card rather than a dominant block, and matches the weekday sibling.
|
||||
<div className="h-[150px] w-full">
|
||||
<div className="h-[clamp(120px,26vh,150px)] w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={data}
|
||||
|
||||
@@ -46,7 +46,9 @@ const MoodDistributionChart = dynamic(
|
||||
})),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <Skeleton className="h-[150px] w-full rounded-md" />,
|
||||
loading: () => (
|
||||
<Skeleton className="h-[clamp(120px,26vh,150px)] w-full rounded-md" />
|
||||
),
|
||||
},
|
||||
);
|
||||
const MoodWeekdayChart = dynamic(
|
||||
@@ -56,7 +58,9 @@ const MoodWeekdayChart = dynamic(
|
||||
})),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <Skeleton className="h-[150px] w-full rounded-md" />,
|
||||
loading: () => (
|
||||
<Skeleton className="h-[clamp(120px,26vh,150px)] w-full rounded-md" />
|
||||
),
|
||||
},
|
||||
);
|
||||
const MoodTimeOfDayChart = dynamic(
|
||||
@@ -66,7 +70,9 @@ const MoodTimeOfDayChart = dynamic(
|
||||
})),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <Skeleton className="h-[220px] w-full rounded-md" />,
|
||||
loading: () => (
|
||||
<Skeleton className="h-[clamp(160px,38vh,220px)] w-full rounded-md" />
|
||||
),
|
||||
},
|
||||
);
|
||||
import { MoodTagBreakdown, type MoodTagRow } from "./mood-tag-breakdown";
|
||||
|
||||
@@ -78,7 +78,7 @@ export function MoodTimeOfDayChart({
|
||||
width-constrained), so an aspect ratio derived the height off the full
|
||||
card width and ballooned the chart to ~800px on a wide viewport. A
|
||||
bounded height keeps it the same size as the sibling charts. */}
|
||||
<div className="h-[220px] w-full">
|
||||
<div className="h-[clamp(160px,38vh,220px)] w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={data}
|
||||
|
||||
@@ -77,7 +77,7 @@ export function MoodWeekdayChart({ weekday }: { weekday: MoodWeekdayRow[] }) {
|
||||
which derived its height off the full card width and ballooned on a
|
||||
wide viewport). A fixed band keeps it a tidy card matching the
|
||||
distribution sibling. */}
|
||||
<div className="h-[150px] w-full">
|
||||
<div className="h-[clamp(120px,26vh,150px)] w-full">
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<BarChart
|
||||
data={data}
|
||||
|
||||
@@ -277,7 +277,14 @@ export function TrendsRow({
|
||||
lives entirely on this slot. */}
|
||||
<div
|
||||
data-slot="trends-row-chart-slot"
|
||||
className="h-[180px] shrink-0 overflow-hidden [--chart-height:120px]"
|
||||
// v1.22.0 — the slot height is responsive to the viewport so a
|
||||
// rotated phone doesn't lose half the screen to a fixed 180 px
|
||||
// band. `clamp(140px,32vh,180px)` pins the same 180 px envelope
|
||||
// on desktop + portrait (where 32vh clears 180 px) and only
|
||||
// shrinks toward the 140 px floor on short landscape viewports.
|
||||
// `overflow-hidden` already clips any stray axis label, so the
|
||||
// tighter band stays tidy.
|
||||
className="h-[clamp(140px,32vh,180px)] shrink-0 overflow-hidden [--chart-height:120px]"
|
||||
>
|
||||
<MetricChart config={config} title={title} />
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user