mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 12:32:43 +00:00
fix(ui): conform the wellbeing card and fill lone grid items full-width
The mental-wellbeing instrument card carried a font-medium title and a gap-4 body, drifting from the medication card it should mirror; bring its title to text-lg font-semibold and its body to the shared space-y-3.5 rhythm. Several insight grids left a lone trailing tile stranded at half width with an empty column beside it. Gate each multi-column grid on having more than one item so a single tile spans the full row, and give the fixed five-card mood-correlation grid a trailing-card span so it no longer orphans on the two-up breakpoint. Add a little bottom breathing room to the device-score tile so its rolling-average line no longer reads flush against the card edge.
This commit is contained in:
1 parent
304f0c7057
commit
ca067bfe3d
7 files changed
+58
-10
No files matched your search
@@ -784,7 +784,14 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
|
||||
aria-label={
|
||||
isLoading ? t("insights.derived.vitals.loadingLabel") : undefined
|
||||
}
|
||||
className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3"
|
||||
className={cn(
|
||||
"grid grid-cols-1 gap-3",
|
||||
// Multi-column only when the skeleton row or more than one tile
|
||||
// fills it; a lone tile spans the full width rather than sitting
|
||||
// in a one-third column with dead space beside it.
|
||||
(isLoading || vitalTiles.length > 1) &&
|
||||
"sm:grid-cols-2 lg:grid-cols-3",
|
||||
)}
|
||||
>
|
||||
{isLoading
|
||||
? Array.from({ length: 6 }).map((_, i) => (
|
||||
@@ -806,7 +813,12 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
|
||||
/>
|
||||
<div
|
||||
data-slot="vitals-mobility-grid"
|
||||
className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3"
|
||||
className={cn(
|
||||
"grid grid-cols-1 gap-3",
|
||||
// A lone mobility tile spans the full width rather than
|
||||
// orphaning a one-third column.
|
||||
mobilityTiles.length > 1 && "sm:grid-cols-2 lg:grid-cols-3",
|
||||
)}
|
||||
>
|
||||
{mobilityTiles.map((tile) => tile.node)}
|
||||
</div>
|
||||
|
||||
@@ -121,7 +121,7 @@ export function DeviceScoreTile({
|
||||
</CardAction>
|
||||
) : null}
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<CardContent className="space-y-3 pb-1">
|
||||
{isLearning ? (
|
||||
<LearningGate
|
||||
compact
|
||||
|
||||
@@ -83,15 +83,21 @@ const STRENGTH_KEY: Record<CorrelationResult["strength"], string> = {
|
||||
function MoodCorrelationCard({
|
||||
kind,
|
||||
data,
|
||||
className,
|
||||
}: {
|
||||
kind: MetricKind;
|
||||
data: MoodMetricCorrelationData;
|
||||
className?: string;
|
||||
}) {
|
||||
const { t } = useTranslations();
|
||||
const hasResult = data.result != null && data.n >= 5;
|
||||
|
||||
return (
|
||||
<Card data-slot="mood-correlation-card" data-kind={kind}>
|
||||
<Card
|
||||
data-slot="mood-correlation-card"
|
||||
data-kind={kind}
|
||||
className={className}
|
||||
>
|
||||
<CardHeader className="pb-2">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<CardTitle className="text-sm font-semibold">
|
||||
@@ -165,7 +171,15 @@ export function MoodCorrelationCards({
|
||||
<MoodCorrelationCard kind="steps" data={steps} />
|
||||
<MoodCorrelationCard kind="pulse" data={pulse} />
|
||||
<MoodCorrelationCard kind="weight" data={weight} />
|
||||
<MoodCorrelationCard kind="bloodPressure" data={bloodPressureSystolic} />
|
||||
{/* Five fixed cards: on the two-up sm grid the trailing card lands
|
||||
alone in its row, so it spans full width there; the three-up lg
|
||||
grid leaves it paired (row of 3 + row of 2) and it stays one
|
||||
column. */}
|
||||
<MoodCorrelationCard
|
||||
kind="bloodPressure"
|
||||
data={bloodPressureSystolic}
|
||||
className="sm:col-span-2 lg:col-span-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import type { ComponentType } from "react";
|
||||
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
/**
|
||||
* v1.8.6 — narrative takeaway feed.
|
||||
@@ -69,7 +70,12 @@ export function MoodNarrativeFeed({ items }: { items: MoodNarrativeItem[] }) {
|
||||
// ladder. Lay them two-up on anything wider than a phone; a lone
|
||||
// takeaway still spans the row rather than orphaning half of it.
|
||||
<ul
|
||||
className="grid gap-2 sm:grid-cols-2"
|
||||
className={cn(
|
||||
"grid gap-2",
|
||||
// A lone takeaway spans the row rather than orphaning half of it;
|
||||
// two or more lay out two-up on anything wider than a phone.
|
||||
items.length > 1 && "sm:grid-cols-2",
|
||||
)}
|
||||
data-slot="mood-narrative-feed"
|
||||
aria-label={t("insights.mood.narrative.title")}
|
||||
>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Activity, Gauge, Moon, Repeat, Target, Waves } from "lucide-react";
|
||||
|
||||
import { useInsightsAnalytics } from "@/hooks/use-insights-analytics";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { SectionHeading } from "@/components/insights/section-heading";
|
||||
import { DeviceScoreTile } from "@/components/insights/device-score-tile";
|
||||
import { DeviceScoreGridSkeleton } from "@/components/insights/device-score-tile-skeleton";
|
||||
@@ -111,7 +112,14 @@ export function SleepQualitySection({ enabled }: { enabled: boolean }) {
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
<div className="grid gap-4 sm:grid-cols-2">
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-4",
|
||||
// Two-up only when more than one metric has data; a lone tile spans
|
||||
// the full row rather than leaving a half-width orphan.
|
||||
present.length > 1 && "sm:grid-cols-2",
|
||||
)}
|
||||
>
|
||||
{present.map((tile) => (
|
||||
<DeviceScoreTile
|
||||
key={tile.type}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { formatDate } from "@/lib/format";
|
||||
import { formatReferenceRange } from "@/lib/labs/reference-range";
|
||||
import { formatLabReading, formatLabValue } from "@/lib/labs/format-value";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { queryKeys } from "@/lib/query-keys";
|
||||
import { applyOrder, useModuleListPrefs } from "@/lib/module-list-prefs";
|
||||
|
||||
@@ -247,7 +248,14 @@ export function LabList({ onAddFirst }: { onAddFirst?: () => void } = {}) {
|
||||
// the line-1 chip, the panel as the category badge. v1.18.10 (#3) — no delete
|
||||
// control on the tile; the trash icon lives only on the value detail view.
|
||||
return (
|
||||
<ul className="grid list-none gap-4 p-0 sm:grid-cols-2">
|
||||
<ul
|
||||
className={cn(
|
||||
"grid list-none gap-4 p-0",
|
||||
// A lone lab spans the full row rather than orphaning half of it;
|
||||
// two or more fall into the two-up grid.
|
||||
groups.length > 1 && "sm:grid-cols-2",
|
||||
)}
|
||||
>
|
||||
{truncated ? (
|
||||
<li className="sm:col-span-2">
|
||||
<p className="text-muted-foreground text-xs">
|
||||
|
||||
@@ -36,9 +36,9 @@ export function InstrumentCard({
|
||||
|
||||
return (
|
||||
<Card className="h-full gap-3" data-slot="instrument-card">
|
||||
<CardContent className="flex h-full flex-col gap-4 p-4">
|
||||
<CardContent className="flex h-full flex-col space-y-3.5 p-4">
|
||||
<div className="flex flex-col gap-0.5">
|
||||
<span className="font-medium">
|
||||
<span className="text-lg leading-none font-semibold">
|
||||
{t(`mentalHealth.instrument.${key}`)}
|
||||
</span>
|
||||
<span className="text-muted-foreground text-xs">
|
||||
|
||||
Reference in new issue
Block a user