Skip to content
Brok UI

Loading…

No results

Gift Card

Open source

Gift-card purchase layouts — a live gradient card preview beside an amount/recipient/message form.

Preview

resources/views/blocks/gift-card-purchase.blade.php Blade
@props([
    'brand' => 'Northwind',
    'action' => '#',
    'amounts' => null,
    'selected' => 1,
])

@php
    // Preset amounts (numeric values). The Alpine state holds the selected index
    // and any custom amount; the card face and submit button reflect it live.
    $amounts ??= [25, 50, 100, 200];
    $selected = max(0, min((int) $selected, count($amounts) - 1));
@endphp

<section
    x-data="{
        amounts: @js(array_map('intval', $amounts)),
        selected: {{ $selected }},
        custom: '',
        get amount() {
            const c = parseFloat(this.custom);
            if (!Number.isNaN(c) && c > 0) return c;
            return this.amounts[this.selected] ?? 0;
        },
        get display() {
            return '$' + Number(this.amount).toLocaleString(undefined, { maximumFractionDigits: 2 });
        },
        pick(i) { this.selected = i; this.custom = ''; },
    }"
    {{ $attributes->merge(['class' => 'bg-background py-12 text-foreground sm:py-16']) }}
>
    <div class="mx-auto grid max-w-6xl grid-cols-1 items-start gap-10 px-4 lg:grid-cols-2 lg:gap-16">
        {{-- Gift-card face --}}
        <div class="flex flex-col gap-4">
            <div
                class="relative flex aspect-[16/10] flex-col justify-between overflow-hidden rounded-lg bg-gradient-to-br from-primary to-accent p-6 text-primary-foreground shadow-lg sm:p-8"
                role="img"
                :aria-label="@js(__($brand) . ' ' . __('Gift Card')) + ' — ' + display"
            >
                {{-- Decorative pattern --}}
                <svg class="pointer-events-none absolute inset-0 size-full opacity-10" viewBox="0 0 200 125" fill="none" stroke="currentColor" stroke-width="1" aria-hidden="true">
                    <circle cx="170" cy="20" r="60" />
                    <circle cx="170" cy="20" r="42" />
                    <circle cx="170" cy="20" r="24" />
                    <path d="M-10 110 L80 20 M10 120 L110 20 M30 125 L140 15" stroke-linecap="round" />
                </svg>

                <div class="relative flex items-center justify-between">
                    <span class="text-sm font-semibold uppercase tracking-widest">{{ __($brand) }}</span>
                    <svg class="size-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                        <rect x="3" y="8" width="18" height="13" rx="2" />
                        <path d="M3 11h18M12 8V21" />
                        <path d="M12 8s-3-5-5.5-3.5S8 8 12 8Zm0 0s3-5 5.5-3.5S16 8 12 8Z" />
                    </svg>
                </div>

                <div class="relative flex flex-col gap-2">
                    <span class="text-sm font-medium uppercase tracking-wide opacity-90">{{ __('Gift Card') }}</span>
                    <span class="text-5xl font-bold tracking-tight tabular-nums sm:text-6xl" x-text="display" aria-live="polite">{{ '$' . number_format((float) $amounts[$selected]) }}</span>
                </div>
            </div>

            <p class="text-pretty text-sm leading-relaxed text-muted-foreground">
                {{ __('Delivered by email with a personal message. Redeemable online and never expires.') }}
            </p>
        </div>

        {{-- Purchase form --}}
        <x-ui.card>
            <x-ui.card.header>
                <x-ui.card.title>{{ __('Buy a gift card') }}</x-ui.card.title>
                <x-ui.card.description>{{ __('Choose an amount and we will send it straight to their inbox.') }}</x-ui.card.description>
            </x-ui.card.header>

            <x-ui.card.content>
                <form method="POST" action="{{ $action }}" class="flex flex-col gap-6">
                    @csrf
                    <input type="hidden" name="amount" x-bind:value="amount" />

                    {{-- Amount chips --}}
                    <fieldset class="flex flex-col gap-2">
                        <legend class="mb-2 text-sm font-medium text-foreground">{{ __('Amount') }}</legend>
                        <div class="grid grid-cols-2 gap-2 sm:grid-cols-4" role="group" aria-label="{{ __('Gift card amount') }}">
                            @foreach ($amounts as $i => $amount)
                                <button
                                    type="button"
                                    @click="pick({{ $i }})"
                                    :class="(custom === '' && selected === {{ $i }}) ? 'bg-primary text-primary-foreground' : 'border-input text-foreground hover:bg-accent hover:text-accent-foreground'"
                                    :aria-pressed="(custom === '' && selected === {{ $i }}) ? 'true' : 'false'"
                                    class="flex h-11 items-center justify-center rounded-md border text-sm font-semibold tabular-nums transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                                >${{ number_format((float) $amount) }}</button>
                            @endforeach
                        </div>
                    </fieldset>

                    <x-ui.field>
                        <x-ui.label for="gift-custom">{{ __('Custom amount') }}</x-ui.label>
                        <x-ui.input
                            id="gift-custom"
                            type="number"
                            name="custom_amount"
                            min="1"
                            step="1"
                            inputmode="numeric"
                            x-model="custom"
                            placeholder="{{ __('Enter another amount') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-recipient" required>{{ __('Recipient email') }}</x-ui.label>
                        <x-ui.input
                            id="gift-recipient"
                            type="email"
                            name="recipient_email"
                            autocomplete="email"
                            required
                            placeholder="{{ __('them@example.com') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-sender">{{ __('Sender name') }}</x-ui.label>
                        <x-ui.input
                            id="gift-sender"
                            type="text"
                            name="sender_name"
                            autocomplete="name"
                            placeholder="{{ __('Your name') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-message">{{ __('Message') }}</x-ui.label>
                        <x-ui.textarea
                            id="gift-message"
                            name="message"
                            rows="3"
                            placeholder="{{ __('Add a personal note (optional)') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-delivery">{{ __('Delivery date') }}</x-ui.label>
                        <x-ui.input id="gift-delivery" type="date" name="delivery_date" autocomplete="off" />
                    </x-ui.field>

                    <x-ui.button type="submit" size="lg" class="w-full">
                        <x-slot:icon>
                            <svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                                <circle cx="9" cy="21" r="1" />
                                <circle cx="20" cy="21" r="1" />
                                <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" />
                            </svg>
                        </x-slot:icon>
                        <span>{{ __('Add to cart') }} — <span x-text="display">{{ '$' . number_format((float) $amounts[$selected]) }}</span></span>
                    </x-ui.button>
                </form>
            </x-ui.card.content>
        </x-ui.card>
    </div>
