mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-08 04:32:42 +00:00
Add a subtitle slot to the insights overview section heading
Detail pages already render a one-line description under their heading; the overview section headings had no slot for one. Add an optional subtitle to SectionHeading, rendered in the same muted typography, and wire it into the obvious top-level sections: Trends (folding its existing right-aligned caption into the slot), Your health scores, and Your vitals.
This commit is contained in:
1 parent
f5e9d875cc
commit
07b65ade88
6 files changed
+31
-8
No files matched your search
@@ -3240,6 +3240,7 @@
|
||||
},
|
||||
"vitals": {
|
||||
"sectionTitle": "Deine Vitalwerte",
|
||||
"sectionSubtitle": "Ruhewerte von Herz-Kreislauf und Atmung im Vergleich zu deiner eigenen Baseline",
|
||||
"loadingLabel": "Vitalwerte werden geladen",
|
||||
"loadError": "Deine Vitalwerte konnten gerade nicht geladen werden.",
|
||||
"building": "Typischer Bereich entsteht — {count} von {target} Tagen",
|
||||
@@ -3366,6 +3367,7 @@
|
||||
},
|
||||
"scores": {
|
||||
"sectionTitle": "Deine Gesundheitswerte",
|
||||
"sectionSubtitle": "Zusammengesetzte Werte für Erholung, Stress und Belastung aus deinen verbundenen Geräten",
|
||||
"loadError": "Deine Wellness-Werte konnten gerade nicht geladen werden.",
|
||||
"recovery": "Erholung",
|
||||
"stress": "Stress",
|
||||
|
||||
@@ -3240,6 +3240,7 @@
|
||||
},
|
||||
"vitals": {
|
||||
"sectionTitle": "Your vitals",
|
||||
"sectionSubtitle": "Resting cardiovascular and respiratory signals against your own baseline",
|
||||
"loadingLabel": "Loading your vitals",
|
||||
"loadError": "Could not load your vitals right now.",
|
||||
"building": "Building your typical range — {count} of {target} days",
|
||||
@@ -3366,6 +3367,7 @@
|
||||
},
|
||||
"scores": {
|
||||
"sectionTitle": "Your health scores",
|
||||
"sectionSubtitle": "Composite recovery, stress and strain read from your connected devices",
|
||||
"loadError": "Could not load your wellness scores right now.",
|
||||
"recovery": "Recovery",
|
||||
"stress": "Stress",
|
||||
|
||||
@@ -729,6 +729,7 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
|
||||
<SectionHeading
|
||||
icon={HeartPulse}
|
||||
title={t("insights.derived.vitals.sectionTitle")}
|
||||
subtitle={t("insights.derived.vitals.sectionSubtitle")}
|
||||
/>
|
||||
<div
|
||||
data-slot="vitals-dashboard-error"
|
||||
@@ -774,6 +775,7 @@ export function VitalsDashboard({ batch, layout, className }: DashboardProps) {
|
||||
<SectionHeading
|
||||
icon={HeartPulse}
|
||||
title={t("insights.derived.vitals.sectionTitle")}
|
||||
subtitle={t("insights.derived.vitals.sectionSubtitle")}
|
||||
/>
|
||||
<div
|
||||
data-slot="vitals-dashboard-grid"
|
||||
|
||||
@@ -211,6 +211,7 @@ export function WellnessScores({
|
||||
<SectionHeading
|
||||
icon={Activity}
|
||||
title={t("insights.derived.scores.sectionTitle")}
|
||||
subtitle={t("insights.derived.scores.sectionSubtitle")}
|
||||
/>
|
||||
<div
|
||||
data-slot="wellness-scores-error"
|
||||
@@ -394,6 +395,7 @@ export function WellnessScores({
|
||||
<SectionHeading
|
||||
icon={Activity}
|
||||
title={t("insights.derived.scores.sectionTitle")}
|
||||
subtitle={t("insights.derived.scores.sectionSubtitle")}
|
||||
/>
|
||||
<div
|
||||
data-slot="wellness-scores-grid"
|
||||
|
||||
@@ -34,6 +34,14 @@ interface SectionHeadingProps {
|
||||
icon: ComponentType<{ className?: string }>;
|
||||
/** Heading text rendered inside the `<h2>`. */
|
||||
title: ReactNode;
|
||||
/**
|
||||
* Optional one-line description rendered directly under the `<h2>`, in the
|
||||
* same muted typography the detail pages use beneath their headings
|
||||
* (`text-muted-foreground text-sm`). Opt-in per section so the overview can
|
||||
* carry the "descriptive line under every heading" rule without forcing a
|
||||
* subtitle where none reads well.
|
||||
*/
|
||||
subtitle?: ReactNode;
|
||||
/** Optional trailing affordance pinned to the right edge of the row. */
|
||||
action?: ReactNode;
|
||||
/** Optional id on the `<h2>`, e.g. for an `aria-labelledby` link. */
|
||||
@@ -44,6 +52,7 @@ interface SectionHeadingProps {
|
||||
export function SectionHeading({
|
||||
icon: Icon,
|
||||
title,
|
||||
subtitle,
|
||||
action,
|
||||
id,
|
||||
className,
|
||||
@@ -58,9 +67,19 @@ export function SectionHeading({
|
||||
>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<Icon className="text-foreground h-5 w-5 shrink-0" aria-hidden="true" />
|
||||
<h2 id={id} className="text-base font-semibold">
|
||||
{title}
|
||||
</h2>
|
||||
<div className="min-w-0">
|
||||
<h2 id={id} className="text-base font-semibold">
|
||||
{title}
|
||||
</h2>
|
||||
{subtitle ? (
|
||||
<p
|
||||
data-slot="section-heading-subtitle"
|
||||
className="text-muted-foreground text-sm"
|
||||
>
|
||||
{subtitle}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{action ? (
|
||||
<div className="flex shrink-0 items-center gap-2">{action}</div>
|
||||
|
||||
@@ -200,11 +200,7 @@ export function TrendsRow({
|
||||
<SectionHeading
|
||||
icon={TrendingUp}
|
||||
title={t("insights.trendsRow.title")}
|
||||
action={
|
||||
<p className="text-muted-foreground text-xs">
|
||||
{t("insights.trendsRow.subtitle")}
|
||||
</p>
|
||||
}
|
||||
subtitle={t("insights.trendsRow.subtitle")}
|
||||
/>
|
||||
{/* v1.4.22 A4 — equal-height cards. The annotation prose
|
||||
below each chart varies in length, which used to leave the
|
||||
|
||||
Reference in new issue
Block a user