Mikkel Manniche
Dansk English Deutsch

Vorlage · React · HTML

Health overview

Ein Gesundheits-Dashboard in Tiles: drei Vitalwerte, eine Patientenkarte, eine Score-Anzeige und Kalorienbalken mit Makros.

Vorschau

React

Installiere die Vorlage mit shadcn. Sie landet als normale Komponenten in deinem Projekt, die du selbst anpasst.

npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.json
npx shadcn@latest add @manniche/health-overview
health-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

Die ganze Seite als eine Datei mit eingebautem CSS und ohne JavaScript. Umschalter, Tabs und Filter funktionieren allein mit HTML und CSS.

In neuem Tab öffnen

Die Farbe in deiner eigenen App

Wenn shadcn bereits eingerichtet ist, ergeben diese Variablen dieselbe Farbe. Hell in :root, dunkel in .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);
}

Installieren

npx shadcn@latest add https://mikkelmanniche.dk/lab/r/health-overview.json

Abhängigkeiten

    Dateien

    • health-overview.tsx
    • health-overview.html

    Manniche Lab · Open Source

    Kostenlose Werkzeuge für KI-Agenten und Webentwicklung.