</section>

Installation

terminal
php artisan ui:add blocks/gift-card-purchase

Installs these dependencies automatically:

Registry contract

Install confidence

php artisan ui:add blocks/gift-card-purchase writes only the generated targets below. The CLI validates each file hash before writing and prompts before replacing local changes unless --force is used.

Version
1.0.3
License
open
Stability
stable
Contract
v1
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/blocks/gift-card-purchase.blade.php

Registry dependencies

card button input field label textarea

Package dependencies

composer: jml/brok:^0.2

Use with AI

A brief for your coding agent: what the block is, the install command, how to render it, its props and the rules. Copy it, or open a prompt about this block in an assistant.

gift-card-purchase.md
# Brok UI block: Gift Card (`gift-card-purchase`)

A two-column gift-card purchase section: a token-gradient gift-card face on the left that live-previews the chosen amount, and a card form on the right with amount chip buttons, a custom amount, recipient email, sender name, message, delivery date, and an add-to-cart button that reflects the selected amount.

Brok UI is a Laravel Blade registry. `ui:add` copies this block into the app as plain Blade the app owns; it composes installed `<brok:*>` primitives and semantic design tokens.

## Install

```bash
php artisan ui:add blocks/gift-card-purchase
```

## Render it

```blade
<x-blocks.gift-card-purchase />
```

## Props

- `brand` (string, default `Northwind`) — Brand name shown on the gift-card face and in its accessible label.
- `action` (string, default `#`) — Form action URL the purchase form posts to.
- `amounts` (mixed|null, default `null`) — Array of preset numeric amounts shown as chip buttons; defaults to [25, 50, 100, 200].
- `selected` (int, default `1`) — Index into amounts selected by default; clamped to a valid index.

## Use when

- Selling a gift card with preset amount chips, a custom amount field, and a live-updating card preview.
- Collecting recipient email, sender name, message, and delivery date alongside the purchase form.

## Avoid when

