Data display
Monitoring Chart code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/monitoring-chart.blade.php
@props([
'label',
'value',
'type' => 'stacked-bar',
'labels' => [],
'series' => [],
'height' => 200,
'grid' => false,
'startLabel' => null,
'endLabel' => null,
])
@php
/*
| Nightwatch-style monitoring panel — uppercase metric label, headline value,
| inline legend with coloured dots, and a dense time-series chart.
|
| type: stacked-bar | line
| series: [['label' => '1/2/3XX', 'summary' => '123K', 'color' => 'gray', 'data' => [...]]]
|
| Usage:
| <x-ui.monitoring-chart
| label="Requests"
| value="124.2K"
| type="stacked-bar"
| :series="$requestSeries"
| start-label="02 Nov 18:00:00 UTC"
| end-label="03 Nov 18:00:00 UTC"
| />
*/
$legendDot = fn (string $color): string => match ($color) {
'amber' => 'bg-amber-500',
'red' => 'bg-red-500',
'green' => 'bg-green-600',
'brand' => 'bg-brand-500',
default => 'bg-gray-400 dark:bg-gray-500',
};
$legendValue = fn (string $color): string => match ($color) {
'amber' => 'text-amber-500',
'red' => 'text-red-500',
'green' => 'text-green-600',
'brand' => 'text-brand-500',
default => 'text-gray-900 dark:text-white',
};
$normalizedSeries = collect($series)
->values()
->map(function (array $item): array {
$color = $item['color'] ?? 'gray';
// Only pass explicit hex through; named tokens resolve from CSS
// vars at chart render time so series follow the active theme.
$chartColor = is_string($color) && str_starts_with($color, '#')
? $color
: null;
return [
'label' => $item['label'] ?? '',
'summary' => $item['summary'] ?? '',
'color' => $color,
'chartColor' => $chartColor,
'data' => array_values($item['data'] ?? []),
];
})
->all();
$config = [
'type' => $type,
'labels' => array_values($labels),
'series' => $normalizedSeries,
'grid' => (bool) $grid,
];
$pointCount = max(array_map(fn (array $item) => count($item['data'] ?? []), $normalizedSeries) ?: [0]);
$seriesLabels = collect($normalizedSeries)->pluck('label')->filter()->implode(', ');
$accessibleLabel = trim(implode(' ', array_filter([
$label ? $label.' monitoring chart.' : 'Monitoring chart.',
$seriesLabels !== '' ? 'Series: '.$seriesLabels.'.' : null,
$pointCount > 0 ? $pointCount.' data point'.($pointCount === 1 ? '' : 's').'.' : null,
])));
@endphp
<div {{ $attributes->class(['harbour-monitoring-chart overflow-hidden rounded-xl border border-gray-200 bg-white dark:border-gray-800 dark:bg-gray-950']) }}>
<div class="px-5 pt-5">
<p class="text-[11px] font-semibold uppercase tracking-[0.14em] text-gray-500 dark:text-gray-400">
{{ $label }}
</p>
<p class="mt-2 text-3xl font-semibold tracking-tight text-gray-900 tabular-nums dark:text-white">
{{ $value }}
</p>
@if ($normalizedSeries !== [])
<div class="mt-4 flex flex-wrap gap-x-5 gap-y-2">
@foreach ($normalizedSeries as $item)
<div class="flex items-center gap-2 text-xs">
<span @class(['h-2 w-2 shrink-0 rounded-full', $legendDot($item['color'])]) aria-hidden="true"></span>
<span class="font-medium text-gray-500 dark:text-gray-400">{{ $item['label'] }}</span>
<span @class(['font-semibold tabular-nums', $legendValue($item['color'])])>{{ $item['summary'] }}</span>
</div>
@endforeach
</div>
@endif
</div>
<div
x-data="uiMonitoringChart(@js($config))"
wire:ignore
class="harbour-monitoring-chart__canvas relative bg-gray-100/80 px-3 pt-2 dark:bg-black/50"
style="height: {{ is_numeric($height) ? $height.'px' : $height }}"
>
<canvas x-ref="canvas" role="img" aria-label="{{ $accessibleLabel }}"></canvas>
</div>
@if ($startLabel || $endLabel)
<div class="flex items-center justify-between px-5 pb-4 text-[11px] text-gray-500 dark:text-gray-400">
<span>{{ $startLabel }}</span>
<span>{{ $endLabel }}</span>
</div>
@endif
</div>