Infrastructure
Forge Provider Picker code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/forge-provider-picker.blade.php
@props([
'providers' => [],
'name' => 'provider',
'selected' => null,
])
@php
/*
| Radio-card picker for Forge-style server providers. Each provider accepts:
| value, label, description, icon, connected, badge, meta, disabled.
|
| Usage:
| <x-ui.forge-provider-picker selected="laravel-vps" :providers="$providers" />
*/
$providers = collect($providers)->map(function (array $provider, int $index): array {
$value = (string) ($provider['value'] ?? $provider['label'] ?? "provider-{$index}");
return [
'value' => $value,
'label' => $provider['label'] ?? $value,
'description' => $provider['description'] ?? null,
'icon' => $provider['icon'] ?? 'cloud',
'connected' => (bool) ($provider['connected'] ?? false),
'badge' => $provider['badge'] ?? null,
'meta' => $provider['meta'] ?? null,
'disabled' => (bool) ($provider['disabled'] ?? false),
];
})->values();
@endphp
<fieldset {{ $attributes->merge(['class' => 'min-w-0']) }}>
<legend class="sr-only">Server provider</legend>
<div class="grid min-w-0 gap-3 sm:grid-cols-2 xl:grid-cols-3">
@foreach ($providers as $provider)
@php
$isSelected = (string) $selected === (string) $provider['value'];
$inputId = $name.'-'.substr(md5((string) $provider['value']), 0, 8);
@endphp
<label
for="{{ $inputId }}"
@class([
'group relative flex min-w-0 cursor-pointer flex-col gap-3 rounded-xl border bg-white p-4 transition dark:bg-gray-900',
'border-gray-200 hover:border-gray-300 dark:border-gray-800 dark:hover:border-gray-700 has-[:checked]:border-brand-500 has-[:checked]:ring-2 has-[:checked]:ring-brand-500/20 dark:has-[:checked]:border-brand-400' => ! $provider['disabled'],
'cursor-not-allowed opacity-60' => $provider['disabled'],
])
>
<input
id="{{ $inputId }}"
type="radio"
name="{{ $name }}"
value="{{ $provider['value'] }}"
class="sr-only"
@checked($isSelected)
@disabled($provider['disabled'])
>
<span class="flex min-w-0 flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<span class="flex min-w-0 items-center gap-3">
<span class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-300">
<x-ui.icon :name="$provider['icon']" weight="duotone" size="lg" />
</span>
<span class="min-w-0">
<span class="block truncate text-sm font-semibold text-gray-900 dark:text-white">{{ $provider['label'] }}</span>
@if ($provider['meta'])
<span class="mt-0.5 block truncate text-xs text-gray-500 dark:text-gray-400">{{ $provider['meta'] }}</span>
@endif
</span>
</span>
@if ($provider['badge'])
<x-ui.badge variant="outline" size="sm" class="w-fit sm:shrink-0">{{ $provider['badge'] }}</x-ui.badge>
@elseif ($provider['connected'])
<x-ui.badge variant="green" size="sm" dot class="w-fit sm:shrink-0">Connected</x-ui.badge>
@else
<x-ui.badge variant="gray" size="sm" class="w-fit sm:shrink-0">Setup</x-ui.badge>
@endif
</span>
@if ($provider['description'])
<span class="block text-sm leading-5 text-gray-600 dark:text-gray-400">{{ $provider['description'] }}</span>
@endif
</label>
@endforeach
</div>
</fieldset>