clusev/resources/views/components/metric.blade.php

56 lines
2.8 KiB
PHP

@props(['label', 'value', 'unit' => null, 'sub' => null, 'icon' => null, 'series' => [], 'tone' => 'accent', 'trend' => null])
@php
use Illuminate\Support\Str;
$stroke = [
'accent' => 'text-accent', 'cyan' => 'text-cyan', 'online' => 'text-online',
'warning' => 'text-warning', 'offline' => 'text-offline',
][$tone] ?? 'text-accent';
$gid = 'm-'.Str::slug($label);
// sparkline path from the series
$n = count($series); $w = 100; $h = 40; $pad = 4; $pts = [];
$min = $n ? min($series) : 0; $max = $n ? max($series) : 1; $range = max(1, $max - $min);
foreach ($series as $i => $v) {
$x = $n > 1 ? round($i / ($n - 1) * $w, 2) : 0;
$y = round($h - $pad - (($v - $min) / $range) * ($h - 2 * $pad), 2);
$pts[] = "$x,$y";
}
$line = implode(' ', $pts);
$area = $n ? "0,$h ".$line." $w,$h" : '';
$trendColor = ['up' => 'text-online', 'down' => 'text-offline', 'flat' => 'text-ink-3'][$trend['dir'] ?? 'flat'] ?? 'text-ink-3';
$arrow = ['up' => '▲', 'down' => '▼', 'flat' => '▪'][$trend['dir'] ?? 'flat'] ?? '▪';
@endphp
<div {{ $attributes->merge(['class' => 'relative flex min-h-[122px] flex-col gap-2.5 overflow-hidden rounded-lg border border-line bg-surface pt-4 shadow-panel']) }}>
<div class="flex items-center justify-between gap-2 px-4">
<span class="inline-flex items-center gap-1.5 font-mono text-[11px] uppercase tracking-wider text-ink-3">
@if ($icon)<x-icon :name="$icon" class="h-3.5 w-3.5 text-ink-4" />@endif
{{ $label }}
</span>
@if ($trend)
<span class="font-mono text-[11px] {{ $trendColor }}">{{ $arrow }} {{ $trend['text'] }}</span>
@endif
</div>
<div class="flex items-baseline gap-1 px-4">
<span class="tabular font-mono text-3xl font-medium leading-none text-ink">{{ $value }}</span>
@if ($unit)<span class="font-mono text-sm text-ink-2">{{ $unit }}</span>@endif
@if ($sub)<span class="ml-0.5 font-mono text-[11px] text-ink-3">{{ $sub }}</span>@endif
</div>
<div class="mt-auto h-10 {{ $stroke }}">
<svg viewBox="0 0 100 40" preserveAspectRatio="none" class="h-full w-full" aria-hidden="true">
<defs>
<linearGradient id="{{ $gid }}" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="currentColor" stop-opacity="0.28" />
<stop offset="100%" stop-color="currentColor" stop-opacity="0" />
</linearGradient>
</defs>
@if ($area)<polyline points="{{ $area }}" fill="url(#{{ $gid }})" stroke="none" />@endif
@if ($line)<polyline points="{{ $line }}" fill="none" stroke="currentColor" stroke-width="1.5" vector-effect="non-scaling-stroke" stroke-linejoin="round" />@endif
</svg>
</div>
</div>