Dashboard
Full dashboard screens — KPI stats, charts, tables and activity feeds across finance, commerce, support, analytics and observability.
Preview
@props([
'name' => 'Alex',
'stats' => null,
'ranges' => null,
'categories' => null,
'transactions' => null,
])
{{--
Dashboard Spending — content-only finance dashboard (drop into an app
shell such as app-shell-assistant for the sidebar/AI rail; this page owns
none of that chrome). A welcome header, a four-up KPI tray row, a
revenue-vs-expense comparison chart, and a two-column spending-breakdown
+ transactions-list row.
The sample figures agree with each other: chart-comparison's own bundled
"Last 30 days" totals (Revenue $8,750.00, Expense $1,852.00) are echoed
in the KPI row, net profit is revenue minus expense, cash flow is net
profit less a stated pending-receivables gap, and the spending-breakdown
categories below sum to the same $1,852.00 total expense.
--}}
@php
// Fixed inline icon set for the KPI tray headers — hand-authored, trusted
// markup (not user data), safe to print unescaped in the loop below.
$icons = [
'bar-chart' => '<path d="M3 3v18h18"/><path d="M8 17V9"/><path d="M13 17V5"/><path d="M18 17v-7"/>',
'coin' => '<circle cx="12" cy="12" r="10"/><path d="M14.8 9A2 2 0 0 0 13 8h-2a2 2 0 0 0 0 4h2a2 2 0 0 1 0 4h-2a2 2 0 0 1-1.8-1"/><path d="M12 6v2"/><path d="M12 16v2"/>',
'trending-up' => '<path d="M22 7 13.5 15.5 8.5 10.5 2 17"/><path d="M16 7h6v6"/>',
'swap' => '<path d="m17 3 4 4-4 4"/><path d="M21 7H9"/><path d="m7 21-4-4 4-4"/><path d="M3 17h12"/>',
];
// Revenue and expense mirror blocks/chart-comparison's own bundled 30-day
// sample one-for-one, so the KPI row and the chart panel underneath never
// disagree. Net profit is revenue minus expense; cash flow is net profit
// less a stated pending-receivables gap (both spelled out in the
// description so the figures read as derived, not arbitrary).
$stats ??= [
['title' => __('Total revenue'), 'icon' => 'bar-chart', 'value' => '$8,750.00', 'delta' => '+12%', 'description' => __('vs last month')],
['title' => __('Total expense'), 'icon' => 'coin', 'value' => '$1,852.00', 'delta' => '-3%', 'description' => __('vs last month'), 'inverse' => true],
['title' => __('Net profit'), 'icon' => 'trending-up', 'value' => '$6,898.00', 'delta' => '+16.9%', 'description' => __('Revenue minus expense')],
['title' => __('Cash flow'), 'icon' => 'swap', 'value' => '$6,240.00', 'delta' => '+17.1%', 'description' => __('Net profit less pending receivables')],
];
// Spending-breakdown categories are a subset of the same $1,852.00 total
// expense above (45% / 30% / 25% of it), not a separate, disagreeing figure.
$categories ??= [
['name' => __('Housing'), 'percent' => 45, 'amount' => '$833.40', 'icon' => 'home'],
['name' => __('Food & Dining'), 'percent' => 30, 'amount' => '$555.60', 'icon' => 'utensils'],
['name' => __('Transport'), 'percent' => 25, 'amount' => '$463.00', 'icon' => 'car'],
];
@endphp
<main id="main-content" data-surface="admin" {{ $attributes->merge(['class' => 'min-h-svh bg-background p-4 text-foreground sm:p-6 lg:p-8']) }}>
<div class="mx-auto max-w-7xl space-y-6">
{{-- Welcome header --}}
<div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
<h1 class="text-2xl font-bold tracking-tight">{{ __('Welcome back, :name', ['name' => $name]) }}</h1>
<x-ui.button size="sm">
<svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
{{ __('Add new') }}
</x-ui.button>
</div>
{{-- KPI tray row --}}
<div data-slot="dashboard-spending-kpis" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
@foreach ($stats as $stat)
<x-ui.tray :title="$stat['title']">
<x-slot:icon>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">{!! $icons[$stat['icon']] ?? '' !!}</svg>
</x-slot:icon>
<x-ui.stat
variant="plain"
:value="$stat['value']"
:delta="$stat['delta']"
:description="$stat['description'] ?? null"
:inverse="$stat['inverse'] ?? false"
/>
</x-ui.tray>
@endforeach
</div>
{{-- Revenue vs. expense comparison --}}
<x-blocks.chart-comparison :ranges="$ranges" />
{{-- Spending breakdown + transactions --}}
<div class="grid gap-6 lg:grid-cols-2">
<x-blocks.metrics-breakdown :categories="$categories" total="$1,852.00" delta="-3%" />
<x-blocks.transactions-list :transactions="$transactions" />
</div>
</div>
</main>
Installation
php artisan ui:add pages/dashboard-spending
Registry contract
Install confidence
php artisan ui:add pages/dashboard-spending
writes only the generated targets below. The CLI validates each file hash before writing and
prompts before replacing local changes unless --force is used.
- Version
- 1.0.1
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/pages/dashboard-spending.blade.php |
Registry dependencies
Package dependencies
composer: jml/brok:^0.2
Use with AI
A brief for your coding agent: what the page is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this page in an assistant.
# Brok UI page: Dashboard Spending (`dashboard-spending`)
A spending dashboard: a welcome header with an 'Add new' action, a four-up KPI tray row (revenue, expense, net profit, cash flow), a revenue-vs-expense comparison chart, and a two-column spending breakdown plus transactions panel.
Brok UI is a Laravel Blade registry. `ui:add` copies this page into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.
## Install
```bash
php artisan ui:add pages/dashboard-spending
```
## Render it
```blade
<x-pages.dashboard-spending />
```
## Props
- `name` (string, default `Alex`) — First name used in the 'Welcome back, :name' heading.
- `stats` (mixed|null, default `null`) — Four KPI tray tiles ({title, icon, value, delta, description, inverse?}); null falls back to sample data that ties to the chart/breakdown below (revenue $8,750, expense $1,852, net profit $6,898, cash flow $6,240).
- `ranges` (mixed|null, default `null`) — Forwarded to blocks/chart-comparison's `ranges` prop; null renders its bundled sample.
- `categories` (mixed|null, default `null`) — Forwarded to blocks/metrics-breakdown's `categories` prop; null falls back to a Housing/Food & Dining/Transport split that sums to the sample total expense.
- `transactions` (mixed|null, default `null`) — Forwarded to blocks/transactions-list's `transactions` prop; null renders its bundled sample.
## Use when
- A finance/spending overview screen needs a welcome header, four KPI tiles framed in trays, a revenue-vs-expense comparison chart, and a spending breakdown alongside a transactions panel.
- The screen is dropped into an app shell (see app-shell-assistant) rather than owning its own sidebar/AI rail — this page is content-only.
## Avoid when
- A general KPI-and-sales-chart overview is enough; use dashboard-overview instead.
- The page needs its own sidebar navigation or AI rail; compose app-shell-assistant around this page instead.
## Rules
- Render the installed page with `<x-pages.dashboard-spending />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.
## Links
- Docs: https://brokui.dev/pages/dashboard-spending
- Registry JSON (files, props, contract): https://brokui.dev/r/open/pages/dashboard-spending.json
Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.
Guidance
Use when
- A finance/spending overview screen needs a welcome header, four KPI tiles framed in trays, a revenue-vs-expense comparison chart, and a spending breakdown alongside a transactions panel.
- The screen is dropped into an app shell (see app-shell-assistant) rather than owning its own sidebar/AI rail — this page is content-only.
Avoid when
- A general KPI-and-sales-chart overview is enough; use dashboard-overview instead.
- The page needs its own sidebar navigation or AI rail; compose app-shell-assistant around this page instead.
Anti-patterns
- Do not replace semantic props with conflicting utility classes.
- Do not remove labels, focus styles, or state attributes.
Usage
Render the page as a component, or wire it to a route. Pass data where useful:
<x-pages.dashboard-spending />
Built from blocks & primitives
This page composes installed <brok:*> primitives and semantic design
tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by
editing CSS variables; flip the preview to RTL to confirm it mirrors.
Source
The exact, editable file ui:add writes
into your app. The preview above renders this same source — there are no preview-only pages.
@props([
'name' => 'Alex',
'stats' => null,
'ranges' => null,
'categories' => null,
'transactions' => null,
])
{{--
Dashboard Spending — content-only finance dashboard (drop into an app
shell such as app-shell-assistant for the sidebar/AI rail; this page owns
none of that chrome). A welcome header, a four-up KPI tray row, a
revenue-vs-expense comparison chart, and a two-column spending-breakdown
+ transactions-list row.
The sample figures agree with each other: chart-comparison's own bundled
"Last 30 days" totals (Revenue $8,750.00, Expense $1,852.00) are echoed
in the KPI row, net profit is revenue minus expense, cash flow is net
profit less a stated pending-receivables gap, and the spending-breakdown
categories below sum to the same $1,852.00 total expense.
--}}
@php
// Fixed inline icon set for the KPI tray headers — hand-authored, trusted
// markup (not user data), safe to print unescaped in the loop below.
$icons = [
'bar-chart' => '<path d="M3 3v18h18"/><path d="M8 17V9"/><path d="M13 17V5"/><path d="M18 17v-7"/>',
'coin' => '<circle cx="12" cy="12" r="10"/><path d="M14.8 9A2 2 0 0 0 13 8h-2a2 2 0 0 0 0 4h2a2 2 0 0 1 0 4h-2a2 2 0 0 1-1.8-1"/><path d="M12 6v2"/><path d="M12 16v2"/>',
'trending-up' => '<path d="M22 7 13.5 15.5 8.5 10.5 2 17"/><path d="M16 7h6v6"/>',
'swap' => '<path d="m17 3 4 4-4 4"/><path d="M21 7H9"/><path d="m7 21-4-4 4-4"/><path d="M3 17h12"/>',
];
// Revenue and expense mirror blocks/chart-comparison's own bundled 30-day
// sample one-for-one, so the KPI row and the chart panel underneath never
// disagree. Net profit is revenue minus expense; cash flow is net profit
// less a stated pending-receivables gap (both spelled out in the
// description so the figures read as derived, not arbitrary).
$stats ??= [
['title' => __('Total revenue'), 'icon' => 'bar-chart', 'value' => '$8,750.00', 'delta' => '+12%', 'description' => __('vs last month')],
['title' => __('Total expense'), 'icon' => 'coin', 'value' => '$1,852.00', 'delta' => '-3%', 'description' => __('vs last month'), 'inverse' => true],
['title' => __('Net profit'), 'icon' => 'trending-up', 'value' => '$6,898.00', 'delta' => '+16.9%', 'description' => __('Revenue minus expense')],
['title' => __('Cash flow'), 'icon' => 'swap', 'value' => '$6,240.00', 'delta' => '+17.1%', 'description' => __('Net profit less pending receivables')],
];
// Spending-breakdown categories are a subset of the same $1,852.00 total
// expense above (45% / 30% / 25% of it), not a separate, disagreeing figure.
$categories ??= [
['name' => __('Housing'), 'percent' => 45, 'amount' => '$833.40', 'icon' => 'home'],
['name' => __('Food & Dining'), 'percent' => 30, 'amount' => '$555.60', 'icon' => 'utensils'],
['name' => __('Transport'), 'percent' => 25, 'amount' => '$463.00', 'icon' => 'car'],
];
@endphp
<main id="main-content" data-surface="admin" {{ $attributes->merge(['class' => 'min-h-svh bg-background p-4 text-foreground sm:p-6 lg:p-8']) }}>
<div class="mx-auto max-w-7xl space-y-6">
{{-- Welcome header --}}
<div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
<h1 class="text-2xl font-bold tracking-tight">{{ __('Welcome back, :name', ['name' => $name]) }}</h1>
<x-ui.button size="sm">
<svg class="size-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14"/><path d="M5 12h14"/></svg>
{{ __('Add new') }}
</x-ui.button>
</div>
{{-- KPI tray row --}}
<div data-slot="dashboard-spending-kpis" class="grid gap-4 sm:grid-cols-2 xl:grid-cols-4">
@foreach ($stats as $stat)
<x-ui.tray :title="$stat['title']">
<x-slot:icon>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">{!! $icons[$stat['icon']] ?? '' !!}</svg>
</x-slot:icon>
<x-ui.stat
variant="plain"
:value="$stat['value']"
:delta="$stat['delta']"
:description="$stat['description'] ?? null"
:inverse="$stat['inverse'] ?? false"
/>
</x-ui.tray>
@endforeach
</div>
{{-- Revenue vs. expense comparison --}}
<x-blocks.chart-comparison :ranges="$ranges" />
{{-- Spending breakdown + transactions --}}
<div class="grid gap-6 lg:grid-cols-2">
<x-blocks.metrics-breakdown :categories="$categories" total="$1,852.00" delta="-3%" />
<x-blocks.transactions-list :transactions="$transactions" />
</div>
</div>
</main>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.1 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0