Card with a two-line chart comparing this week's exercise minutes against the average by day, both drawn in primary ink with the average at half strength. Client component on recharts 3.8.
"use client"
import { CartesianGrid, Line, LineChart, XAxis } from "recharts"
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import {
ChartContainer,
ChartTooltip,
ChartTooltipContent,
type ChartConfig,
} from "@/components/ui/chart"
// The copy: change text here, not in the markup.
const COPY = {
title: "Exercise minutes",
description: "Your exercise minutes are ahead of where you normally are.",
} as const
const EXERCISE_MINUTES = [
{ day: "Monday", today: 240, average: 400 },
{ day: "Tuesday", today: 139, average: 300 },
{ day: "Wednesday", today: 980, average: 200 },
{ day: "Thursday", today: 390, average: 278 },
{ day: "Friday", today: 480, average: 189 },
{ day: "Saturday", today: 380, average: 239 },
{ day: "Sunday", today: 430, average: 349 },
]
// Both series take the primary ink; the average is drawn at half strength.
const CHART_CONFIG = {
today: { label: "Today", color: "var(--primary)" },
average: { label: "Average", color: "var(--primary)" },
} satisfies ChartConfig
export default function ExerciseMinutes() {
return (
<Card className="mx-auto w-full max-w-md">
<CardHeader>
<CardTitle>
<h2>{COPY.title}</h2>
</CardTitle>
<CardDescription>{COPY.description}</CardDescription>
</CardHeader>
<CardContent>
<ChartContainer config={CHART_CONFIG} className="w-full md:h-[200px]">
<LineChart
accessibilityLayer
aria-label={COPY.title}
data={EXERCISE_MINUTES}
margin={{ top: 5, right: 10, left: 16, bottom: 0 }}
>
<CartesianGrid vertical={false} />
{/* Stock ChartContainer's label color misses recharts 3's label layer. */}
<XAxis
tick={{ fill: "var(--muted-foreground)" }}
dataKey="day"
tickLine={false}
axisLine={false}
tickMargin={8}
tickFormatter={(value: string) => value.slice(0, 3)}
/>
<Line
type="monotone"
dataKey="today"
strokeWidth={2}
stroke="var(--color-today)"
dot={{ fill: "var(--color-today)" }}
activeDot={{ r: 5 }}
/>
<Line
type="monotone"
dataKey="average"
strokeWidth={2}
stroke="var(--color-average)"
strokeOpacity={0.5}
dot={{ fill: "var(--color-average)", opacity: 0.5 }}
activeDot={{ r: 5 }}
/>
<ChartTooltip content={<ChartTooltipContent />} />
</LineChart>
</ChartContainer>
</CardContent>
</Card>
)
}
pnpm dlx shadcn add @01orbital/exercise-minutesnpx shadcn add @01orbital/exercise-minutesyarn shadcn add @01orbital/exercise-minutesbunx --bun shadcn add @01orbital/exercise-minutesFree under the MIT license. Add the @01orbital registry to components.json once (install guide), then run the command.
It lands at components/blocks/charts/exercise-minutes/index.tsx, as source you own and edit.
import ExerciseMinutes from "@/components/blocks/charts/exercise-minutes"
export default function Example() {
return <ExerciseMinutes />
}npm: recharts@3.8.0. The CLI installs them for you.
Registry pieces it installs with it:
cardchartDonut Chart with Center Total
Card with a donut chart of minutes by genre, the total printed in the center, and a footer list giving each genre's swatch, minutes and share. Client component on recharts 3.8.
Horizontal Ranking Bar Chart
Card with a horizontal bar chart ranking five countries by listeners, country names on the axis and values printed at the end of each bar. Client component on recharts 3.8.