- Use gift-card-balance instead for checking an existing gift card's balance rather than purchasing one.

## Rules

- Render the installed block with `<x-blocks.gift-card-purchase />` and pass data through its props; edit the copied file only for structural changes.
- Keep the semantic design tokens (`bg-background`, `text-muted-foreground`); never swap in raw colour utilities.
- Keep the `data-slot` attributes and the logical (start/end) spacing so the markup still mirrors under `dir="rtl"`.

## Links

- Docs: https://brokui.dev/blocks/gift-card-purchase
- Registry JSON (files, props, contract): https://brokui.dev/r/open/blocks/gift-card-purchase.json

Working in Claude Code, Cursor or Codex? Give the agent the whole registry through the MCP server or the Brok UI skill.

Guidance

Use when

  • Selling a gift card with preset amount chips, a custom amount field, and a live-updating card preview.
  • Collecting recipient email, sender name, message, and delivery date alongside the purchase form.

Avoid when

  • Use gift-card-balance instead for checking an existing gift card's balance rather than purchasing one.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.
Anatomy
gift-card face amount chip group custom amount field recipient/sender fields add-to-cart button

Usage

Render the block as a component, passing data where useful:

resources/views/welcome.blade.php Blade
<x-blocks.gift-card-purchase />

Built from primitives

Composes <brok:*> Semantic tokens Re-themeable RTL-ready

This block composes installed <brok:*> primitives and semantic design tokens only — it does not reimplement any primitive. Re-theme it (light, dark, admin, customer) by editing CSS variables; flip the preview to RTL to confirm it mirrors.

Source

The exact, editable file ui:add writes into your app. The preview above renders this same source — there are no preview-only blocks.

resources/views/blocks/gift-card-purchase.blade.php Blade
@props([
    'brand' => 'Northwind',
    'action' => '#',
    'amounts' => null,
    'selected' => 1,
])

@php
    // Preset amounts (numeric values). The Alpine state holds the selected index
    // and any custom amount; the card face and submit button reflect it live.
    $amounts ??= [25, 50, 100, 200];
    $selected = max(0, min((int) $selected, count($amounts) - 1));
@endphp

<section
    x-data="{
        amounts: @js(array_map('intval', $amounts)),
        selected: {{ $selected }},
        custom: '',
        get amount() {
            const c = parseFloat(this.custom);
            if (!Number.isNaN(c) && c > 0) return c;
            return this.amounts[this.selected] ?? 0;
        },
        get display() {
            return '$' + Number(this.amount).toLocaleString(undefined, { maximumFractionDigits: 2 });
        },
        pick(i) { this.selected = i; this.custom = ''; },
    }"
    {{ $attributes->merge(['class' => 'bg-background py-12 text-foreground sm:py-16']) }}
