Skip to main content

Layout primitives

Pipeline Card code

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

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

@props([
    'title',
    'branch' => null,
    'commit' => null,
    'meta' => null,
    'status' => null,
    'statusVariant' => 'brand',
    'steps' => [],
    'href' => null,
])

@php
    /*
    | Compact CI/CD pipeline card with branch metadata and vertical run steps.
    | Useful for deploy queues, build monitors and release dashboards.
    |
    | statusVariant: gray, brand, green, red, amber, blue
    | steps: array of [
    |     'label' => 'Build',
    |     'state' => 'complete',     // complete, running, pending, failed
    |     'duration' => '42s',       // optional
    |     'progress' => 78,          // optional, for running steps
    | ]
    |
    | Usage:
    |   <x-ui.pipeline-card
    |       title="Production deploy"
    |       branch="main"
    |       commit="fc4a19f"
    |       meta="Triggered 6m ago by deploy-bot"
    |       status="Deploying"
    |       :steps="[
    |           ['label' => 'Build', 'state' => 'complete', 'duration' => '42s'],
    |           ['label' => 'Deploy', 'state' => 'running', 'progress' => 78],
    |           ['label' => 'Smoke tests', 'state' => 'pending'],
    |       ]"
    |       href="/deployments/842"
    |   />
    */
    $stateStyles = [
        'complete' => 'bg-green-50 text-green-600 dark:bg-green-950/60 dark:text-green-400',
        'running' => 'bg-brand-50 text-brand-600 dark:bg-brand-950/60 dark:text-brand-400',
        'pending' => 'border border-gray-200 bg-white text-gray-300 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-600',
        'failed' => 'bg-red-50 text-red-600 dark:bg-red-950/60 dark:text-red-400',
    ];

    $stateIcons = [
        'complete' => 'check',
        'running' => 'circle-notch',
        'pending' => null,
        'failed' => 'x',
    ];
@endphp

<x-ui.card padding="sm" :href="$href" {{ $attributes }}>
    <div class="flex items-start justify-between gap-3">
        <div class="min-w-0">
            <h3 class="truncate text-sm font-semibold text-gray-900 dark:text-white">{{ $title }}</h3>

            @if ($branch || $commit)
                <p class="mt-1 flex min-w-0 items-center gap-1.5 font-mono text-[11px] text-gray-500 dark:text-gray-400">
                    @if ($branch)
                        <x-ui.icon name="git-branch" size="sm" class="shrink-0" />
                        <span class="truncate">{{ $branch }}</span>
                    @endif
                    @if ($branch && $commit)
                        <span class="text-gray-300 dark:text-gray-600">·</span>
                    @endif
                    @if ($commit)
                        <span class="truncate">{{ $commit }}</span>
                    @endif
                </p>
            @endif

            @if ($meta)
                <p class="mt-0.5 truncate text-xs text-gray-500 dark:text-gray-400">{{ $meta }}</p>
            @endif
        </div>

        @if ($status)
            <x-ui.badge :variant="$statusVariant" size="sm" class="shrink-0">{{ $status }}</x-ui.badge>
        @endif
    </div>

    @if (count($steps) > 0)
        <ol class="mt-4 min-w-0 space-y-2.5 border-t border-gray-100 pt-4 dark:border-gray-800">
            @foreach ($steps as $step)
                @php
                    $state = $step['state'] ?? 'pending';
                    $isRunning = $state === 'running';
                @endphp
                <li class="min-w-0 space-y-1.5">
                    <div class="flex items-center gap-2.5">
                        <span @class([
                            'flex h-4 w-4 shrink-0 items-center justify-center rounded-full',
                            $stateStyles[$state] ?? $stateStyles['pending'],
                        ])>
                            @if ($stateIcons[$state] ?? null)
                                <x-ui.icon
                                    :name="$stateIcons[$state]"
                                    weight="bold"
                                    size="xs"
                                    @class(['animate-spin' => $isRunning])
                                />
                            @endif
                        </span>

                        <span @class([
                            'min-w-0 flex-1 truncate text-xs',
                            $isRunning ? 'font-medium text-gray-900 dark:text-white' : 'text-gray-600 dark:text-gray-400',
                        ])>{{ $step['label'] }}</span>

                        @if ($isRunning && isset($step['progress']))
                            <span class="shrink-0 text-xs font-medium tabular-nums text-brand-600 dark:text-brand-400">{{ $step['progress'] }}%</span>
                        @elseif (filled($step['duration'] ?? null))
                            <span class="shrink-0 text-xs tabular-nums text-gray-400 dark:text-gray-500">{{ $step['duration'] }}</span>
                        @elseif ($state === 'pending')
                            <span class="shrink-0 text-xs text-gray-400 dark:text-gray-500">Pending</span>
                        @endif
                    </div>

                    @if ($isRunning && isset($step['progress']))
                        <div class="pl-6">
                            <x-ui.progress :value="$step['progress']" size="sm" />
                        </div>
                    @endif
                </li>
            @endforeach
        </ol>
    @endif

    {{ $slot }}
</x-ui.card>