Fixed Garmin sync progress bar granularity, timeout issue, and lookback days input, plus redesigned the sleep timeline with taller bars and yellow Awake colour.
This commit is contained in:
@@ -169,7 +169,7 @@ function SleepTimeline({ sleepStart, sleepEnd, deep, light, rem, awake }) {
|
||||
{ key: 'deep', secs: deep || 0, color: '#6366f1', label: 'Deep' },
|
||||
{ key: 'rem', secs: rem || 0, color: '#8b5cf6', label: 'REM' },
|
||||
{ key: 'light', secs: light || 0, color: '#a78bfa', label: 'Light' },
|
||||
{ key: 'awake', secs: awake || 0, color: '#374151', label: 'Awake' },
|
||||
{ key: 'awake', secs: awake || 0, color: '#eab308', label: 'Awake' },
|
||||
].filter(s => s.secs > 0)
|
||||
|
||||
// Generate hour tick marks within the sleep window
|
||||
@@ -185,27 +185,32 @@ function SleepTimeline({ sleepStart, sleepEnd, deep, light, rem, awake }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="space-y-1.5">
|
||||
{/* Time bar */}
|
||||
<div className="relative">
|
||||
<div className="flex rounded-md overflow-hidden h-5 w-full">
|
||||
{stages.map((s, i) => (
|
||||
<div
|
||||
key={s.key}
|
||||
style={{ width: `${(s.secs / stageSecs * 100).toFixed(2)}%`, backgroundColor: s.color }}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{/* Tick marks */}
|
||||
<div>
|
||||
{/* Stage bars rising from the time axis */}
|
||||
<div className="relative flex overflow-hidden rounded-t-sm" style={{ height: 48 }}>
|
||||
{stages.map(s => (
|
||||
<div
|
||||
key={s.key}
|
||||
title={`${s.label}: ${Math.round(s.secs / 60)} min`}
|
||||
style={{ width: `${(s.secs / stageSecs * 100).toFixed(2)}%`, backgroundColor: s.color }}
|
||||
/>
|
||||
))}
|
||||
{/* Tick lines overlaid on bars */}
|
||||
{ticks.map((t, i) => (
|
||||
<div key={i} className="absolute top-0 h-5 flex flex-col items-center pointer-events-none" style={{ left: `${t.pct}%` }}>
|
||||
<div className="w-px h-full bg-black/40" />
|
||||
</div>
|
||||
<div key={i} className="absolute top-0 bottom-0 w-px bg-black/25 pointer-events-none"
|
||||
style={{ left: `${t.pct}%` }} />
|
||||
))}
|
||||
</div>
|
||||
{/* Axis line */}
|
||||
<div className="border-t border-gray-600 relative">
|
||||
{ticks.map((t, i) => (
|
||||
<div key={i} className="absolute top-0 w-px h-1.5 bg-gray-600"
|
||||
style={{ left: `${t.pct}%` }} />
|
||||
))}
|
||||
</div>
|
||||
{/* Time labels */}
|
||||
<div className="relative h-4">
|
||||
<span className="absolute left-0 text-xs text-gray-500" style={{ transform: 'translateX(-0%)' }}>
|
||||
<div className="relative h-4 mt-1">
|
||||
<span className="absolute left-0 text-xs text-gray-500">
|
||||
{new Date(startMs).toLocaleTimeString('en-GB', { hour: '2-digit', minute: '2-digit' })}
|
||||
</span>
|
||||
{ticks.map((t, i) => (
|
||||
@@ -318,7 +323,7 @@ function DailySnapshot({ day, avg30, intradayHr, bodyBattery, bbHires, onOlder,
|
||||
['Deep', day.sleep_deep_s, '#6366f1'],
|
||||
['REM', day.sleep_rem_s, '#8b5cf6'],
|
||||
['Light', day.sleep_light_s, '#a78bfa'],
|
||||
['Awake', day.sleep_awake_s, '#4b5563'],
|
||||
['Awake', day.sleep_awake_s, '#eab308'],
|
||||
].map(([label, secs, color]) => secs ? (
|
||||
<div key={label} className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm" style={{ backgroundColor: color }} />
|
||||
@@ -565,7 +570,7 @@ function SleepChart({ data, selectedDate, onDayClick }) {
|
||||
<Bar dataKey="deep" name="Deep" stackId="a" fill="#6366f1" />
|
||||
<Bar dataKey="rem" name="REM" stackId="a" fill="#8b5cf6" />
|
||||
<Bar dataKey="light" name="Light" stackId="a" fill="#a78bfa" />
|
||||
<Bar dataKey="awake" name="Awake" stackId="a" fill="#374151" radius={[2, 2, 0, 0]} />
|
||||
<Bar dataKey="awake" name="Awake" stackId="a" fill="#eab308" radius={[2, 2, 0, 0]} />
|
||||
</BarChart>
|
||||
</ResponsiveContainer>
|
||||
)
|
||||
@@ -704,7 +709,7 @@ export default function HealthPage() {
|
||||
<SleepChart data={metrics}
|
||||
selectedDate={selDateForCharts} onDayClick={handleDayClick} />
|
||||
<div className="flex gap-4 mt-2">
|
||||
{[['Deep','#6366f1'],['REM','#8b5cf6'],['Light','#a78bfa'],['Awake','#374151']].map(([l,c]) => (
|
||||
{[['Deep','#6366f1'],['REM','#8b5cf6'],['Light','#a78bfa'],['Awake','#eab308']].map(([l,c]) => (
|
||||
<div key={l} className="flex items-center gap-1.5">
|
||||
<div className="w-2.5 h-2.5 rounded-sm" style={{ backgroundColor: c }} />
|
||||
<span className="text-xs text-gray-400">{l}</span>
|
||||
|
||||
Reference in New Issue
Block a user