Skabelon · React · HTML
Account home
En startside til en bankkonto i Tiles: et betalingskort, saldoen, en skive med tre tilstande og seneste transaktioner.
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/account-home.jsonnpx shadcn@latest add @manniche/account-homeaccount-home.tsx
// An account home screen in Tiles: the payment card, the balance, a three-state spending dial and recent transactions.
import { cn } from '@/lib/utils'
import { BigNumber, DeltaPill } from '@/registry/manniche/chart-kit/chart-kit'
import { formatValue, type ValueFormat } from '@/registry/manniche/chart-kit/chart-utils'
import { DataTile, TileFact } from '@/registry/manniche/data-tile/data-tile'
import { CardStack, type StackCard } from '@/registry/manniche/card-stack/card-stack'
import { Dial, type DialZone } from '@/registry/manniche/dial/dial'
import { TransactionList, type Transaction } from '@/registry/manniche/transaction-list/transaction-list'
export type AccountHomeProps = {
data: {
card: StackCard
balance: number
change: number
/** Spending pace against the budget: 1 is exactly on budget. */
pace: number
budget: number
transactions: Transaction[]
categories?: Record<string, string>
}
format?: ValueFormat
title?: string
note?: string
/** "YYYY-MM-DD" of today, so the list reads "Today" and "Yesterday". Default the day of `now`. */
today?: string
/** The current time. Used for `today` when that is not given. */
now?: Date
labels?: { card?: string; balance?: string; pace?: string; paceCaption?: string; transactions?: string; budget?: string; zones?: [string, string, string] }
className?: string
}
const DEFAULT_FORMAT: ValueFormat = { currency: 'EUR', decimals: 2 }
/** Account home: card, balance, spending pace dial (under, on track, over) and transactions. */
// "YYYY-MM-DD" of `now` in local time, for TransactionList's "Today" and "Yesterday".
const dayOf = (d: Date) => `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`
export function AccountHome({ data, format = DEFAULT_FORMAT, title = 'Account', note = 'Example data.', today, now, labels, className }: AccountHomeProps) {
const day = today ?? (now ? dayOf(now) : undefined)
const l = { card: 'Card', balance: 'Balance', pace: 'Spending pace', paceCaption: 'of your daily budget', transactions: 'Recent transactions', budget: 'Budget this month', zones: ['Under', 'On track', 'Over'] as [string, string, string], ...labels }
const zones: DialZone[] = [
{ label: l.zones[0], to: 0.85, color: 'var(--chart-1)' },
{ label: l.zones[1], to: 1.1, color: 'var(--success)' },
{ label: l.zones[2], to: 1.6, color: 'var(--destructive)' },
]
return (
<div className={cn('@container w-full font-sans text-foreground', className)}>
<div className="grid gap-4 @3xl:grid-cols-6 @6xl:grid-cols-12">
<h1 className="text-[22px] leading-tight font-semibold tracking-tight @3xl:col-span-6 @6xl:col-span-12">{title}</h1>
<DataTile title={l.card} className="@3xl:col-span-3 @6xl:col-span-4">
<CardStack data={[data.card]} label={l.card} format={format} hideAmount />
</DataTile>
<DataTile title={l.balance} inverted className="@3xl:col-span-3 @6xl:col-span-4" footer={<span>{note}</span>}>
<BigNumber value={data.balance} format={format} size="lg" />
<div className="mt-3">
<DeltaPill value={data.change} format={{ decimals: 1, suffix: '%', sign: true }} />
</div>
<div className="mt-5">
<TileFact label={l.budget}>{formatValue(data.budget, { ...format, decimals: 2 })}</TileFact>
</div>
</DataTile>
<DataTile title={l.pace} className="@3xl:col-span-6 @6xl:col-span-4">
<Dial value={data.pace} zones={zones} format={{ decimals: 2, suffix: '×' }} label={l.pace} caption={l.paceCaption} />
</DataTile>
<DataTile title={l.transactions} className="@3xl:col-span-6 @6xl:col-span-12">
<TransactionList data={data.transactions} label={l.transactions} today={day} format={format} categories={data.categories} limit={5} />
</DataTile>
</div>
</div>
)
}
export default AccountHomeaccount-home-demo.tsx
import { AccountHome } from '@/components/account-home'
// Example data for the demo, not a real account. "Today" is Thursday 8 October 2026.
const data = {
card: { id: 'everyday', name: 'Everyday', kind: 'Debit', ending: '4821', amount: 2091.2 },
balance: 2091.2,
change: 1.8,
pace: 0.92,
budget: 1800,
categories: {
Groceries: 'var(--chart-1)',
Transport: 'var(--chart-2)',
'Eating out': 'var(--chart-3)',
Shopping: 'var(--chart-4)',
Bills: 'var(--chart-5)',
},
transactions: [
{ id: 't1', name: 'Harbour Market', category: 'Groceries', date: '2026-10-08T12:58', amount: -48.2, status: 'pending' as const },
{ id: 't2', name: 'City Transit', category: 'Transport', date: '2026-10-08T08:31', amount: -3.1 },
{ id: 't3', name: 'Corner Bakery', category: 'Eating out', date: '2026-10-08T08:12', amount: -6.4 },
{ id: 't5', name: 'Northwind Books', category: 'Shopping', date: '2026-10-07T16:05', amount: -31.5 },
{ id: 't6', name: 'From Savings', category: 'Transfer', date: '2026-10-07T09:00', amount: 200 },
{ id: 't7', name: 'Lumen Energy', category: 'Bills', date: '2026-10-06T07:00', amount: -74 },
],
}
export default function AccountHomeDemo() {
return <AccountHome data={data} today="2026-10-08" />
}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/account-home.json