Dashboard
Full dashboard screens — KPI stats, charts, tables and activity feeds across finance, commerce, support, analytics and observability.
Preview
@props([
'title' => 'Support overview',
'subtitle' => 'Conversation volume, satisfaction, and your on-duty team.',
'stats' => null,
'series' => null,
'categories' => null,
'team' => null,
'tickets' => null,
])
@php
$stats ??= [
['label' => 'Open conversations', 'value' => '128', 'delta' => '+6.0%', 'description' => 'vs yesterday'],
['label' => 'CSAT score', 'value' => '94.2%', 'delta' => '+1.8%', 'description' => 'last 7 days'],
['label' => 'Avg. first reply', 'value' => '3m 12s', 'delta' => '-0.7%', 'description' => 'faster than target'],
['label' => 'Resolved today', 'value' => '342', 'delta' => '+12.4%', 'description' => 'vs yesterday'],
];
$series ??= [
['name' => __('Inbound'), 'data' => [320, 412, 388, 451, 502, 287, 196]],
['name' => __('Resolved'), 'data' => [298, 376, 354, 423, 471, 268, 184]],
];
$categories ??= [
__('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat'), __('Sun'),
];
$team ??= [
['name' => 'Ava Chen', 'initials' => 'AC', 'role' => 'Tier 2', 'open' => 7, 'status' => 'Online', 'tone' => 'success'],
['name' => 'Diego Mora', 'initials' => 'DM', 'role' => 'Tier 1', 'open' => 12, 'status' => 'Online', 'tone' => 'success'],
['name' => 'Priya Nair', 'initials' => 'PN', 'role' => 'Billing', 'open' => 3, 'status' => 'Away', 'tone' => 'warning'],
['name' => 'Sam Okafor', 'initials' => 'SO', 'role' => 'Tier 2', 'open' => 0, 'status' => 'Offline', 'tone' => 'secondary'],
];
$tickets ??= [
['id' => 'TKT-5821', 'subject' => 'Cannot export reports', 'customer' => 'Lumen Studio', 'priority' => 'High', 'priorityTone' => 'destructive', 'status' => 'Open', 'statusTone' => 'warning'],
['id' => 'TKT-5820', 'subject' => 'Billing address update', 'customer' => 'Northwind Co.', 'priority' => 'Low', 'priorityTone' => 'secondary', 'status' => 'Pending', 'statusTone' => 'outline'],
['id' => 'TKT-5819', 'subject' => 'SSO login loop', 'customer' => 'Atlas Freight', 'priority' => 'High', 'priorityTone' => 'destructive', 'status' => 'Open', 'statusTone' => 'warning'],
['id' => 'TKT-5818', 'subject' => 'Feature request: dark mode', 'customer' => 'Peak Labs', 'priority' => 'Medium', 'priorityTone' => 'default', 'status' => 'Resolved', 'statusTone' => 'success'],
['id' => 'TKT-5817', 'subject' => 'Webhook retries failing', 'customer' => 'Vela Group', 'priority' => 'Medium', 'priorityTone' => 'default', 'status' => 'Resolved', 'statusTone' => 'success'],
];
$statusDot = [
'success' => 'bg-success',
'warning' => 'bg-warning',
'secondary' => 'bg-muted-foreground',
];
// ApexCharts needs concrete colours; reference the semantic tokens via their CSS
// variables so the chart still tracks the active theme (this is chart config, not markup).
$chartOptions = [
'colors' => ['var(--chart-1-color, hsl(var(--chart-1)))', 'var(--chart-2-color, hsl(var(--chart-2)))'],
'chart' => [
'toolbar' => ['show' => false],
'zoom' => ['enabled' => false],
'fontFamily' => 'inherit',
'stacked' => false,
],
'plotOptions' => ['bar' => ['borderRadius' => 4, 'columnWidth' => '55%']],
'dataLabels' => ['enabled' => false],
'grid' => ['borderColor' => 'var(--border-color, hsl(var(--border)))', 'strokeDashArray' => 4],
'legend' => ['show' => true, 'position' => 'top', 'horizontalAlign' => 'left', 'labels' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
'xaxis' => [
'categories' => $categories,
'axisBorder' => ['show' => false],
'axisTicks' => ['show' => false],
'labels' => ['style' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
],
'yaxis' => ['labels' => ['style' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']]],
];
@endphp
<section 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">
{{-- Header --}}
<div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
<div>
<h1 class="text-2xl font-bold tracking-tight">{{ __($title) }}</h1>
<p class="mt-2 text-muted-foreground">{{ __($subtitle) }}</p>
</div>
<div class="flex shrink-0 gap-2">
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap">{{ __('Last 7 days') }}</x-ui.button>
<x-ui.button size="sm" class="whitespace-nowrap">{{ __('New conversation') }}</x-ui.button>
</div>
</div>
{{-- CSAT + volume stat row --}}
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($stats as $stat)
<x-ui.stat
:label="__($stat['label'])"
:value="$stat['value']"
:delta="$stat['delta']"
:description="__($stat['description'])"
/>
@endforeach
</div>
{{-- Conversation chart + on-duty team --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Conversation volume') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Inbound versus resolved conversations this week.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.chart type="bar" :series="$series" :options="$chartOptions" :height="300" :label="__('Conversation volume bar chart')" />
</x-ui.card.content>
</x-ui.card>
<x-ui.card>
<x-ui.card.header>
<div class="flex items-center justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __('On duty') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Agents handling the queue right now.') }}</x-ui.card.description>
</div>
<x-ui.badge variant="success" class="whitespace-nowrap">{{ __('2 online') }}</x-ui.badge>
</div>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.item.group class="gap-2">
@foreach ($team as $agent)
<x-ui.item size="sm" class="px-0">
<x-ui.item.media class="relative">
<x-ui.avatar size="md" :fallback="$agent['initials']" :alt="$agent['name']" />
<span @class([
'absolute -bottom-0.5 -end-0.5 size-3 rounded-full ring-2 ring-card',
$statusDot[$agent['tone']] ?? 'bg-muted-foreground',
]) aria-hidden="true"></span>
</x-ui.item.media>
<x-ui.item.content class="min-w-0">
<x-ui.item.title><span class="truncate">{{ $agent['name'] }}</span></x-ui.item.title>
<x-ui.item.description class="truncate text-xs">{{ __($agent['role']) }}, {{ $agent['open'] }} {{ __('open') }}</x-ui.item.description>
</x-ui.item.content>
<x-ui.item.actions>
<x-ui.badge :variant="$agent['tone'] === 'secondary' ? 'secondary' : $agent['tone']" class="whitespace-nowrap">{{ __($agent['status']) }}</x-ui.badge>
</x-ui.item.actions>
</x-ui.item>
@endforeach
</x-ui.item.group>
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Recent tickets --}}
<x-ui.card>
<x-ui.card.header>
<div class="flex items-center justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __('Recent tickets') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Latest items across every inbox.') }}</x-ui.card.description>
</div>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap">{{ __('View all') }}</x-ui.button>
</div>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.table>
<x-ui.table.header>
<x-ui.table.row>
<x-ui.table.head>{{ __('Ticket') }}</x-ui.table.head>
<x-ui.table.head>{{ __('Subject') }}</x-ui.table.head>
<x-ui.table.head class="max-sm:hidden">{{ __('Customer') }}</x-ui.table.head>
<x-ui.table.head>{{ __('Priority') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Status') }}</x-ui.table.head>
</x-ui.table.row>
</x-ui.table.header>
<x-ui.table.body>
@foreach ($tickets as $ticket)
<x-ui.table.row>
<x-ui.table.cell class="font-medium tabular-nums">{{ $ticket['id'] }}</x-ui.table.cell>
<x-ui.table.cell>{{ __($ticket['subject']) }}</x-ui.table.cell>
<x-ui.table.cell class="text-muted-foreground max-sm:hidden">{{ $ticket['customer'] }}</x-ui.table.cell>
<x-ui.table.cell>
<x-ui.badge :variant="$ticket['priorityTone']">{{ __($ticket['priority']) }}</x-ui.badge>
</x-ui.table.cell>
<x-ui.table.cell class="text-end">
<x-ui.badge :variant="$ticket['statusTone']">{{ __($ticket['status']) }}</x-ui.badge>
</x-ui.table.cell>
</x-ui.table.row>
@endforeach
</x-ui.table.body>
</x-ui.table>
</x-ui.card.content>
</x-ui.card>
</div>
</section>
Installation
php artisan ui:add pages/dashboard-support
Registry contract
Install confidence
php artisan ui:add pages/dashboard-support
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.7
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/pages/dashboard-support.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 03 (`dashboard-support`)
A customer-support dashboard: CSAT and volume KPI stats, an inbound-versus-resolved conversation bar chart, an on-duty team card with avatars and status badges, and a recent-tickets table.
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-support
```
## Render it
```blade
<x-pages.dashboard-support />
```
## Props
- `title` (string, default `Support overview`) — Section heading.
- `subtitle` (string, default `Conversation volume, satisfaction, and your on-duty team.`) — Supporting copy under the heading.
- `stats` (mixed|null, default `null`) — KPI stat cards ({label, value, delta, description}); null falls back to sample data.
- `series` (mixed|null, default `null`) — Inbound-versus-resolved chart series; null falls back to sample data.
- `categories` (mixed|null, default `null`) — X-axis weekday labels for the chart; null falls back to sample data.
- `team` (mixed|null, default `null`) — On-duty team rows with role, open-ticket count and status; null falls back to sample data.
- `tickets` (mixed|null, default `null`) — Recent-tickets table rows; null falls back to sample data.
## Use when
- A customer-support admin dashboard: CSAT and volume KPI stats, an inbound-versus-resolved conversation bar chart, an on-duty team card with avatars and a recent-tickets table.
- It composes primitives directly (stat, card, chart, table, button, badge, avatar, item) rather than marketing blocks.
## Avoid when
- Needing a finance, commerce or web-analytics dashboard instead of support; use dashboard-dense-kpi, dashboard-commerce or dashboard-analytics instead.
## Rules
- Render the installed page with `<x-pages.dashboard-support />` 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-support
- Registry JSON (files, props, contract): https://brokui.dev/r/open/pages/dashboard-support.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 customer-support admin dashboard: CSAT and volume KPI stats, an inbound-versus-resolved conversation bar chart, an on-duty team card with avatars and a recent-tickets table.
- It composes primitives directly (stat, card, chart, table, button, badge, avatar, item) rather than marketing blocks.
Avoid when
- Needing a finance, commerce or web-analytics dashboard instead of support; use dashboard-dense-kpi, dashboard-commerce or dashboard-analytics 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-support />
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([
'title' => 'Support overview',
'subtitle' => 'Conversation volume, satisfaction, and your on-duty team.',
'stats' => null,
'series' => null,
'categories' => null,
'team' => null,
'tickets' => null,
])
@php
$stats ??= [
['label' => 'Open conversations', 'value' => '128', 'delta' => '+6.0%', 'description' => 'vs yesterday'],
['label' => 'CSAT score', 'value' => '94.2%', 'delta' => '+1.8%', 'description' => 'last 7 days'],
['label' => 'Avg. first reply', 'value' => '3m 12s', 'delta' => '-0.7%', 'description' => 'faster than target'],
['label' => 'Resolved today', 'value' => '342', 'delta' => '+12.4%', 'description' => 'vs yesterday'],
];
$series ??= [
['name' => __('Inbound'), 'data' => [320, 412, 388, 451, 502, 287, 196]],
['name' => __('Resolved'), 'data' => [298, 376, 354, 423, 471, 268, 184]],
];
$categories ??= [
__('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat'), __('Sun'),
];
$team ??= [
['name' => 'Ava Chen', 'initials' => 'AC', 'role' => 'Tier 2', 'open' => 7, 'status' => 'Online', 'tone' => 'success'],
['name' => 'Diego Mora', 'initials' => 'DM', 'role' => 'Tier 1', 'open' => 12, 'status' => 'Online', 'tone' => 'success'],
['name' => 'Priya Nair', 'initials' => 'PN', 'role' => 'Billing', 'open' => 3, 'status' => 'Away', 'tone' => 'warning'],
['name' => 'Sam Okafor', 'initials' => 'SO', 'role' => 'Tier 2', 'open' => 0, 'status' => 'Offline', 'tone' => 'secondary'],
];
$tickets ??= [
['id' => 'TKT-5821', 'subject' => 'Cannot export reports', 'customer' => 'Lumen Studio', 'priority' => 'High', 'priorityTone' => 'destructive', 'status' => 'Open', 'statusTone' => 'warning'],
['id' => 'TKT-5820', 'subject' => 'Billing address update', 'customer' => 'Northwind Co.', 'priority' => 'Low', 'priorityTone' => 'secondary', 'status' => 'Pending', 'statusTone' => 'outline'],
['id' => 'TKT-5819', 'subject' => 'SSO login loop', 'customer' => 'Atlas Freight', 'priority' => 'High', 'priorityTone' => 'destructive', 'status' => 'Open', 'statusTone' => 'warning'],
['id' => 'TKT-5818', 'subject' => 'Feature request: dark mode', 'customer' => 'Peak Labs', 'priority' => 'Medium', 'priorityTone' => 'default', 'status' => 'Resolved', 'statusTone' => 'success'],
['id' => 'TKT-5817', 'subject' => 'Webhook retries failing', 'customer' => 'Vela Group', 'priority' => 'Medium', 'priorityTone' => 'default', 'status' => 'Resolved', 'statusTone' => 'success'],
];
$statusDot = [
'success' => 'bg-success',
'warning' => 'bg-warning',
'secondary' => 'bg-muted-foreground',
];
// ApexCharts needs concrete colours; reference the semantic tokens via their CSS
// variables so the chart still tracks the active theme (this is chart config, not markup).
$chartOptions = [
'colors' => ['var(--chart-1-color, hsl(var(--chart-1)))', 'var(--chart-2-color, hsl(var(--chart-2)))'],
'chart' => [
'toolbar' => ['show' => false],
'zoom' => ['enabled' => false],
'fontFamily' => 'inherit',
'stacked' => false,
],
'plotOptions' => ['bar' => ['borderRadius' => 4, 'columnWidth' => '55%']],
'dataLabels' => ['enabled' => false],
'grid' => ['borderColor' => 'var(--border-color, hsl(var(--border)))', 'strokeDashArray' => 4],
'legend' => ['show' => true, 'position' => 'top', 'horizontalAlign' => 'left', 'labels' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
'xaxis' => [
'categories' => $categories,
'axisBorder' => ['show' => false],
'axisTicks' => ['show' => false],
'labels' => ['style' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
],
'yaxis' => ['labels' => ['style' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']]],
];
@endphp
<section 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">
{{-- Header --}}
<div class="flex flex-col justify-between gap-4 sm:flex-row sm:items-center">
<div>
<h1 class="text-2xl font-bold tracking-tight">{{ __($title) }}</h1>
<p class="mt-2 text-muted-foreground">{{ __($subtitle) }}</p>
</div>
<div class="flex shrink-0 gap-2">
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap">{{ __('Last 7 days') }}</x-ui.button>
<x-ui.button size="sm" class="whitespace-nowrap">{{ __('New conversation') }}</x-ui.button>
</div>
</div>
{{-- CSAT + volume stat row --}}
<div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
@foreach ($stats as $stat)
<x-ui.stat
:label="__($stat['label'])"
:value="$stat['value']"
:delta="$stat['delta']"
:description="__($stat['description'])"
/>
@endforeach
</div>
{{-- Conversation chart + on-duty team --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Conversation volume') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Inbound versus resolved conversations this week.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.chart type="bar" :series="$series" :options="$chartOptions" :height="300" :label="__('Conversation volume bar chart')" />
</x-ui.card.content>
</x-ui.card>
<x-ui.card>
<x-ui.card.header>
<div class="flex items-center justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __('On duty') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Agents handling the queue right now.') }}</x-ui.card.description>
</div>
<x-ui.badge variant="success" class="whitespace-nowrap">{{ __('2 online') }}</x-ui.badge>
</div>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.item.group class="gap-2">
@foreach ($team as $agent)
<x-ui.item size="sm" class="px-0">
<x-ui.item.media class="relative">
<x-ui.avatar size="md" :fallback="$agent['initials']" :alt="$agent['name']" />
<span @class([
'absolute -bottom-0.5 -end-0.5 size-3 rounded-full ring-2 ring-card',
$statusDot[$agent['tone']] ?? 'bg-muted-foreground',
]) aria-hidden="true"></span>
</x-ui.item.media>
<x-ui.item.content class="min-w-0">
<x-ui.item.title><span class="truncate">{{ $agent['name'] }}</span></x-ui.item.title>
<x-ui.item.description class="truncate text-xs">{{ __($agent['role']) }}, {{ $agent['open'] }} {{ __('open') }}</x-ui.item.description>
</x-ui.item.content>
<x-ui.item.actions>
<x-ui.badge :variant="$agent['tone'] === 'secondary' ? 'secondary' : $agent['tone']" class="whitespace-nowrap">{{ __($agent['status']) }}</x-ui.badge>
</x-ui.item.actions>
</x-ui.item>
@endforeach
</x-ui.item.group>
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Recent tickets --}}
<x-ui.card>
<x-ui.card.header>
<div class="flex items-center justify-between gap-4">
<div class="space-y-2">
<x-ui.card.title>{{ __('Recent tickets') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Latest items across every inbox.') }}</x-ui.card.description>
</div>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap">{{ __('View all') }}</x-ui.button>
</div>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.table>
<x-ui.table.header>
<x-ui.table.row>
<x-ui.table.head>{{ __('Ticket') }}</x-ui.table.head>
<x-ui.table.head>{{ __('Subject') }}</x-ui.table.head>
<x-ui.table.head class="max-sm:hidden">{{ __('Customer') }}</x-ui.table.head>
<x-ui.table.head>{{ __('Priority') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Status') }}</x-ui.table.head>
</x-ui.table.row>
</x-ui.table.header>
<x-ui.table.body>
@foreach ($tickets as $ticket)
<x-ui.table.row>
<x-ui.table.cell class="font-medium tabular-nums">{{ $ticket['id'] }}</x-ui.table.cell>
<x-ui.table.cell>{{ __($ticket['subject']) }}</x-ui.table.cell>
<x-ui.table.cell class="text-muted-foreground max-sm:hidden">{{ $ticket['customer'] }}</x-ui.table.cell>
<x-ui.table.cell>
<x-ui.badge :variant="$ticket['priorityTone']">{{ __($ticket['priority']) }}</x-ui.badge>
</x-ui.table.cell>
<x-ui.table.cell class="text-end">
<x-ui.badge :variant="$ticket['statusTone']">{{ __($ticket['status']) }}</x-ui.badge>
</x-ui.table.cell>
</x-ui.table.row>
@endforeach
</x-ui.table.body>
</x-ui.table>
</x-ui.card.content>
</x-ui.card>
</div>
</section>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.7 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0