@props([ 'series' => [], // [['date' => 'Y-m-d', 'value' => int], ...] 'label' => '', 'format' => 'number', // number | bytes | money 'accent' => 'electric', ]) @php /* | Inline SVG area chart. No charting library: this draws one shape from a | list of numbers, and pulling in ~100KB of JavaScript to do that would | cost more than the feature is worth — on an admin page that also has to | work with JS disabled. */ $points = collect($series); $values = $points->pluck('value'); $max = max(1, (int) $values->max()); $total = (int) $values->sum(); $latest = (int) ($values->last() ?? 0); $width = 600; $height = 120; $count = max(1, $points->count() - 1); $coords = $points->values()->map(function (array $point, int $index) use ($max, $width, $height, $count) { return [ 'x' => round($index / $count * $width, 2), // SVG y grows downward, so invert. 4px inset keeps the peak from // being clipped by the viewBox edge. 'y' => round($height - ($point['value'] / $max) * ($height - 8) - 4, 2), 'date' => $point['date'], 'value' => $point['value'], ]; }); $line = $coords->map(fn ($c) => "{$c['x']},{$c['y']}")->implode(' '); $area = "0,{$height} ".$line." {$width},{$height}"; $id = 'chart-'.Str::random(6); $stroke = $accent === 'cyan' ? 'var(--color-cyan-400)' : 'var(--color-electric-400)'; $display = match ($format) { 'bytes' => format_bytes($total), 'money' => format_money($total), default => number_format($total), }; @endphp
{{ $label }}
{{ $display }}
No data in this period.
@else {{-- The same numbers as text. A chart alone is unreadable to a screen reader, and preserveAspectRatio="none" distorts any inline label. --}}| {{ $c['date'] }} | @if ($format === 'bytes') {{ format_bytes($c['value']) }} @elseif ($format === 'money') {{ format_money($c['value']) }} @else {{ number_format($c['value']) }} @endif |