Skip to main content

General

Uptime Bar code

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

resources/views/components/ui/uptime-bar.blade.php

@props([
    'days' => [],
    'size' => 'base',
])

@php
    /*
    | Uptime history strip — one slim bar per day, coloured by status. Powers the
    | classic status-page "90 day" view. Each entry may be a status string
    | (operational, degraded, partial, major, maintenance, none), a numeric
    | uptime percentage, or an array ['status' => ?, 'uptime' => ?, 'label' => ?].
    |
    | size: sm, base, lg
    |
    | Usage:
    |   <x-ui.uptime-bar :days="array_fill(0, 90, 'operational')" />
    |   <x-ui.uptime-bar :days="[99.99, 100, 96.2, 'major']" />
    */
    $colors = [
        'operational' => 'bg-green-500',
        'degraded' => 'bg-amber-400',
        'partial' => 'bg-amber-500',
        'major' => 'bg-red-500',
        'maintenance' => 'bg-accent-400',
        'none' => 'bg-gray-200 dark:bg-gray-700',
    ];

    $labels = [
        'operational' => 'Operational',
        'degraded' => 'Degraded',
        'partial' => 'Partial outage',
        'major' => 'Major outage',
        'maintenance' => 'Maintenance',
        'none' => 'No data',
    ];

    $heights = ['sm' => 'h-5', 'base' => 'h-8', 'lg' => 'h-10'];
    $height = $heights[$size] ?? $heights['base'];

    $fromUptime = function ($value): string {
        $value = (float) $value;

        return match (true) {
            $value >= 99.9 => 'operational',
            $value >= 99 => 'degraded',
            $value >= 95 => 'partial',
            default => 'major',
        };
    };

    $normalized = collect($days)->map(function ($day) use ($fromUptime): array {
        if (is_array($day)) {
            $status = $day['status'] ?? (isset($day['uptime']) ? $fromUptime($day['uptime']) : 'none');

            return ['status' => $status, 'label' => $day['label'] ?? null];
        }

        if (is_numeric($day)) {
            return ['status' => $fromUptime($day), 'label' => null];
        }

        return ['status' => (string) $day, 'label' => null];
    })->all();
@endphp

<div {{ $attributes->merge(['class' => 'flex w-full items-stretch gap-px overflow-hidden rounded']) }} role="img" aria-label="Uptime history">
    @foreach ($normalized as $day)
        @php
            $status = $day['status'];
            $color = $colors[$status] ?? $colors['none'];
            $statusLabel = $labels[$status] ?? ucfirst((string) $status);
            $title = $day['label'] ? $day['label'].' — '.$statusLabel : $statusLabel;
        @endphp
        <div class="group/day relative flex-1 {{ $height }} min-w-[2px] rounded-[1px] {{ $color }} transition hover:opacity-80" title="{{ $title }}">
            <span class="pointer-events-none absolute bottom-full left-1/2 z-10 mb-1.5 hidden -translate-x-1/2 whitespace-nowrap rounded-md bg-gray-900 px-2 py-1 text-xs font-medium text-white shadow-lg group-hover/day:block dark:bg-gray-700">{{ $title }}</span>
        </div>
    @endforeach
</div>