Skabelon · React · HTML
Health overview
Et sundhedsdashboard i Tiles: tre vitale tal, et patientkort, en scoreskive og kaloriesøjler med makroer.
Forhåndsvisning
React
Installér skabelonen med shadcn. Den lægges i dit projekt som almindelige komponenter, som du selv retter i.
npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.jsonnpx shadcn@latest add @manniche/health-overviewhealth-overview.tsx
// A health overview: three vital figures, a patient card, a score dial and calorie bars with macros.
import { cn } from '@/lib/utils'
import { BarChart, type BarPoint } from '@/registry/manniche/bar-chart/bar-chart'
import { BigNumber } from '@/registry/manniche/chart-kit/chart-kit'
import { DataTile, TileFact } from '@/registry/manniche/data-tile/data-tile'
import { Dial, type DialZone } from '@/registry/manniche/dial/dial'
import { Donut, type DonutDatum } from '@/registry/manniche/donut/donut'
export type HealthOverviewData = {
vitals: { id: string; title: string; value: number; unit: string }[]
patient: { name: string; details: { label: string; value: string }[] }
score: { title: string; value: number; zones: DialZone[]; caption: string }
calories: { title: string; points: BarPoint[]; macros: DonutDatum[]; macrosTitle: string }
}
export type HealthOverviewLabels = { note?: string }
export type HealthOverviewProps = { data: HealthOverviewData; labels?: HealthOverviewLabels; className?: string }
export function HealthOverview({ data, labels, className }: HealthOverviewProps) {
const note = labels?.note ?? 'Example data.'
return (
<div className={cn('@container w-full rounded-2xl bg-background p-3 text-foreground', className)}>
<div className="grid grid-cols-1 gap-3 @lg:grid-cols-3 @3xl:grid-cols-6">
{data.vitals.map((v) => (
<div key={v.id} className="@3xl:col-span-2">
<DataTile className="h-full" title={v.title} density="compact">
<TileFact aside={<span className="text-sm text-muted-foreground">{v.unit}</span>}>
<BigNumber value={v.value} size="lg" />
</TileFact>
</DataTile>
</div>
))}
<div className="@lg:col-span-3 @3xl:col-span-3">
<DataTile className="h-full" title={data.patient.name} inverted>
<dl className="grid grid-cols-2 gap-3 text-sm">
{data.patient.details.map((d) => (
<div key={d.label}>
<dt className="opacity-70">{d.label}</dt>
<dd className="font-medium">{d.value}</dd>
</div>
))}
</dl>
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-3">
<DataTile className="h-full" title={data.score.title} footer={note}>
<Dial value={data.score.value} min={0} max={100} zones={data.score.zones} label={data.score.title} caption={data.score.caption} />
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-4">
<DataTile className="h-full" title={data.calories.title} footer={note}>
<BarChart data={data.calories.points} label={data.calories.title} format={{ suffix: ' kcal' }} />
</DataTile>
</div>
<div className="@lg:col-span-3 @3xl:col-span-2">
<DataTile className="h-full" title={data.calories.macrosTitle} footer={note}>
<Donut data={data.calories.macros} label={data.calories.macrosTitle} format={{ suffix: ' g' }} />
</DataTile>
</div>
</div>
</div>
)
}health-overview-demo.tsx
import { HealthOverview, type HealthOverviewData } from '@/components/health-overview'
// Example data only. The person and all figures are invented; this is not medical information.
const data: HealthOverviewData = {
vitals: [
{ id: 'hr', title: 'Heart rate', value: 64, unit: 'bpm' },
{ id: 'sl', title: 'Sleep', value: 7, unit: 'hours' },
{ id: 'st', title: 'Steps', value: 8200, unit: 'today' },
],
patient: {
name: 'Sample Patient',
details: [
{ label: 'Age', value: '41' },
{ label: 'Height', value: '178 cm' },
{ label: 'Last visit', value: '2 Oct 2026' },
{ label: 'Plan', value: 'Example plan' },
],
},
score: {
title: 'Wellness score',
value: 74,
caption: 'example score',
zones: [
{ label: 'Low', to: 40 },
{ label: 'Fair', to: 70 },
{ label: 'Good', to: 100 },
],
},
calories: {
title: 'Calories, last 7 days',
points: ['Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue'].map((label, i) => ({ label, value: [2100, 1950, 2250, 2000, 2300, 2600, 1900][i] })),
macrosTitle: 'Macros today',
macros: [
{ label: 'Carbs', value: 240 },
{ label: 'Protein', value: 110 },
{ label: 'Fat', value: 70 },
],
},
}
export default function HealthOverviewDemo() {
return <HealthOverview data={data} />
}HTML
Hele siden som én fil med al CSS indbygget og intet JavaScript. Knapper, faner og filtre virker med HTML og CSS alene.
Farven i din egen app
Har du allerede shadcn sat op, giver disse variabler samme farve. Lys i :root, mørk i .dark.
:root {
--primary: oklch(0.52 0.2 262);
--primary-foreground: oklch(0.99 0 0);
--accent: oklch(0.95 0.034 262);
--accent-foreground: oklch(0.36 0.140 262);
--ring: oklch(0.52 0.2 262);
}
.dark {
--primary: oklch(0.74 0.150 262);
--primary-foreground: oklch(0.18 0.024 262);
--accent: oklch(0.29 0.050 262);
--accent-foreground: oklch(0.9 0.050 262);
--ring: oklch(0.74 0.150 262);
}Installér
npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.json