Skip to main content

Infrastructure

Usage Meter code

Copy the implementation or inspect every file that belongs to this component unit.

resources/views/components/ui/usage-meter.blade.php

@props([
    'label' => null,
    'used' => 0,
    'limit' => null,
    'unit' => null,
    'value' => null,
    'limitLabel' => null,
    'warnAt' => 75,
    'dangerAt' => 90,
    'variant' => null,
    'size' => 'base',
    'icon' => null,
    'showValues' => true,
    'note' => null,
])

@php
    /*
    | Metered-usage / quota bar for consumption-based billing. Shows "used of
    | limit" with a fill that turns amber past `warnAt` and red past `dangerAt`
    | (or when over the limit). Pass numeric `used`/`limit` for automatic
    | formatting and percent, or supply pre-formatted `value`/`limitLabel`.
    | A null `limit` is treated as unlimited.
    |
    | size: sm, base, lg
    |
    | Usage:
    |   <x-ui.usage-meter label="API calls" :used="8400" :limit="10000" unit="requests" note="Resets Jul 1" />
    |   <x-ui.usage-meter label="Storage" :used="92" :limit="100" unit="GB" icon="hard-drives" />
    |   <x-ui.usage-meter label="Seats" :used="12" :limit="null" limit-label="Unlimited" />
    */
    $isNumeric = is_numeric($used) && is_numeric($limit) && (float) $limit > 0;
    $percent = $isNumeric ? (int) round(((float) $used / (float) $limit) * 100) : 0;
    $clampedPercent = max(0, min(100, $percent));
    $isOver = $isNumeric && (float) $used > (float) $limit;

    $autoVariant = ($isOver || $percent >= (int) $dangerAt)
        ? 'red'
        : ($percent >= (int) $warnAt ? 'amber' : 'brand');
    $resolvedVariant = $variant ?? $autoVariant;

    $barColors = [
        'brand' => 'bg-brand-600 dark:bg-brand-500',
        'green' => 'bg-green-600 dark:bg-green-500',
        'amber' => 'bg-amber-500 dark:bg-amber-400',
        'red' => 'bg-red-600 dark:bg-red-500',
        'blue' => 'bg-accent-600 dark:bg-accent-500',
        'gray' => 'bg-gray-500 dark:bg-gray-400',
    ];
    $barColor = $barColors[$resolvedVariant] ?? $barColors['brand'];

    $heights = ['sm' => 'h-1.5', 'base' => 'h-2.5', 'lg' => 'h-3.5'];
    $height = $heights[$size] ?? $heights['base'];

    $format = fn ($number) => is_numeric($number) ? rtrim(rtrim(number_format((float) $number, 2), '0'), '.') : (string) $number;
    $usedDisplay = $value ?? $format($used);
    $limitDisplay = $limit === null ? ($limitLabel ?? 'Unlimited') : ($limitLabel ?? $format($limit));
    $unitSuffix = $unit ? ' '.$unit : '';
@endphp

<div {{ $attributes->merge(['class' => 'w-full']) }}>
    @if ($label || $showValues)
        <div class="mb-1.5 flex items-end justify-between gap-3">
            <div class="flex min-w-0 items-center gap-1.5">
                @if ($icon)
                    <x-ui.icon :name="$icon" size="sm" class="shrink-0 text-gray-400 dark:text-gray-500" />
                @endif
                @if ($label)
                    <span class="truncate text-sm font-medium text-gray-700 dark:text-gray-300">{{ $label }}</span>
                @endif
            </div>

            @if ($showValues)
                <span class="shrink-0 text-sm tabular-nums text-gray-500 dark:text-gray-400">
                    <span class="font-medium text-gray-900 dark:text-white">{{ $usedDisplay }}</span>
                    <span class="text-gray-400 dark:text-gray-500"> / {{ $limitDisplay }}{{ $unitSuffix }}</span>
                </span>
            @endif
        </div>
    @endif

    <div
        class="w-full overflow-hidden rounded-full bg-gray-200 dark:bg-gray-800 {{ $height }}"
        role="progressbar"
        aria-valuemin="0"
        aria-valuemax="100"
        aria-valuenow="{{ $clampedPercent }}"
        @if ($label) aria-label="{{ $label }}" @endif
    >
        <div class="{{ $height }} rounded-full transition-all duration-500 {{ $barColor }}" style="width: {{ $isNumeric ? $clampedPercent : 0 }}%"></div>
    </div>

    @if ($isNumeric || $note || $isOver)
        <div class="mt-1.5 flex items-center justify-between gap-3 text-xs">
            <span @class([
                'font-medium',
                'text-red-600 dark:text-red-400' => $isOver,
                'text-gray-500 dark:text-gray-400' => ! $isOver,
            ])>
                @if ($isOver)
                    <x-ui.icon name="warning" weight="fill" size="xs" class="-mt-0.5 inline" /> Over limit
                @elseif ($isNumeric)
                    {{ $clampedPercent }}% used
                @endif
            </span>

            @if ($note)
                <span class="truncate text-gray-400 dark:text-gray-500">{{ $note }}</span>
            @endif
        </div>
    @endif
</div>