Dashboard

This commit is contained in:
2026-04-06 13:03:50 +02:00
parent 259d031895
commit d098cf647c

View File

@@ -373,6 +373,11 @@ export function Dashboard({athleteId}: { athleteId: number }) {
const loadData = buildLoadData(activities, wStart)
const ctlValues = loadData.map(d => d.ctl).filter((v): v is number => v !== null)
const ctlDomain: [number, number] | ['auto', 'auto'] = ctlValues.length
? [Math.floor(Math.min(...ctlValues) * 0.9), Math.ceil(Math.max(...ctlValues) * 1.1)]
: ['auto', 'auto']
return (
<div className="flex-1 overflow-y-auto bg-zinc-50 p-8">
{/* Page header */}
@@ -467,14 +472,14 @@ export function Dashboard({athleteId}: { athleteId: number }) {
/>
</div>
{/* Training Load chart */}
{/* Weekly TSS chart */}
<div className="border border-zinc-200 rounded-sm bg-white p-5">
<p className="text-xs font-semibold tracking-widest text-zinc-400 uppercase mb-5">
Weekly Training Load (TSS)
</p>
{loadData.some((d) => d.tss > 0 || d.ctl !== null) ? (
<ResponsiveContainer width="100%" height={220}>
<ComposedChart data={loadData} margin={{left: -20, right: 30}}>
{loadData.some((d) => d.tss > 0) ? (
<ResponsiveContainer width="100%" height={200}>
<ComposedChart data={loadData} margin={{left: -20, right: 10}}>
<defs>
<linearGradient id="tssGrad" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stopColor="#ef4444"/>
@@ -487,21 +492,11 @@ export function Dashboard({athleteId}: { athleteId: number }) {
</defs>
<XAxis dataKey="week" tick={{fontSize: 10, fill: '#a1a1aa'}} axisLine={false}
tickLine={false}/>
<YAxis yAxisId="tss" tick={{fontSize: 10, fill: '#a1a1aa'}} axisLine={false}
tickLine={false}/>
<YAxis yAxisId="fitness" orientation="right" tick={{fontSize: 10, fill: '#a1a1aa'}}
axisLine={false} tickLine={false}/>
<YAxis tick={{fontSize: 10, fill: '#a1a1aa'}} axisLine={false} tickLine={false}/>
<Tooltip content={<LoadTooltip/>}/>
<Area yAxisId="tss" type="monotone" dataKey="tss" fill="url(#tssAreaGrad)"
stroke="none"/>
<Line yAxisId="tss" type="monotone" dataKey="tss" stroke="url(#tssGrad)" strokeWidth={2}
<Area type="monotone" dataKey="tss" fill="url(#tssAreaGrad)" stroke="none"/>
<Line type="monotone" dataKey="tss" stroke="url(#tssGrad)" strokeWidth={2}
dot={false} name="TSS"/>
<Line yAxisId="fitness" type="monotone" dataKey="ctl" stroke="#ef4444" strokeWidth={1.5}
strokeDasharray="5 3" dot={false} name="CTL" connectNulls/>
<Line yAxisId="fitness" type="monotone" dataKey="atl" stroke="#fdba74" strokeWidth={1.5}
strokeDasharray="5 3" dot={false} name="ATL" connectNulls/>
<Line yAxisId="fitness" type="monotone" dataKey="tsb" stroke="#52525b" strokeWidth={1.5}
strokeDasharray="3 3" dot={false} name="TSB" connectNulls/>
</ComposedChart>
</ResponsiveContainer>
) : (
@@ -510,6 +505,44 @@ export function Dashboard({athleteId}: { athleteId: number }) {
</div>
)}
</div>
{/* CTL / ATL / TSB chart */}
<div className="border border-zinc-200 rounded-sm bg-white p-5">
<p className="text-xs font-semibold tracking-widest text-zinc-400 uppercase mb-5">
Fitness, Fatigue &amp; Form (CTL / ATL / TSB)
</p>
{loadData.some((d) => d.ctl !== null) ? (
<ResponsiveContainer width="100%" height={200}>
<ComposedChart data={loadData} margin={{left: -20, right: 0}}>
<defs>
<linearGradient id="tssAreaGrad2" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stopColor="#ef4444" stopOpacity={0.12}/>
<stop offset="100%" stopColor="#f97316" stopOpacity={0}/>
</linearGradient>
</defs>
<XAxis dataKey="week" tick={{fontSize: 10, fill: '#a1a1aa'}} axisLine={false}
tickLine={false} padding={{left: 20, right: 20}}/>
<YAxis yAxisId="left" domain={ctlDomain} tick={{fontSize: 10, fill: '#a1a1aa'}}
axisLine={false} tickLine={false}/>
<YAxis yAxisId="right" orientation="right" tick={{fontSize: 10, fill: '#a1a1aa'}}
axisLine={false} tickLine={false}/>
<Tooltip content={<LoadTooltip/>}/>
<Area yAxisId="left" type="monotone" dataKey="ctl" fill="url(#tssAreaGrad2)"
stroke="none" connectNulls/>
<Line yAxisId="left" type="monotone" dataKey="ctl" stroke="#ef4444"
strokeWidth={2} dot={false} name="CTL" connectNulls/>
<Line yAxisId="left" type="monotone" dataKey="atl" stroke="#fdba74" strokeWidth={1.5}
strokeDasharray="5 3" dot={false} name="ATL" connectNulls/>
<Line yAxisId="right" type="monotone" dataKey="tsb" stroke="#52525b" strokeWidth={1.5}
strokeDasharray="3 3" dot={false} name="TSB" connectNulls/>
</ComposedChart>
</ResponsiveContainer>
) : (
<div className="h-[200px] flex items-center justify-center text-zinc-400 text-sm">
No fitness data yet
</div>
)}
</div>
</section>
</div>
)