mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
Make every metric subpage identical by construction in the shared scaffold rather than per-page bespoke. - Target tile matches the other cards: dark `bg-card` background and the `rounded-xl border p-4` spacing the assessment and stat-strip cards use, instead of the old translucent `bg-card/20` panel. - Drop the 7T/30T/90T/1J range row and its "+X% vs previous" delta from every subpage. The chart owns its own window via its in-card range tabs, so the chart query is unaffected. Retire the now-dead `MetricRangeControls`, `MetricRangeDelta`, `TimeRangePills`, `useAnalyticsRange`, the `useInsightsRangePref` persisted-range hook, and `sentimentFromMetricDirection` along with their tests. - Fix the spine order to intro -> chart -> target card -> assessment -> Min/Max/Median/Mittelwert stat strip. The stat strip moves to the foot of the spine, below the assessment. Remove the "Letzte Messung" card and the headline primary tile from subpages; retire `MetricLastMeasurementCard` and `MetricPrimaryTile`. - Blood pressure gains the stat strip it was missing: two stacked systolic / diastolic strips, since a single-series strip would drop the diastolic half. `MetricStatStrip` takes an optional series caption. Update the spine guard to assert the target card precedes the assessment and that the retired range row and last-measurement card appear on no subpage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> (cherry picked from commit 80b2a810314b4c0951c0d68c04bffc89003005d6)
56 lines
2.3 KiB
TypeScript
56 lines
2.3 KiB
TypeScript
/**
|
|
* v1.9.0 — shared metric-aware trend sentiment helpers.
|
|
*
|
|
* Extracted from `trend-card.tsx` so the range-delta caption (the time-range
|
|
* pills feature) paints the exact same colour for the same signal as the
|
|
* dashboard tiles. The mapping is the v1.5 phase-5 audit's: an upward move is
|
|
* good for some metrics (mood, HRV, steps), bad for others (resting HR,
|
|
* weight, body fat), and value-judgement-free for the rest.
|
|
*/
|
|
|
|
/**
|
|
* Maps a metric's "up means" direction to colour sentiment.
|
|
*
|
|
* - `up-good` — higher value is better (mood, HRV, steps). ↑ green, ↓ orange.
|
|
* - `up-bad` — higher value is worse (resting HR, weight, body fat).
|
|
* ↑ orange, ↓ green.
|
|
* - `neutral` — direction carries no value judgement (the change renders
|
|
* muted).
|
|
*/
|
|
export type TrendDirectionSentiment = "up-good" | "up-bad" | "neutral";
|
|
|
|
/**
|
|
* The resolved sentiment of a signed change under a metric's direction.
|
|
*
|
|
* - `positive` — the change moves the metric toward its goal. Renders green.
|
|
* - `negative` — the change moves away from the goal. Renders orange.
|
|
* - `neutral` — the metric's direction is neutral, or the change is below
|
|
* the noise floor (|change| < 0.05). Renders muted.
|
|
*/
|
|
export type TrendSentimentDirection = "positive" | "negative" | "neutral";
|
|
|
|
export function getTrendSentiment(
|
|
change: number | null | undefined,
|
|
sentiment: TrendDirectionSentiment,
|
|
): TrendSentimentDirection {
|
|
if (change == null || Math.abs(change) < 0.05) return "neutral";
|
|
if (sentiment === "neutral") return "neutral";
|
|
const isUp = change > 0;
|
|
const isGood =
|
|
(sentiment === "up-good" && isUp) || (sentiment === "up-bad" && !isUp);
|
|
return isGood ? "positive" : "negative";
|
|
}
|
|
|
|
export function sentimentColorClass(
|
|
direction: TrendSentimentDirection,
|
|
): string {
|
|
// Semantic tokens, not raw --dracula-*: `--success` / `--warning` alias
|
|
// the same Dracula green/orange in dark mode (pixel-identical there) but
|
|
// carry the AA-safe `:root.light` overrides, so the trend arrow + delta
|
|
// clear AA on the white card instead of the ~1.2:1 the raw primitives hit.
|
|
if (direction === "positive") return "text-success";
|
|
if (direction === "negative") return "text-warning";
|
|
return "text-muted-foreground";
|
|
}
|
|
|