Skip to main content

Data display

Chart Card code

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

resources/views/components/ui/chart-card.blade.php

@props([
    'label',
    'value',
    'data' => [],
    'type' => 'line',
    'color' => null,
    'fill' => true,
    'height' => 56,
    'reveal' => false,
    'href' => null,
])

@php
    /*
    | KPI tile with an edge-to-edge sparkline — no outer padding on the chart area.
    |
    | label / value: headline metric copy
    | data, type, color, fill, height, reveal: passed through to <x-ui.sparkline>
    |
    | Usage:
    |   <x-ui.chart-card
    |       label="Sessions"
    |       value="18,402"
    |       :data="[3, 7, 4, 9, 6, 11, 8, 12]"
    |   />
    |
    |   <x-ui.chart-card.multi :metrics="[
    |       ['label' => 'Sessions', 'value' => '18,402', 'data' => [3, 7, 4, 9, 6, 11, 8, 12]],
    |       ['label' => 'Revenue', 'value' => '$48.2k', 'data' => [48, 52, 44, 58, 49], 'color' => '#16a34a'],
    |   ]" />
    */
    $classes = 'overflow-hidden rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm';
@endphp

@if ($href)
    <a href="{{ $href }}" {{ $attributes->merge(['class' => $classes.' block']) }}>
        <div class="px-6 pt-6 pb-4">
            <p class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ $label }}</p>
            <p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white tabular-nums">{{ $value }}</p>
        </div>

        <x-ui.sparkline
            :label="$label"
            :data="$data"
            :type="$type"
            :color="$color"
            :fill="$fill"
            :height="$height"
            :reveal="$reveal"
            class="block"
        />
    </a>
@else
    <div {{ $attributes->merge(['class' => $classes]) }}>
        <div class="px-6 pt-6 pb-4">
            <p class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ $label }}</p>
            <p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white tabular-nums">{{ $value }}</p>
        </div>

        <x-ui.sparkline
            :label="$label"
            :data="$data"
            :type="$type"
            :color="$color"
            :fill="$fill"
            :height="$height"
            :reveal="$reveal"
            class="block"
        />
    </div>
@endif

resources/views/components/ui/chart-card/multi.blade.php

@props([
    'metrics' => [],
    'height' => 120,
    'reveal' => false,
    'href' => null,
])

@php
    /*
    | Multi-metric chart card — two KPIs in one card, each with a two-line header
    | (label + value), and a single edge-to-edge chart with dual y-axes.
    |
    | metrics: array of [
    |     'label' => 'Sessions',
    |     'value' => '18,402',
    |     'data'  => [3, 7, 4, 9, 6, 11, 8, 12],
    |     'color' => '#16a34a', // optional
    |     'axis'  => 'left',     // left | right — defaults to left then right
    | ]
    |
    | Usage:
    |   <x-ui.chart-card.multi :metrics="[
    |       ['label' => 'Sessions', 'value' => '18,402', 'data' => [3, 7, 4, 9, 6, 11, 8, 12]],
    |       ['label' => 'Revenue', 'value' => '$48.2k', 'data' => [48, 52, 44, 58, 49], 'color' => '#16a34a'],
    |   ]" />
    */
    $count = count($metrics);
    $columns = match (true) {
        $count <= 1 => 'grid-cols-1',
        $count === 2 => 'grid-cols-1 sm:grid-cols-2',
        $count === 3 => 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
        default => 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
    };

        $series = collect($metrics)
        ->values()
        ->map(fn (array $metric, int $index) => [
            'label' => $metric['label'] ?? '',
            'data' => array_values($metric['data'] ?? []),
            'color' => $metric['color'] ?? null,
            'axis' => $metric['axis'] ?? ($index === 0 ? 'left' : 'right'),
            'fill' => $metric['fill'] ?? true,
        ])
        ->all();

    $classes = 'overflow-hidden rounded-2xl border border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shadow-sm';
@endphp

@if ($href)
    <a href="{{ $href }}" {{ $attributes->merge(['class' => $classes.' block']) }}>
        <div class="px-6 pt-6 pb-4">
            <div class="grid {{ $columns }} gap-6">
                @foreach ($metrics as $metric)
                    <div class="min-w-0">
                        <p class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ $metric['label'] }}</p>
                        <p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white tabular-nums">{{ $metric['value'] }}</p>
                    </div>
                @endforeach
            </div>
        </div>

        <x-ui.sparkline
            :series="$series"
            dual-axis
            :height="$height"
            :reveal="$reveal"
            class="block"
        />
    </a>
@else
    <div {{ $attributes->merge(['class' => $classes]) }}>
        <div class="px-6 pt-6 pb-4">
            <div class="grid {{ $columns }} gap-6">
                @foreach ($metrics as $metric)
                    <div class="min-w-0">
                        <p class="text-sm font-medium text-gray-500 dark:text-gray-400">{{ $metric['label'] }}</p>
                        <p class="mt-1 text-2xl font-semibold tracking-tight text-gray-900 dark:text-white tabular-nums">{{ $metric['value'] }}</p>
                    </div>
                @endforeach
            </div>
        </div>

        <x-ui.sparkline
            :series="$series"
            dual-axis
            :height="$height"
            :reveal="$reveal"
            class="block"
        />
    </div>
@endif