>
    <div class="mx-auto grid max-w-6xl grid-cols-1 items-start gap-10 px-4 lg:grid-cols-2 lg:gap-16">
        {{-- Gift-card face --}}
        <div class="flex flex-col gap-4">
            <div
                class="relative flex aspect-[16/10] flex-col justify-between overflow-hidden rounded-lg bg-gradient-to-br from-primary to-accent p-6 text-primary-foreground shadow-lg sm:p-8"
                role="img"
                :aria-label="@js(__($brand) . ' ' . __('Gift Card')) + ' — ' + display"
            >
                {{-- Decorative pattern --}}
                <svg class="pointer-events-none absolute inset-0 size-full opacity-10" viewBox="0 0 200 125" fill="none" stroke="currentColor" stroke-width="1" aria-hidden="true">
                    <circle cx="170" cy="20" r="60" />
                    <circle cx="170" cy="20" r="42" />
                    <circle cx="170" cy="20" r="24" />
                    <path d="M-10 110 L80 20 M10 120 L110 20 M30 125 L140 15" stroke-linecap="round" />
                </svg>

                <div class="relative flex items-center justify-between">
                    <span class="text-sm font-semibold uppercase tracking-widest">{{ __($brand) }}</span>
                    <svg class="size-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                        <rect x="3" y="8" width="18" height="13" rx="2" />
                        <path d="M3 11h18M12 8V21" />
                        <path d="M12 8s-3-5-5.5-3.5S8 8 12 8Zm0 0s3-5 5.5-3.5S16 8 12 8Z" />
                    </svg>
                </div>

                <div class="relative flex flex-col gap-2">
                    <span class="text-sm font-medium uppercase tracking-wide opacity-90">{{ __('Gift Card') }}</span>
                    <span class="text-5xl font-bold tracking-tight tabular-nums sm:text-6xl" x-text="display" aria-live="polite">{{ '$' . number_format((float) $amounts[$selected]) }}</span>
                </div>
            </div>

            <p class="text-pretty text-sm leading-relaxed text-muted-foreground">
                {{ __('Delivered by email with a personal message. Redeemable online and never expires.') }}
            </p>
        </div>

        {{-- Purchase form --}}
        <x-ui.card>
            <x-ui.card.header>
                <x-ui.card.title>{{ __('Buy a gift card') }}</x-ui.card.title>
                <x-ui.card.description>{{ __('Choose an amount and we will send it straight to their inbox.') }}</x-ui.card.description>
            </x-ui.card.header>

            <x-ui.card.content>
                <form method="POST" action="{{ $action }}" class="flex flex-col gap-6">
                    @csrf
                    <input type="hidden" name="amount" x-bind:value="amount" />

                    {{-- Amount chips --}}
                    <fieldset class="flex flex-col gap-2">
                        <legend class="mb-2 text-sm font-medium text-foreground">{{ __('Amount') }}</legend>
                        <div class="grid grid-cols-2 gap-2 sm:grid-cols-4" role="group" aria-label="{{ __('Gift card amount') }}">
                            @foreach ($amounts as $i => $amount)
                                <button
                                    type="button"
                                    @click="pick({{ $i }})"
                                    :class="(custom === '' && selected === {{ $i }}) ? 'bg-primary text-primary-foreground' : 'border-input text-foreground hover:bg-accent hover:text-accent-foreground'"
                                    :aria-pressed="(custom === '' && selected === {{ $i }}) ? 'true' : 'false'"
                                    class="flex h-11 items-center justify-center rounded-md border text-sm font-semibold tabular-nums transition-colors focus:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                                >${{ number_format((float) $amount) }}</button>
                            @endforeach
                        </div>
                    </fieldset>

                    <x-ui.field>
                        <x-ui.label for="gift-custom">{{ __('Custom amount') }}</x-ui.label>
                        <x-ui.input
                            id="gift-custom"
                            type="number"
                            name="custom_amount"
                            min="1"
                            step="1"
                            inputmode="numeric"
                            x-model="custom"
                            placeholder="{{ __('Enter another amount') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-recipient" required>{{ __('Recipient email') }}</x-ui.label>
                        <x-ui.input
                            id="gift-recipient"
                            type="email"
                            name="recipient_email"
                            autocomplete="email"
                            required
                            placeholder="{{ __('them@example.com') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-sender">{{ __('Sender name') }}</x-ui.label>
                        <x-ui.input
                            id="gift-sender"
                            type="text"
                            name="sender_name"
                            autocomplete="name"
                            placeholder="{{ __('Your name') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-message">{{ __('Message') }}</x-ui.label>
                        <x-ui.textarea
                            id="gift-message"
                            name="message"
                            rows="3"
                            placeholder="{{ __('Add a personal note (optional)') }}"
                        />
                    </x-ui.field>

                    <x-ui.field>
                        <x-ui.label for="gift-delivery">{{ __('Delivery date') }}</x-ui.label>
                        <x-ui.input id="gift-delivery" type="date" name="delivery_date" autocomplete="off" />
                    </x-ui.field>

                    <x-ui.button type="submit" size="lg" class="w-full">
                        <x-slot:icon>
                            <svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
                                <circle cx="9" cy="21" r="1" />
                                <circle cx="20" cy="21" r="1" />
                                <path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" />
                            </svg>
                        </x-slot:icon>
                        <span>{{ __('Add to cart') }} — <span x-text="display">{{ '$' . number_format((float) $amounts[$selected]) }}</span></span>
                    </x-ui.button>
                </form>
            </x-ui.card.content>
        </x-ui.card>
    </div>
</section>

Ownership & lifecycle

Owner, release state, review evidence and adoption for this item.
Owner
Platform UI (@JoshJML)
Current version
1.0.3
Status
Stable
License
open
Deprecation
Not deprecated
Contract
v1
Foundation
≥ 1.0.0