HRV balanced dots, dashed gap lines, dashboard widgets + drag-to-edit layout
- Green dots for balanced HRV (joining orange unbalanced / red low) on the trend - Trend charts bridge data gaps with a dashed line instead of a blank break - Dashboard: drop Health today; add VO2 max, small sleep, and HRV status widgets - Dashboard: editable widget grid (react-grid-layout) with drag/resize, saved per-user Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useState, useMemo } from 'react'
|
||||
import { useQuery, keepPreviousData } from '@tanstack/react-query'
|
||||
import {
|
||||
AreaChart, Area, BarChart, Bar, ReferenceLine, ReferenceArea,
|
||||
AreaChart, Area, ComposedChart, Line, BarChart, Bar, ReferenceLine, ReferenceArea,
|
||||
XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell,
|
||||
} from 'recharts'
|
||||
import { format, subDays, differenceInCalendarDays, parseISO } from 'date-fns'
|
||||
@@ -651,7 +651,7 @@ function DailySnapshot({ day, snapshotWeight, avg30, intradayHr, bodyBattery, bb
|
||||
|
||||
// Highlight problem days on a trend line by colouring the dot from a status field
|
||||
// (e.g. HRV status): orange = unbalanced, red = low/poor. Other days get no dot.
|
||||
const STATUS_DOT_COLORS = { unbalanced: '#f97316', low: '#ef4444', poor: '#ef4444' }
|
||||
const STATUS_DOT_COLORS = { balanced: '#22c55e', unbalanced: '#f97316', low: '#ef4444', poor: '#ef4444' }
|
||||
const statusDot = (statusKey) => (props) => {
|
||||
const { cx, cy, payload } = props
|
||||
const color = STATUS_DOT_COLORS[String(payload?.[statusKey] || '').toLowerCase()]
|
||||
@@ -666,7 +666,7 @@ function MetricChart({ data, dataKey, color, formatter, height = 140, selectedDa
|
||||
)
|
||||
return (
|
||||
<ResponsiveContainer width="100%" height={height}>
|
||||
<AreaChart
|
||||
<ComposedChart
|
||||
data={data}
|
||||
margin={{ top: 4, right: 4, bottom: 4, left: 0 }}
|
||||
style={{ cursor: onDayClick ? 'pointer' : 'default' }}
|
||||
@@ -694,11 +694,15 @@ function MetricChart({ data, dataKey, color, formatter, height = 140, selectedDa
|
||||
{(referenceLines || []).map((rl, i) => (
|
||||
<ReferenceLine key={i} {...rl} />
|
||||
))}
|
||||
{/* Dashed line bridging gaps (no data). Drawn first; the solid area below
|
||||
covers it wherever real data exists, leaving only gaps shown dashed. */}
|
||||
<Line type="monotone" dataKey={dataKey} stroke={color} strokeWidth={1.5}
|
||||
strokeDasharray="4 4" dot={false} connectNulls isAnimationActive={false} legendType="none" />
|
||||
<Area type="monotone" dataKey={dataKey} stroke={color} strokeWidth={2}
|
||||
fill={`url(#grad-${dataKey})`}
|
||||
dot={statusDotKey ? statusDot(statusDotKey) : (showDots ? { fill: color, r: 3, strokeWidth: 0 } : false)}
|
||||
connectNulls={connectNulls} isAnimationActive={false} />
|
||||
</AreaChart>
|
||||
connectNulls={false} isAnimationActive={false} />
|
||||
</ComposedChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
}
|
||||
@@ -1030,6 +1034,7 @@ export default function HealthPage() {
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-sm font-medium text-gray-300">HRV (nightly avg)</h3>
|
||||
<div className="flex items-center gap-3 text-xs text-gray-500">
|
||||
<span className="flex items-center gap-1"><span className="w-2 h-2 rounded-full" style={{ background: '#22c55e' }} /> Balanced</span>
|
||||
<span className="flex items-center gap-1"><span className="w-2 h-2 rounded-full" style={{ background: '#f97316' }} /> Unbalanced</span>
|
||||
<span className="flex items-center gap-1"><span className="w-2 h-2 rounded-full" style={{ background: '#ef4444' }} /> Low</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user