44 lines
1.6 KiB
PHP
44 lines
1.6 KiB
PHP
@props(['label', 'value', 'previousValue' => null, 'format' => 'number', 'suffix' => ''])
|
|||
|
|
|
||
|
|
@php
|
||
|
|
$formatted = match($format) {
|
||
|
|
'duration' => gmdate('i:s', (int) $value),
|
||
|
|
'percent' => $value . '%',
|
||
|
|
default => number_format($value) . $suffix,
|
||
|
|
};
|
||
|
|
|
||
|
|
$delta = null;
|
||
|
|
$deltaClass = '';
|
||
|
|
$deltaIcon = '';
|
||
|
|
if ($previousValue !== null && is_numeric($previousValue)) {
|
||
|
|
if ($previousValue > 0) {
|
||
|
|
$delta = round((($value - $previousValue) / $previousValue) * 100, 1);
|
||
|
|
} elseif ($value > 0) {
|
||
|
|
$delta = 100;
|
||
|
|
}
|
||
|
|
|
||
|
|
if ($delta !== null) {
|
||
|
|
$isNegativeBetter = in_array($format, ['percent']) && str_contains(strtolower($label), 'bounce');
|
||
|
|
$isPositive = $delta > 0;
|
||
|
|
$isGood = $isNegativeBetter ? !$isPositive : $isPositive;
|
||
|
|
|
||
|
|
$deltaClass = $delta == 0
|
||
|
|
? 'text-gray-500 bg-gray-50'
|
||
|
|
: ($isGood ? 'text-emerald-700 bg-emerald-50' : 'text-red-700 bg-red-50');
|
||
|
|
$deltaIcon = $delta > 0 ? '↑' : ($delta < 0 ? '↓' : '→');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@endphp
|
||
|
|
|
||
|
|
<div class="bg-white rounded-xl border border-gray-200 p-5 hover:shadow-sm transition-shadow">
|
||
|
|
<dt class="text-sm font-medium text-gray-500 truncate">{{ $label }}</dt>
|
||
|
|
<dd class="mt-2 flex items-baseline gap-2">
|
||
|
|
<span class="text-2xl font-bold text-gray-900 tracking-tight">{{ $formatted }}</span>
|
||
|
|
@if ($delta !== null)
|
||
|
|
<span class="inline-flex items-center gap-0.5 rounded-full px-2 py-0.5 text-xs font-medium {{ $deltaClass }}">
|
||
|
|
{{ $deltaIcon }} {{ abs($delta) }}%
|
||
|
|
</span>
|
||
|
|
@endif
|
||
|
|
</dd>
|
||
|
|
</div>
|