mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(insights): drop the empty tail on the signal and narrative cards
Both overview cards carried a min-h floor sized for their tallest state and applied it to every state, so the calm everyday read left a large empty band at the bottom. - Today's signal: the min-h-48 floor now applies only to the tall `fired` state; all-clear / watch / insufficient size to their short content. - Period overview: the resolved card drops the min-h-40 floor and the footer's mt-auto that pinned the timestamp to the bottom of the floored height. The in-flight skeletons keep their min-h footprint, so the first paint still reserves the row and does not shift as the read resolves.
This commit is contained in:
1 parent
93bdbd8e0c
commit
4e2248dfff
2 files changed
+24
-16
No files matched your search
@@ -81,8 +81,9 @@ function CoincidentProvenance({
|
||||
|
||||
/**
|
||||
* The card shell — uppercase label + the provenance affordance, with the
|
||||
* state-specific body as children. Keeps every state on one card geometry so
|
||||
* the page reserves a stable footprint.
|
||||
* state-specific body as children. The tall `fired` state keeps a `min-h` floor;
|
||||
* the calmer everyday states size to their (short) content so the card carries
|
||||
* no empty tail.
|
||||
*/
|
||||
function CardShell({
|
||||
state,
|
||||
@@ -99,13 +100,15 @@ function CardShell({
|
||||
data-slot="coincident-deviation-card"
|
||||
data-state={state}
|
||||
className={cn(
|
||||
// `min-h` sized to the tallest realistic state (fired: 44px provenance
|
||||
// header + the named-vitals body + the mandatory factors line). Every
|
||||
// calmer state shares this footprint so the card — and everything below
|
||||
// it on the overview — never shifts as the state resolves (the CLS the
|
||||
// design pass closes). `min-h` not fixed `h`: a rare taller body still
|
||||
// grows, it just never shrinks below the reserved height.
|
||||
"bg-card flex min-h-48 w-full min-w-0 flex-col gap-2 rounded-xl border p-4 md:p-6",
|
||||
"bg-card flex w-full min-w-0 flex-col gap-2 rounded-xl border p-4 md:p-6",
|
||||
// `min-h` floor only on the tallest state (fired: 44px provenance header
|
||||
// + the named-vitals body + the mandatory factors line). The calmer
|
||||
// everyday states (all-clear / watch / insufficient) carry a single
|
||||
// short body, so flooring them to the fired height left a large empty
|
||||
// tail; they now size to their content. The in-flight `CardSkeleton`
|
||||
// keeps the `min-h-48` footprint so the initial paint still reserves the
|
||||
// row and does not shift as the read resolves.
|
||||
state === "fired" && "min-h-48",
|
||||
// At most amber — never destructive/red. The fired state borders
|
||||
// warning; every calmer state keeps the neutral card border.
|
||||
state === "fired" ? "border-warning/40" : "border-border",
|
||||
|
||||
@@ -22,10 +22,10 @@ import {
|
||||
* fresh one out of band, so this card never blocks on the provider.
|
||||
*
|
||||
* Restraint guarantees: plain React text children (NO markdown — the whole
|
||||
* tree forbids a markdown library for XSS reasons), no score, no chart, a
|
||||
* single ⓘ provenance disclosure, and a fixed `min-h` footprint shared across
|
||||
* the loading / preparing / resolved states so the card — and everything below
|
||||
* it on the overview — never shifts (no CLS).
|
||||
* tree forbids a markdown library for XSS reasons), no score, no chart, and a
|
||||
* single ⓘ provenance disclosure. The in-flight skeleton reserves a `min-h`
|
||||
* footprint so the first paint holds the row open (CLS-safe); the resolved card
|
||||
* then sizes to its content so a short narrative leaves no empty tail.
|
||||
*/
|
||||
|
||||
type NarrativePeriod = "week" | "month";
|
||||
@@ -98,7 +98,12 @@ function ProvenanceDisclosure({
|
||||
}
|
||||
|
||||
const SHELL =
|
||||
"bg-card border-border flex min-h-40 w-full min-w-0 flex-col gap-3 rounded-xl border p-4 md:p-6";
|
||||
"bg-card border-border flex w-full min-w-0 flex-col gap-3 rounded-xl border p-4 md:p-6";
|
||||
// The in-flight skeleton keeps a `min-h` floor so the initial paint reserves the
|
||||
// row (CLS-safe). The resolved card drops the floor and sizes to its content —
|
||||
// a short narrative used to leave a large empty tail under the prose, widened by
|
||||
// the footer's `mt-auto` pinning it to the bottom of the floored height.
|
||||
const SKELETON_SHELL = `${SHELL} min-h-40`;
|
||||
|
||||
export function PeriodNarrativeCard({
|
||||
enabled = true,
|
||||
@@ -123,7 +128,7 @@ export function PeriodNarrativeCard({
|
||||
<div
|
||||
data-slot="period-narrative-card-skeleton"
|
||||
aria-hidden="true"
|
||||
className={cn(SHELL, className)}
|
||||
className={cn(SKELETON_SHELL, className)}
|
||||
>
|
||||
<div className="flex h-7 items-center justify-between gap-2">
|
||||
<div className="bg-muted/40 h-3 w-32 rounded" />
|
||||
@@ -199,7 +204,7 @@ export function PeriodNarrativeCard({
|
||||
)}
|
||||
|
||||
{narrative ? (
|
||||
<p className="text-muted-foreground mt-auto text-[11px]">
|
||||
<p className="text-muted-foreground text-[11px]">
|
||||
{data?.revalidating
|
||||
? t("insights.narrativeUpdating")
|
||||
: t("insights.narrativeUpdated", {
|
||||
|
||||
Reference in new issue
Block a user