Feedback & status
Upgrade Banner code
Copy the implementation or inspect every file that belongs to this component unit.
resources/views/components/ui/upgrade-banner.blade.php
@props([
'title' => null,
'description' => null,
'variant' => 'brand',
'icon' => null,
'cta' => 'Upgrade plan',
'href' => null,
'plan' => null,
'usageLabel' => null,
'used' => null,
'limit' => null,
'unit' => null,
'dismissible' => false,
'storageKey' => null,
])
@php
/*
| Contextual upgrade / plan-limit nudge card. Designed to surface when a
| usage-meter nears or hits a quota. Renders an icon medallion, a headline +
| description, an optional inline usage meter and a primary CTA. Use the
| `actions` slot to override the buttons. Distinct from the full-width
| announcement banner component.
|
| variant: brand (nudge), amber (approaching limit), red (limit reached)
|
| Usage:
| <x-ui.upgrade-banner
| variant="amber"
| title="You're approaching your API limit"
| description="You've used 92% of your monthly requests."
| :used="9200" :limit="10000" usage-label="API calls" unit="requests"
| cta="Upgrade to Pro" href="/billing" />
*/
$variants = [
'brand' => [
'wrap' => 'border-brand-200 bg-gradient-to-br from-brand-50 to-white dark:border-brand-900/60 dark:from-brand-950/50 dark:to-gray-900',
'medallion' => 'bg-brand-100 text-brand-600 dark:bg-brand-900/60 dark:text-brand-300',
'icon' => 'rocket-launch',
'button' => 'primary',
'meter' => 'brand',
],
'amber' => [
'wrap' => 'border-amber-200 bg-gradient-to-br from-amber-50 to-white dark:border-amber-900/60 dark:from-amber-950/40 dark:to-gray-900',
'medallion' => 'bg-amber-100 text-amber-600 dark:bg-amber-900/60 dark:text-amber-300',
'icon' => 'warning',
'button' => 'primary',
'meter' => 'amber',
],
'red' => [
'wrap' => 'border-red-200 bg-gradient-to-br from-red-50 to-white dark:border-red-900/60 dark:from-red-950/40 dark:to-gray-900',
'medallion' => 'bg-red-100 text-red-600 dark:bg-red-900/60 dark:text-red-300',
'icon' => 'warning-octagon',
'button' => 'danger',
'meter' => 'red',
],
];
$meta = $variants[$variant] ?? $variants['brand'];
$resolvedIcon = $icon ?? $meta['icon'];
$hasMeter = $used !== null && $limit !== null;
@endphp
<div
@if ($dismissible)
x-data="{
show: true,
init() {
@if ($storageKey)
if (localStorage.getItem('upgrade-banner:{{ $storageKey }}') === 'dismissed') { this.show = false; }
@endif
},
dismiss() {
this.show = false;
@if ($storageKey)
localStorage.setItem('upgrade-banner:{{ $storageKey }}', 'dismissed');
@endif
},
}"
x-show="show"
x-cloak
@endif
role="region"
aria-label="{{ $title ?? 'Upgrade' }}"
{{ $attributes->merge(['class' => 'relative overflow-hidden rounded-2xl border p-5 sm:p-6 '.$meta['wrap']]) }}
>
<div class="flex flex-col gap-4 sm:flex-row sm:items-start">
<span class="flex h-11 w-11 shrink-0 items-center justify-center rounded-xl {{ $meta['medallion'] }}">
<x-ui.icon :name="$resolvedIcon" weight="fill" size="lg" />
</span>
<div class="min-w-0 flex-1">
<div class="flex flex-wrap items-center gap-2">
@if ($title)
<h3 class="text-base font-semibold text-gray-900 dark:text-white">{{ $title }}</h3>
@endif
@if ($plan)
<x-ui.badge variant="gray" size="sm">{{ $plan }}</x-ui.badge>
@endif
</div>
@if ($description)
<p class="mt-1 text-sm text-gray-600 dark:text-gray-300">{{ $description }}</p>
@endif
@if (! $slot->isEmpty())
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">{{ $slot }}</div>
@endif
@if ($hasMeter)
<div class="mt-4">
<x-ui.usage-meter
:label="$usageLabel"
:used="$used"
:limit="$limit"
:unit="$unit"
:variant="$meta['meter']"
size="sm"
/>
</div>
@endif
<div class="mt-4 flex flex-wrap items-center gap-3">
@isset($actions)
{{ $actions }}
@else
<x-ui.button :variant="$meta['button']" size="sm" :href="$href" icon="lightning">{{ $cta }}</x-ui.button>
@endisset
</div>
</div>
</div>
@if ($dismissible)
<button
type="button"
@click="dismiss()"
class="absolute end-3 top-3 rounded-md p-1.5 text-gray-400 opacity-70 transition hover:bg-black/5 hover:opacity-100 dark:text-gray-500 dark:hover:bg-white/5"
aria-label="Dismiss"
>
<x-ui.icon name="x" weight="bold" size="sm" />
</button>
@endif
</div>