Dashboard
Full dashboard screens — KPI stats, charts, tables and activity feeds across finance, commerce, support, analytics and observability.
Preview
@props([
'title' => 'Analytics',
'subtitle' => 'Real-time traffic and performance for the last 7 days.',
'stats' => null,
'visitorSeries' => null,
'visitorCategories' => null,
'liveSeries' => null,
'topPages' => null,
'sources' => null,
'vitals' => null,
])
@php
$stats ??= [
['label' => 'Visitors', 'value' => '128,420', 'delta' => '+8.2%', 'description' => 'vs last week'],
['label' => 'Page views', 'value' => '482,910', 'delta' => '+5.7%', 'description' => 'vs last week'],
['label' => 'Bounce rate', 'value' => '38.4%', 'delta' => '-2.1%', 'description' => 'vs last week'],
['label' => 'Avg. session', 'value' => '3m 12s', 'delta' => '+0.9%', 'description' => 'vs last week'],
];
$visitorSeries ??= [
['name' => __('Visitors'), 'data' => [9200, 11400, 10600, 13800, 12200, 8600, 15400]],
['name' => __('Returning'), 'data' => [4200, 5100, 4800, 6200, 5600, 3900, 6900]],
];
$visitorCategories ??= [__('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat'), __('Sun')];
// Tiny sparkline for the "live users" card.
$liveSeries ??= [['name' => __('Live'), 'data' => [38, 44, 41, 52, 48, 61, 57, 66, 72, 68, 81, 79]]];
$topPages ??= [
['path' => '/', 'views' => '84,210', 'unique' => '52,140', 'share' => '17.4%'],
['path' => '/pricing', 'views' => '41,920', 'unique' => '33,610', 'share' => '8.7%'],
['path' => '/blog/launch', 'views' => '28,640', 'unique' => '24,180', 'share' => '5.9%'],
['path' => '/docs/install', 'views' => '19,330', 'unique' => '15,720', 'share' => '4.0%'],
['path' => '/changelog', 'views' => '12,880', 'unique' => '10,940', 'share' => '2.7%'],
];
$sources ??= [
['label' => 'Organic search', 'value' => 46],
['label' => 'Direct', 'value' => 28],
['label' => 'Referral', 'value' => 14],
['label' => 'Social', 'value' => 9],
['label' => 'Email', 'value' => 3],
];
$vitals ??= [
['label' => 'LCP', 'name' => 'Largest Contentful Paint', 'value' => '1.9s', 'status' => 'Good', 'tone' => 'success'],
['label' => 'INP', 'name' => 'Interaction to Next Paint', 'value' => '184ms', 'status' => 'Needs work', 'tone' => 'warning'],
['label' => 'CLS', 'name' => 'Cumulative Layout Shift', 'value' => '0.04', 'status' => 'Good', 'tone' => 'success'],
];
// ApexCharts config: colours reference semantic tokens via CSS vars so the
// chart tracks the active theme (chart config data, not markup).
$visitorOptions = [
'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'],
'stroke' => ['curve' => 'smooth', 'width' => 2],
'dataLabels' => ['enabled' => false],
'fill' => ['type' => 'gradient', 'gradient' => ['shadeIntensity' => 1, 'opacityFrom' => 0.4, 'opacityTo' => 0.05, 'stops' => [0, 90, 100]]],
'grid' => ['borderColor' => 'var(--border-color, hsl(var(--border)))', 'strokeDashArray' => 4],
'legend' => ['show' => true, 'labels' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
'xaxis' => [
'categories' => $visitorCategories,
'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)))']]],
];
$sparkOptions = [
'colors' => ['var(--chart-1-color, hsl(var(--chart-1)))'],
'chart' => ['sparkline' => ['enabled' => true], 'fontFamily' => 'inherit'],
'stroke' => ['curve' => 'smooth', 'width' => 2],
'fill' => ['type' => 'gradient', 'gradient' => ['shadeIntensity' => 1, 'opacityFrom' => 0.4, 'opacityTo' => 0.05]],
'tooltip' => ['enabled' => false],
];
@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 items-center gap-2">
<span class="inline-flex items-center gap-2 rounded-full bg-success/10 px-2 py-2 text-xs font-medium text-success">
<span class="relative flex size-2">
<span class="absolute inline-flex size-full motion-safe:animate-ping rounded-full bg-success opacity-75"></span>
<span class="relative inline-flex size-2 rounded-full bg-success"></span>
</span>
{{ __('Live') }}
</span>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap shrink-0">
<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="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
{{ __('Last 7 days') }}
</x-ui.button>
</div>
</div>
{{-- KPI 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>
{{-- Visitors chart + live users --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Visitors') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Daily visitors and returning audience this week.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.chart type="area" :series="$visitorSeries" :options="$visitorOptions" :height="300" :label="__('Weekly visitors area chart')" />
</x-ui.card.content>
</x-ui.card>
<x-ui.card class="flex flex-col">
<x-ui.card.header>
<x-ui.card.title>{{ __('Live users') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Active on the site right now.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content class="flex flex-1 flex-col justify-between gap-4">
<div class="flex items-baseline gap-2">
<span class="text-2xl font-bold tracking-tight tabular-nums">1,284</span>
<span class="inline-flex items-center gap-2 text-sm font-medium text-success">
<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="M7 17 17 7"/><path d="M7 7h10v10"/></svg>
12%
</span>
</div>
<x-ui.chart type="area" :series="$liveSeries" :options="$sparkOptions" :height="90" :label="__('Live users sparkline')" />
<dl class="grid grid-cols-3 gap-2 border-t border-border pt-4 text-center">
<div>
<dt class="text-xs text-muted-foreground">{{ __('Desktop') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">742</dd>
</div>
<div>
<dt class="text-xs text-muted-foreground">{{ __('Mobile') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">468</dd>
</div>
<div>
<dt class="text-xs text-muted-foreground">{{ __('Tablet') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">74</dd>
</div>
</dl>
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Top pages + traffic sources --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<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>{{ __('Top pages') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Most-viewed pages in the selected range.') }}</x-ui.card.description>
</div>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap shrink-0">{{ __('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>{{ __('Page') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Views') }}</x-ui.table.head>
<x-ui.table.head class="text-end max-sm:hidden">{{ __('Unique') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Share') }}</x-ui.table.head>
</x-ui.table.row>
</x-ui.table.header>
<x-ui.table.body>
@foreach ($topPages as $page)
<x-ui.table.row>
<x-ui.table.cell class="font-medium">{{ $page['path'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums">{{ $page['views'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums max-sm:hidden">{{ $page['unique'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums text-muted-foreground">{{ $page['share'] }}</x-ui.table.cell>
</x-ui.table.row>
@endforeach
</x-ui.table.body>
</x-ui.table>
</x-ui.card.content>
</x-ui.card>
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Traffic sources') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Where your visitors come from.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content class="space-y-4 text-sm">
@foreach ($sources as $source)
<div>
<div class="mb-2 flex items-center justify-between">
<span class="font-medium">{{ __($source['label']) }}</span>
<span class="text-muted-foreground tabular-nums">{{ $source['value'] }}%</span>
</div>
<x-ui.progress :value="$source['value']" :aria-label="__($source['label'])" />
</div>
@endforeach
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Core Web Vitals --}}
<div>
<h2 class="mb-4 text-sm font-semibold text-muted-foreground">{{ __('Core Web Vitals') }}</h2>
<div class="grid gap-4 sm:grid-cols-3">
@foreach ($vitals as $vital)
<x-ui.card>
<x-ui.card.content class="pt-6">
<div class="flex items-start justify-between gap-2">
<div>
<p class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">{{ $vital['label'] }}</p>
<p class="mt-2 text-2xl font-bold tabular-nums">{{ $vital['value'] }}</p>
</div>
<x-ui.badge :variant="$vital['tone']">{{ __($vital['status']) }}</x-ui.badge>
</div>
<p class="mt-4 text-xs text-muted-foreground">{{ __($vital['name']) }}</p>
</x-ui.card.content>
</x-ui.card>
@endforeach
</div>
</div>
</div>
</section>
Installation
php artisan ui:add pages/dashboard-analytics
Registry contract
Install confidence
php artisan ui:add pages/dashboard-analytics
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.6
- License
- open
- Stability
- stable
- Contract
- v1
- Foundation
- ≥ 1.0.0
| Type | Generated target |
|---|---|
| blade | resources/views/pages/dashboard-analytics.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 05 (`dashboard-analytics`)
A web-analytics dashboard with a visitors area chart, a live-users sparkline card, a top-pages table, traffic-source meters, and Core Web Vitals cards.
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-analytics
```
## Render it
```blade
<x-pages.dashboard-analytics />
```
## Props
- `title` (string, default `Analytics`) — Section heading.
- `subtitle` (string, default `Real-time traffic and performance for the last 7 days.`) — Supporting copy under the heading.
- `stats` (mixed|null, default `null`) — KPI stat cards ({label, value, delta, description}); null falls back to sample data.
- `visitor-series` (mixed|null, default `null`) — Visitors-versus-returning area-chart series; null falls back to sample data.
- `visitor-categories` (mixed|null, default `null`) — X-axis weekday labels for the visitors chart; null falls back to sample data.
- `live-series` (mixed|null, default `null`) — Sparkline data for the live-users card; null falls back to sample data.
- `top-pages` (mixed|null, default `null`) — Top-pages table rows; null falls back to sample data.
- `sources` (mixed|null, default `null`) — Traffic-source meter rows ({label, value}); null falls back to sample data.
- `vitals` (mixed|null, default `null`) — Core Web Vitals cards ({label, name, value, status, tone}); null falls back to sample data.
## Use when
- A web-analytics admin dashboard: a visitors area chart, a live-users sparkline card, a top-pages table, traffic-source meters and Core Web Vitals cards.
- It composes primitives directly (stat, card, chart, table, button, badge, progress) rather than marketing blocks.
## Avoid when
- Needing finance, support or commerce metrics instead of web analytics; use dashboard-dense-kpi, dashboard-support or dashboard-commerce instead. Needing a simpler single-chart view; use dashboard-traffic instead.
## Rules
- Render the installed page with `<x-pages.dashboard-analytics />` 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-analytics
- Registry JSON (files, props, contract): https://brokui.dev/r/open/pages/dashboard-analytics.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 web-analytics admin dashboard: a visitors area chart, a live-users sparkline card, a top-pages table, traffic-source meters and Core Web Vitals cards.
- It composes primitives directly (stat, card, chart, table, button, badge, progress) rather than marketing blocks.
Avoid when
- Needing finance, support or commerce metrics instead of web analytics; use dashboard-dense-kpi, dashboard-support or dashboard-commerce instead. Needing a simpler single-chart view; use dashboard-traffic 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-analytics />
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' => 'Analytics',
'subtitle' => 'Real-time traffic and performance for the last 7 days.',
'stats' => null,
'visitorSeries' => null,
'visitorCategories' => null,
'liveSeries' => null,
'topPages' => null,
'sources' => null,
'vitals' => null,
])
@php
$stats ??= [
['label' => 'Visitors', 'value' => '128,420', 'delta' => '+8.2%', 'description' => 'vs last week'],
['label' => 'Page views', 'value' => '482,910', 'delta' => '+5.7%', 'description' => 'vs last week'],
['label' => 'Bounce rate', 'value' => '38.4%', 'delta' => '-2.1%', 'description' => 'vs last week'],
['label' => 'Avg. session', 'value' => '3m 12s', 'delta' => '+0.9%', 'description' => 'vs last week'],
];
$visitorSeries ??= [
['name' => __('Visitors'), 'data' => [9200, 11400, 10600, 13800, 12200, 8600, 15400]],
['name' => __('Returning'), 'data' => [4200, 5100, 4800, 6200, 5600, 3900, 6900]],
];
$visitorCategories ??= [__('Mon'), __('Tue'), __('Wed'), __('Thu'), __('Fri'), __('Sat'), __('Sun')];
// Tiny sparkline for the "live users" card.
$liveSeries ??= [['name' => __('Live'), 'data' => [38, 44, 41, 52, 48, 61, 57, 66, 72, 68, 81, 79]]];
$topPages ??= [
['path' => '/', 'views' => '84,210', 'unique' => '52,140', 'share' => '17.4%'],
['path' => '/pricing', 'views' => '41,920', 'unique' => '33,610', 'share' => '8.7%'],
['path' => '/blog/launch', 'views' => '28,640', 'unique' => '24,180', 'share' => '5.9%'],
['path' => '/docs/install', 'views' => '19,330', 'unique' => '15,720', 'share' => '4.0%'],
['path' => '/changelog', 'views' => '12,880', 'unique' => '10,940', 'share' => '2.7%'],
];
$sources ??= [
['label' => 'Organic search', 'value' => 46],
['label' => 'Direct', 'value' => 28],
['label' => 'Referral', 'value' => 14],
['label' => 'Social', 'value' => 9],
['label' => 'Email', 'value' => 3],
];
$vitals ??= [
['label' => 'LCP', 'name' => 'Largest Contentful Paint', 'value' => '1.9s', 'status' => 'Good', 'tone' => 'success'],
['label' => 'INP', 'name' => 'Interaction to Next Paint', 'value' => '184ms', 'status' => 'Needs work', 'tone' => 'warning'],
['label' => 'CLS', 'name' => 'Cumulative Layout Shift', 'value' => '0.04', 'status' => 'Good', 'tone' => 'success'],
];
// ApexCharts config: colours reference semantic tokens via CSS vars so the
// chart tracks the active theme (chart config data, not markup).
$visitorOptions = [
'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'],
'stroke' => ['curve' => 'smooth', 'width' => 2],
'dataLabels' => ['enabled' => false],
'fill' => ['type' => 'gradient', 'gradient' => ['shadeIntensity' => 1, 'opacityFrom' => 0.4, 'opacityTo' => 0.05, 'stops' => [0, 90, 100]]],
'grid' => ['borderColor' => 'var(--border-color, hsl(var(--border)))', 'strokeDashArray' => 4],
'legend' => ['show' => true, 'labels' => ['colors' => 'var(--muted-foreground-color, hsl(var(--muted-foreground)))']],
'xaxis' => [
'categories' => $visitorCategories,
'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)))']]],
];
$sparkOptions = [
'colors' => ['var(--chart-1-color, hsl(var(--chart-1)))'],
'chart' => ['sparkline' => ['enabled' => true], 'fontFamily' => 'inherit'],
'stroke' => ['curve' => 'smooth', 'width' => 2],
'fill' => ['type' => 'gradient', 'gradient' => ['shadeIntensity' => 1, 'opacityFrom' => 0.4, 'opacityTo' => 0.05]],
'tooltip' => ['enabled' => false],
];
@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 items-center gap-2">
<span class="inline-flex items-center gap-2 rounded-full bg-success/10 px-2 py-2 text-xs font-medium text-success">
<span class="relative flex size-2">
<span class="absolute inline-flex size-full motion-safe:animate-ping rounded-full bg-success opacity-75"></span>
<span class="relative inline-flex size-2 rounded-full bg-success"></span>
</span>
{{ __('Live') }}
</span>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap shrink-0">
<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="M8 2v4"/><path d="M16 2v4"/><rect width="18" height="18" x="3" y="4" rx="2"/><path d="M3 10h18"/></svg>
{{ __('Last 7 days') }}
</x-ui.button>
</div>
</div>
{{-- KPI 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>
{{-- Visitors chart + live users --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Visitors') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Daily visitors and returning audience this week.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content>
<x-ui.chart type="area" :series="$visitorSeries" :options="$visitorOptions" :height="300" :label="__('Weekly visitors area chart')" />
</x-ui.card.content>
</x-ui.card>
<x-ui.card class="flex flex-col">
<x-ui.card.header>
<x-ui.card.title>{{ __('Live users') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Active on the site right now.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content class="flex flex-1 flex-col justify-between gap-4">
<div class="flex items-baseline gap-2">
<span class="text-2xl font-bold tracking-tight tabular-nums">1,284</span>
<span class="inline-flex items-center gap-2 text-sm font-medium text-success">
<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="M7 17 17 7"/><path d="M7 7h10v10"/></svg>
12%
</span>
</div>
<x-ui.chart type="area" :series="$liveSeries" :options="$sparkOptions" :height="90" :label="__('Live users sparkline')" />
<dl class="grid grid-cols-3 gap-2 border-t border-border pt-4 text-center">
<div>
<dt class="text-xs text-muted-foreground">{{ __('Desktop') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">742</dd>
</div>
<div>
<dt class="text-xs text-muted-foreground">{{ __('Mobile') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">468</dd>
</div>
<div>
<dt class="text-xs text-muted-foreground">{{ __('Tablet') }}</dt>
<dd class="mt-0.5 font-semibold tabular-nums">74</dd>
</div>
</dl>
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Top pages + traffic sources --}}
<div class="grid gap-6 lg:grid-cols-[2fr_1fr]">
<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>{{ __('Top pages') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Most-viewed pages in the selected range.') }}</x-ui.card.description>
</div>
<x-ui.button variant="outline" size="sm" class="whitespace-nowrap shrink-0">{{ __('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>{{ __('Page') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Views') }}</x-ui.table.head>
<x-ui.table.head class="text-end max-sm:hidden">{{ __('Unique') }}</x-ui.table.head>
<x-ui.table.head class="text-end">{{ __('Share') }}</x-ui.table.head>
</x-ui.table.row>
</x-ui.table.header>
<x-ui.table.body>
@foreach ($topPages as $page)
<x-ui.table.row>
<x-ui.table.cell class="font-medium">{{ $page['path'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums">{{ $page['views'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums max-sm:hidden">{{ $page['unique'] }}</x-ui.table.cell>
<x-ui.table.cell class="text-end tabular-nums text-muted-foreground">{{ $page['share'] }}</x-ui.table.cell>
</x-ui.table.row>
@endforeach
</x-ui.table.body>
</x-ui.table>
</x-ui.card.content>
</x-ui.card>
<x-ui.card>
<x-ui.card.header>
<x-ui.card.title>{{ __('Traffic sources') }}</x-ui.card.title>
<x-ui.card.description>{{ __('Where your visitors come from.') }}</x-ui.card.description>
</x-ui.card.header>
<x-ui.card.content class="space-y-4 text-sm">
@foreach ($sources as $source)
<div>
<div class="mb-2 flex items-center justify-between">
<span class="font-medium">{{ __($source['label']) }}</span>
<span class="text-muted-foreground tabular-nums">{{ $source['value'] }}%</span>
</div>
<x-ui.progress :value="$source['value']" :aria-label="__($source['label'])" />
</div>
@endforeach
</x-ui.card.content>
</x-ui.card>
</div>
{{-- Core Web Vitals --}}
<div>
<h2 class="mb-4 text-sm font-semibold text-muted-foreground">{{ __('Core Web Vitals') }}</h2>
<div class="grid gap-4 sm:grid-cols-3">
@foreach ($vitals as $vital)
<x-ui.card>
<x-ui.card.content class="pt-6">
<div class="flex items-start justify-between gap-2">
<div>
<p class="text-xs font-semibold uppercase tracking-wide text-muted-foreground">{{ $vital['label'] }}</p>
<p class="mt-2 text-2xl font-bold tabular-nums">{{ $vital['value'] }}</p>
</div>
<x-ui.badge :variant="$vital['tone']">{{ __($vital['status']) }}</x-ui.badge>
</div>
<p class="mt-4 text-xs text-muted-foreground">{{ __($vital['name']) }}</p>
</x-ui.card.content>
</x-ui.card>
@endforeach
</div>
</div>
</div>
</section>
Ownership & lifecycle
Owner, release state, review evidence and adoption for this item.
- Owner
- Platform UI (@JoshJML)
- Current version
-
1.0.6 - Status
- Stable
- License
-
open - Deprecation
- Not deprecated
- Contract
-
v1 - Foundation
-
≥ 1.0.0