Skabelon · React · HTML
People ops
Et HR-dashboard i Tiles: en rekrutteringstragt, dagens skema, en lønliste og en prikmatrix over fremmøde.
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/people-ops.jsonnpx shadcn@latest add @manniche/people-opspeople-ops.tsx
// A people-ops screen: hiring funnel, today's schedule, payroll list and an attendance dot matrix.
import { cn } from '@/lib/utils'
import { BarChart, type BarPoint } from '@/registry/manniche/bar-chart/bar-chart'
import { DataTile } from '@/registry/manniche/data-tile/data-tile'
import { DotMatrix } from '@/registry/manniche/dot-matrix/dot-matrix'
import { TransactionList, type Transaction } from '@/registry/manniche/transaction-list/transaction-list'
import type { ValueFormat } from '@/registry/manniche/chart-kit/chart-utils'
export type PeopleOpsData = {
funnel: { title: string; stages: BarPoint[] }
today: { title: string; items: { id: string; time: string; title: string; who: string }[] }
payroll: { title: string; items: Transaction[]; today?: string; format?: ValueFormat }
attendance: { title: string; data: number[][]; rows: string[]; columns: string[] }
}
export type PeopleOpsLabels = { note?: string }
export type PeopleOpsProps = { data: PeopleOpsData; labels?: PeopleOpsLabels; className?: string }
export function PeopleOps({ data, labels, className }: PeopleOpsProps) {
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 @2xl:grid-cols-6">
<div className="@2xl:col-span-3">
<DataTile className="h-full" title={data.today.title} inverted>
<ol className="flex flex-col gap-3">
{data.today.items.map((it) => (
<li key={it.id} className="flex items-baseline gap-3 text-sm">
<time className="w-12 shrink-0 tabular-nums opacity-70">{it.time}</time>
<span className="min-w-0 flex-1 truncate font-medium">{it.title}</span>
<span className="opacity-70">{it.who}</span>
</li>
))}
</ol>
</DataTile>
</div>
<div className="@2xl:col-span-3">
<DataTile className="h-full" title={data.funnel.title} footer={note}>
<BarChart data={data.funnel.stages} label={data.funnel.title} current={null} />
</DataTile>
</div>
<div className="@2xl:col-span-3">
<DataTile className="h-full" title={data.payroll.title} footer={note}>
<TransactionList data={data.payroll.items} label={data.payroll.title} today={data.payroll.today} format={data.payroll.format} />
</DataTile>
</div>
<div className="@2xl:col-span-3">
<DataTile className="h-full" title={data.attendance.title} footer={note}>
<DotMatrix data={data.attendance.data} rows={data.attendance.rows} columns={data.attendance.columns} label={data.attendance.title} />
</DataTile>
</div>
</div>
</div>
)
}people-ops-demo.tsx
import { PeopleOps, type PeopleOpsData } from '@/components/people-ops'
// Example data only. All names and figures are invented.
const data: PeopleOpsData = {
funnel: {
title: 'Hiring funnel',
stages: [
{ label: 'Applied', value: 120 },
{ label: 'Screen', value: 48 },
{ label: 'Interview', value: 20 },
{ label: 'Offer', value: 5 },
],
},
today: {
title: "Today's schedule",
items: [
{ id: 's1', time: '09:30', title: 'Sample stand-up', who: 'Team' },
{ id: 's2', time: '11:00', title: 'Demo interview', who: 'Alex E.' },
{ id: 's3', time: '14:00', title: 'Example onboarding', who: 'Sam S.' },
],
},
payroll: {
title: 'Payroll',
today: '2026-10-06',
format: { currency: 'EUR', decimals: 0 },
items: [
{ id: 'p1', name: 'Alex Example', amount: -3200, date: '2026-09-30', category: 'Salary' },
{ id: 'p2', name: 'Sam Sample', amount: -2900, date: '2026-09-30', category: 'Salary' },
{ id: 'p3', name: 'Robin Demo', amount: -2600, date: '2026-09-30', category: 'Salary' },
],
},
attendance: {
title: 'Attendance',
rows: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
columns: ['W1', 'W2', 'W3', 'W4'],
data: [[8, 7, 8, 6], [7, 8, 8, 7], [8, 6, 7, 8], [7, 7, 8, 8], [5, 6, 4, 6]],
},
}
export default function PeopleOpsDemo() {
return <PeopleOps 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/people-ops.json