Mikkel Manniche
Dansk English Deutsch

Vorlage · React · HTML

Account home

Eine Startseite für ein Bankkonto in Tiles: eine Zahlungskarte, der Kontostand, eine Anzeige mit drei Zuständen und letzte Transaktionen.

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/account-home.json
npx shadcn@latest add @manniche/account-home
account-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 AccountHome
account-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

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/account-home.json

Abhängigkeiten

    Dateien

    • account-home.tsx
    • account-home.html

    Manniche Lab · Open Source

    Kostenlose Werkzeuge für KI-Agenten und Webentwicklung.