Skip to content
Brok UI

Loading…

No results

Resource Pages

Open source

Authenticated resource workflows — searchable and selectable index, create, edit, and detail pages with activity history, plus the operator set: an alert-led index, a waiting-for work queue, a stepped record and one create/edit form with save blockers.

7 of 8

Preview

resources/views/pages/admin-record.blade.php Blade
{{--
    Admin Record — the record detail screen for working a list in sequence.

    Generalised from the Noord-C admin's `orders/show.blade.php`: an attention
    banner zone, a sticky record header (title, status, dirty state, action
    cluster), previous/next stepping so an operator never has to return to the
    list to reach the next record, a tabbed body, a side rail of related
    cards, and an activity timeline.

    Rule carried over from the source spec, and the reason `actions` has no
    per-action `disabled`: an action the viewer may not take is ABSENT, not
    rendered-and-disabled. The caller filters `actions` to what the viewer is
    eligible for before it ever reaches this page.

    Left out on purpose (domain logic the consumer supplies): money/VAT
    arithmetic, carrier/warehouse specifics, and any eligibility rule for
    which action or status transition applies to THIS record.
--}}
@props([
    'title' => '#1042',
    'subtitle' => 'Webshop, Mollie, Aug 22, 2026, ref PO-1042',
    'indexHref' => '#',
    'indexLabel' => 'Orders',
    'status' => 'processing',
    'statusOptions' => null,
    'dirty' => true,
    'navigation' => null,
    'alerts' => null,
    'actions' => null,
    'lines' => null,
    'totals' => null,
    'sideCards' => null,
    'activity' => null,
])

@php
    $statusOptions ??= [
        ['value' => 'awaiting_payment', 'label' => 'Awaiting payment', 'tone' => 'soft-warning'],
        ['value' => 'processing', 'label' => 'Processing', 'tone' => 'soft-info'],
        ['value' => 'shipped', 'label' => 'Shipped', 'tone' => 'soft-info'],
        ['value' => 'delivered', 'label' => 'Delivered', 'tone' => 'soft-success'],
        ['value' => 'on_hold', 'label' => 'On hold', 'tone' => 'soft-destructive'],
    ];

    $navigation ??= [
        'previous' => ['href' => '#', 'label' => '#1041'],
        'next' => ['href' => '#', 'label' => '#1043'],
        'position' => 'Record 12 of 128',
    ];

    $alerts ??= [
        [
            'tone' => 'warning',
            'title' => 'Payment not yet confirmed',
            'description' => 'The payment provider has not confirmed this order in 22 minutes. Fulfilment is on hold until it settles.',
        ],
    ];

    $actions ??= [
        'primary' => ['key' => 'ship', 'label' => 'Mark as shipped', 'kind' => 'submit', 'url' => '#'],
        'secondary' => [
            ['key' => 'invoice', 'label' => 'Send invoice', 'kind' => 'submit', 'url' => '#'],
            ['key' => 'packing-slip', 'label' => 'Print packing slip', 'kind' => 'link', 'url' => '#', 'newTab' => true],
        ],
        // No "Refund" here: this order has not been paid yet, so a refund is
        // not eligible — the action is absent, not disabled.
        'menu' => [
            ['key' => 'export-timeline', 'label' => 'Export timeline', 'kind' => 'link', 'url' => '#'],
            ['key' => 'cancel', 'label' => 'Cancel order', 'kind' => 'dialog'],
        ],
    ];

    $lines ??= [
        ['name' => 'Wireless keyboard — graphite', 'meta' => 'SKU KB-2201', 'quantity' => 1, 'total' => '€64.00'],
        ['name' => 'USB-C hub, 7-port', 'meta' => 'SKU HB-0087', 'quantity' => 2, 'total' => '€96.00'],
        ['name' => 'Desk mat, wool felt — charcoal', 'meta' => 'SKU DM-1140', 'quantity' => 1, 'total' => '€28.50'],
    ];

    $totals ??= [
        ['label' => 'Subtotal', 'value' => '€188.50'],
        ['label' => 'Shipping', 'value' => '€6.95'],
        ['label' => 'VAT (21%)', 'value' => '€41.02'],
        ['label' => 'Total', 'value' => '€236.47', 'emphasis' => true],
    ];

    $sideCards ??= [
        [
            'title' => 'Payment',
            'description' => 'Mollie, iDEAL',
            'rows' => [
                ['label' => 'Method', 'value' => 'iDEAL'],
                ['label' => 'Status', 'value' => 'Pending confirmation'],
                ['label' => 'Reference', 'value' => 'tr_8sK3n0qP2x'],
            ],
            'action' => ['label' => 'View in Mollie', 'href' => '#'],
        ],
        [
            'title' => 'Customer',
            'description' => 'Els Bakker',
            'rows' => [
                ['label' => 'Email', 'value' => 'els.bakker@example.com'],
                ['label' => 'Orders placed', 'value' => '7'],
                ['label' => 'Customer since', 'value' => 'Mar 2024'],
            ],
            'action' => ['label' => 'View customer', 'href' => '#'],
        ],
        [
            'title' => 'Fulfilment',
            'description' => 'PostNL, Standard',
            'rows' => [
                ['label' => 'Warehouse', 'value' => 'Utrecht DC'],
                ['label' => 'Promised by', 'value' => 'Aug 26, 2026'],
                ['label' => 'Address', 'value' => 'Kerkstraat 12, 3512 AA Utrecht'],
            ],
            'action' => null,
        ],
    ];

    $activity ??= [
        ['actor' => 'Maya Chen', 'initials' => 'MC', 'action' => 'changed the status to', 'target' => 'Processing', 'time' => '12 minutes ago', 'datetime' => now()->subMinutes(12)->toIso8601String()],
        ['actor' => 'System', 'initials' => '⚙', 'action' => 'received a payment webhook for', 'target' => 'tr_8sK3n0qP2x', 'time' => '22 minutes ago', 'datetime' => now()->subMinutes(22)->toIso8601String()],
        ['actor' => 'Noah Williams', 'initials' => 'NW', 'action' => 'added a note:', 'target' => 'Customer asked to combine with order #1039.', 'time' => 'Yesterday', 'datetime' => now()->subDay()->toIso8601String()],
        ['actor' => 'Els Bakker', 'initials' => 'EB', 'action' => 'placed this order', 'target' => '', 'time' => 'Aug 22, 2026', 'datetime' => '2026-08-22T09:14:00+02:00'],
    ];
@endphp

<main
    id="main-content"
    data-slot="admin-record-page"
    data-surface="admin"
    data-visual-contracts="VC-006"
    {{ $attributes->merge(['class' => 'min-h-screen bg-background text-foreground pb-16']) }}
>
    <div
        data-slot="admin-record-header"
        class="sticky top-0 z-20 border-b border-border bg-background px-4 py-4 sm:px-6"
    >
        <div class="flex flex-wrap items-center justify-between gap-4">
            <x-ui.breadcrumb>
                <x-ui.breadcrumb.list>
                    <x-ui.breadcrumb.item>
                        <x-ui.breadcrumb.link :href="$indexHref">{{ __($indexLabel) }}</x-ui.breadcrumb.link>
                    </x-ui.breadcrumb.item>
                    <x-ui.breadcrumb.separator />
                    <x-ui.breadcrumb.item>
                        <x-ui.breadcrumb.page>{{ __($title) }}</x-ui.breadcrumb.page>
                    </x-ui.breadcrumb.item>
                </x-ui.breadcrumb.list>
            </x-ui.breadcrumb>

            @if ($navigation)
                <nav class="flex shrink-0 items-center gap-2" aria-label="{{ __('Record navigation') }}">
                    @if (! empty($navigation['position']))
                        <span class="text-xs text-muted-foreground">{{ __($navigation['position']) }}</span>
                    @endif
                    <x-ui.button
                        variant="outline"
                        size="icon-sm"
                        :href="$navigation['previous']['href'] ?? null"
                        :disabled="empty($navigation['previous'])"
                        :icon-label="__('Previous record:record', ['record' => $navigation['previous']['label'] ?? ''])"
                    >
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 rtl:rotate-180" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg>
                    </x-ui.button>
                    <x-ui.button
                        variant="outline"
                        size="icon-sm"
                        :href="$navigation['next']['href'] ?? null"
                        :disabled="empty($navigation['next'])"
                        :icon-label="__('Next record: :record', ['record' => $navigation['next']['label'] ?? ''])"
                    >
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 rtl:rotate-180" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
                    </x-ui.button>
                </nav>
            @endif
        </div>

        <div class="mt-4 flex flex-wrap items-start justify-between gap-x-6 gap-y-4">
            <div class="min-w-0">
                <div class="flex flex-wrap items-center gap-x-2 gap-y-2">
                    <h1 class="text-xl font-semibold tracking-tight">{{ __($title) }}</h1>
                    <x-ui.status-select :value="$status" :options="$statusOptions" />
                    @if ($dirty)
                        <x-ui.badge variant="soft-warning">{{ __('Unsaved changes') }}</x-ui.badge>
                    @endif
                </div>
                <p class="mt-2 text-xs text-muted-foreground">{{ __($subtitle) }}</p>
            </div>

            <div class="flex shrink-0 flex-wrap items-center gap-2">
                @if ($dirty)
                    <x-ui.button variant="ghost" size="sm">{{ __('Discard') }}</x-ui.button>
                    <x-ui.button variant="secondary" size="sm">{{ __('Save changes') }}</x-ui.button>
                @endif

                @foreach ($actions['secondary'] ?? [] as $action)
                    <x-ui.button
                        variant="outline"
                        size="sm"
                        :type="($action['kind'] ?? 'link') === 'submit' ? 'submit' : 'button'"
                        :href="($action['kind'] ?? 'link') === 'link' ? ($action['url'] ?? '#') : null"
                        :target="($action['newTab'] ?? false) ? '_blank' : null"
                        :rel="($action['newTab'] ?? false) ? 'noopener noreferrer' : null"
                    >
                        {{ __($action['label'] ?? '') }}
                    </x-ui.button>
                @endforeach

                @if (! empty($actions['primary']))
                    <x-ui.button size="sm">{{ __($actions['primary']['label'] ?? '') }}</x-ui.button>
                @endif

                @if (! empty($actions['menu']))
                    <x-ui.dropdown :anchored="true">
                        <x-ui.dropdown.trigger
                            :aria-label="__('More actions for :record', ['record' => $title])"
                            class="inline-flex size-9 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                        >
                            <svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor" class="size-4">
                                <circle cx="3" cy="8" r="1.25" /><circle cx="8" cy="8" r="1.25" /><circle cx="13" cy="8" r="1.25" />
                            </svg>
                        </x-ui.dropdown.trigger>
                        <x-ui.dropdown.content align="end">
                            @foreach ($actions['menu'] as $action)
                                <x-ui.dropdown.item :href="($action['kind'] ?? 'link') === 'link' ? ($action['url'] ?? '#') : null">
                                    {{ __($action['label'] ?? '') }}
                                </x-ui.dropdown.item>
                            @endforeach
                        </x-ui.dropdown.content>
                    </x-ui.dropdown>
                @endif
            </div>
        </div>
    </div>

    <div class="mx-auto max-w-6xl px-4 py-6 sm:px-6">
        @if (! empty($alerts))
            <div class="mb-6 space-y-2" data-slot="admin-record-alerts">
                @foreach ($alerts as $alert)
                    <x-ui.alert :variant="$alert['tone'] ?? 'warning'">
                        <div class="text-sm font-semibold">{{ __($alert['title'] ?? '') }}</div>
                        @if (! empty($alert['description']))
                            <p class="mt-2 max-w-2xl text-xs leading-5 text-pretty opacity-90">{{ __($alert['description']) }}</p>
                        @endif
                    </x-ui.alert>
                @endforeach
            </div>
        @endif

        <div class="grid items-start gap-6 lg:grid-cols-[minmax(0,1fr)_20rem]">
            <div class="min-w-0">
                <x-ui.tabs default="details">
                    <x-ui.tabs.list aria-label="{{ __('Record sections') }}">
                        <x-ui.tabs.trigger value="details">{{ __('Details') }}</x-ui.tabs.trigger>
                        <x-ui.tabs.trigger value="activity">{{ __('Activity') }}</x-ui.tabs.trigger>
                    </x-ui.tabs.list>

                    <x-ui.tabs.content value="details">
                        <x-ui.card>
                            <x-ui.card.content class="p-0">
                                <x-ui.table>
                                    <x-ui.table.header>
                                        <x-ui.table.row>
                                            <x-ui.table.head>{{ __('Item') }}</x-ui.table.head>
                                            <x-ui.table.head class="text-end">{{ __('Qty') }}</x-ui.table.head>
                                            <x-ui.table.head class="text-end">{{ __('Total') }}</x-ui.table.head>
                                        </x-ui.table.row>
                                    </x-ui.table.header>
                                    <x-ui.table.body>
                                        @foreach ($lines as $line)
                                            <x-ui.table.row>
                                                <x-ui.table.cell>
                                                    <span class="block font-medium">{{ $line['name'] ?? '' }}</span>
                                                    @if (! empty($line['meta']))
                                                        <span class="block text-xs text-muted-foreground">{{ $line['meta'] }}</span>
                                                    @endif
                                                </x-ui.table.cell>
                                                <x-ui.table.cell class="text-end tabular-nums">{{ $line['quantity'] ?? '' }}</x-ui.table.cell>
                                                <x-ui.table.cell class="text-end font-medium tabular-nums">{{ $line['total'] ?? '' }}</x-ui.table.cell>
                                            </x-ui.table.row>
                                        @endforeach
                                    </x-ui.table.body>
                                </x-ui.table>

                                <x-ui.separator />

                                <dl class="space-y-2 p-4">
                                    @foreach ($totals as $total)
                                        <div class="flex items-center justify-between gap-4 text-sm">
                                            <dt @class(['text-muted-foreground', 'font-medium text-foreground' => $total['emphasis'] ?? false])>{{ __($total['label'] ?? '') }}</dt>
                                            <dd @class(['tabular-nums', 'font-semibold text-foreground' => $total['emphasis'] ?? false])>{{ $total['value'] ?? '' }}</dd>
                                        </div>
                                    @endforeach
                                </dl>
                            </x-ui.card.content>
                        </x-ui.card>
                    </x-ui.tabs.content>

                    <x-ui.tabs.content value="activity">
                        <x-ui.card>
                            <x-ui.card.content class="pt-6">
                                <x-ui.audit-log
                                    variant="plain"
                                    :grouped="false"
                                    :label="__('Record activity')"
                                    :empty-label="__('No activity has been recorded yet.')"
                                    :events="collect($activity)->map(fn (array $event): array => [
                                        'actor' => ['name' => $event['actor'] ?? '', 'initials' => $event['initials'] ?? ''],
                                        'action' => __($event['action'] ?? ''),
                                        'subject' => $event['target'] ?? '',
                                        'at' => $event['datetime'] ?? null,
                                    ])->all()"
                                />
                            </x-ui.card.content>
                        </x-ui.card>
                    </x-ui.tabs.content>
                </x-ui.tabs>
            </div>

            <aside class="space-y-6" data-slot="admin-record-side-rail">
                @foreach ($sideCards as $card)
                    <x-ui.card>
                        <x-ui.card.header>
                            <x-ui.card.title>{{ __($card['title'] ?? '') }}</x-ui.card.title>
                            @if (! empty($card['description']))
                                <x-ui.card.description>{{ __($card['description']) }}</x-ui.card.description>
                            @endif
                        </x-ui.card.header>
                        <x-ui.card.content>
                            <dl class="space-y-2">
                                @foreach ($card['rows'] ?? [] as $row)
                                    <div class="flex items-start justify-between gap-4 text-sm">
                                        <dt class="shrink-0 text-muted-foreground">{{ __($row['label'] ?? '') }}</dt>
                                        <dd class="min-w-0 text-end break-words text-foreground">{{ $row['value'] ?? '' }}</dd>
                                    </div>
                                @endforeach
                            </dl>
                        </x-ui.card.content>
                        @if (! empty($card['action']))
                            <x-ui.card.footer>
                                <x-ui.button variant="ghost" size="sm" :href="$card['action']['href'] ?? '#'">
                                    {{ __($card['action']['label'] ?? '') }}
                                </x-ui.button>
                            </x-ui.card.footer>
                        @endif
                    </x-ui.card>
                @endforeach
            </aside>
        </div>
    </div>
</main>

Installation

terminal
php artisan ui:add pages/admin-record

Registry contract

Install confidence

php artisan ui:add pages/admin-record 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
v4
Foundation
≥ 1.0.0
Type Generated target
blade resources/views/pages/admin-record.blade.php

Registry dependencies

breadcrumb badge button card separator avatar tabs status-select alert dropdown table audit-log

Package dependencies

composer: jml/brok:^0.2

Use with AI

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

admin-record.md
# Brok UI page: Admin Record (`admin-record`)

A record detail screen for working a list in sequence: an attention banner zone, a sticky record header with status, dirty state, and an action cluster of only the actions the viewer may take, previous/next stepping, a tabbed body, a side rail of related cards, and an activity timeline.

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

## Install

```bash
php artisan ui:add pages/admin-record
```

## Render it

```blade
<x-pages.admin-record />
```

## Props

- `title` (string, default `#1042`) — Record identifier and page heading.
- `subtitle` (string, default `Webshop, Mollie, Aug 22, 2026, ref PO-1042`) — One-line identity summary under the title.
- `index-href` (string, default `#`) — Breadcrumb destination back to the index.
- `index-label` (string, default `Orders`) — Breadcrumb label for the index.
- `status` (string, default `processing`) — Current status value, matched against statusOptions.
- `status-options` (array|null, default `null`) — Status vocabulary for <x-ui.status-select>: ['value','label','tone'].
- `dirty` (bool, default `true`) — Whether the record has local unsaved changes. Renders a badge and save/discard actions in the header when true.
- `navigation` (array|null, default `null`) — ['previous' => ['href','label']|null, 'next' => ['href','label']|null, 'position' => 'Record 12 of 128']. A missing side renders its stepper button disabled, never absent, matching ordinary pagination.
- `alerts` (array|null, default `null`) — Attention-banner entries: each is ['tone','title','description','actionLabel','actionHref']. Most severe first.
- `actions` (array|null, default `null`) — ['primary' => action|null, 'secondary' => [action], 'menu' => [action]]. Only actions the viewer may take are present — an ineligible action is absent, never rendered disabled.
- `lines` (array|null, default `null`) — Line items for the Details tab: each is ['name','meta','quantity','total'].
- `totals` (array|null, default `null`) — Totals rows under the line items: each is ['label','value','emphasis' => bool].
- `side-cards` (array|null, default `null`) — Related-content cards for the side rail: each is ['title','description','rows' => [['label','value']],'action' => ['label','href']|null].
- `activity` (array|null, default `null`) — Chronological actor, action, target, time, datetime, and initials entries for the Activity tab.

## Use when

- Building the show route for a record an operator opens from a worked list and needs to step through in sequence.
- The record has more state than a plain metadata list: a status that changes, actions gated by permission or workflow state, and a history worth showing as a timeline.

## Avoid when

- The record has no workflow actions and no activity history — use the simpler pages/resource-page-detail instead.
- There is no list to step through — drop the previous/next stepper rather than rendering it with both sides empty.

## Rules

- Render the installed page with `<x-pages.admin-record />` 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/pages/admin-record
- Registry JSON (files, props, contract): https://brokui.dev/r/open/pages/admin-record.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

  • Building the show route for a record an operator opens from a worked list and needs to step through in sequence.
  • The record has more state than a plain metadata list: a status that changes, actions gated by permission or workflow state, and a history worth showing as a timeline.

Avoid when

  • The record has no workflow actions and no activity history — use the simpler pages/resource-page-detail instead.
  • There is no list to step through — drop the previous/next stepper rather than rendering it with both sides empty.

Anti-patterns

  • Do not replace semantic props with conflicting utility classes.
  • Do not remove labels, focus styles, or state attributes.
Anatomy
attention banner zone sticky record header (title, status, dirty state, action cluster) previous/next record stepper tabbed body side rail of related cards activity timeline
Theming hooks
Pins the pattern to the admin surface and uses semantic design tokens throughout.

Usage

Render the page as a component, or wire it to a route. Pass data where useful:

resources/views/welcome.blade.php Blade
<x-pages.admin-record />

Built from blocks & primitives

This page 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 pages.

resources/views/pages/admin-record.blade.php Blade
{{--
    Admin Record — the record detail screen for working a list in sequence.

    Generalised from the Noord-C admin's `orders/show.blade.php`: an attention
    banner zone, a sticky record header (title, status, dirty state, action
    cluster), previous/next stepping so an operator never has to return to the
    list to reach the next record, a tabbed body, a side rail of related
    cards, and an activity timeline.

    Rule carried over from the source spec, and the reason `actions` has no
    per-action `disabled`: an action the viewer may not take is ABSENT, not
    rendered-and-disabled. The caller filters `actions` to what the viewer is
    eligible for before it ever reaches this page.

    Left out on purpose (domain logic the consumer supplies): money/VAT
    arithmetic, carrier/warehouse specifics, and any eligibility rule for
    which action or status transition applies to THIS record.
--}}
@props([
    'title' => '#1042',
    'subtitle' => 'Webshop, Mollie, Aug 22, 2026, ref PO-1042',
    'indexHref' => '#',
    'indexLabel' => 'Orders',
    'status' => 'processing',
    'statusOptions' => null,
    'dirty' => true,
    'navigation' => null,
    'alerts' => null,
    'actions' => null,
    'lines' => null,
    'totals' => null,
    'sideCards' => null,
    'activity' => null,
])

@php
    $statusOptions ??= [
        ['value' => 'awaiting_payment', 'label' => 'Awaiting payment', 'tone' => 'soft-warning'],
        ['value' => 'processing', 'label' => 'Processing', 'tone' => 'soft-info'],
        ['value' => 'shipped', 'label' => 'Shipped', 'tone' => 'soft-info'],
        ['value' => 'delivered', 'label' => 'Delivered', 'tone' => 'soft-success'],
        ['value' => 'on_hold', 'label' => 'On hold', 'tone' => 'soft-destructive'],
    ];

    $navigation ??= [
        'previous' => ['href' => '#', 'label' => '#1041'],
        'next' => ['href' => '#', 'label' => '#1043'],
        'position' => 'Record 12 of 128',
    ];

    $alerts ??= [
        [
            'tone' => 'warning',
            'title' => 'Payment not yet confirmed',
            'description' => 'The payment provider has not confirmed this order in 22 minutes. Fulfilment is on hold until it settles.',
        ],
    ];

    $actions ??= [
        'primary' => ['key' => 'ship', 'label' => 'Mark as shipped', 'kind' => 'submit', 'url' => '#'],
        'secondary' => [
            ['key' => 'invoice', 'label' => 'Send invoice', 'kind' => 'submit', 'url' => '#'],
            ['key' => 'packing-slip', 'label' => 'Print packing slip', 'kind' => 'link', 'url' => '#', 'newTab' => true],
        ],
        // No "Refund" here: this order has not been paid yet, so a refund is
        // not eligible — the action is absent, not disabled.
        'menu' => [
            ['key' => 'export-timeline', 'label' => 'Export timeline', 'kind' => 'link', 'url' => '#'],
            ['key' => 'cancel', 'label' => 'Cancel order', 'kind' => 'dialog'],
        ],
    ];

    $lines ??= [
        ['name' => 'Wireless keyboard — graphite', 'meta' => 'SKU KB-2201', 'quantity' => 1, 'total' => '€64.00'],
        ['name' => 'USB-C hub, 7-port', 'meta' => 'SKU HB-0087', 'quantity' => 2, 'total' => '€96.00'],
        ['name' => 'Desk mat, wool felt — charcoal', 'meta' => 'SKU DM-1140', 'quantity' => 1, 'total' => '€28.50'],
    ];

    $totals ??= [
        ['label' => 'Subtotal', 'value' => '€188.50'],
        ['label' => 'Shipping', 'value' => '€6.95'],
        ['label' => 'VAT (21%)', 'value' => '€41.02'],
        ['label' => 'Total', 'value' => '€236.47', 'emphasis' => true],
    ];

    $sideCards ??= [
        [
            'title' => 'Payment',
            'description' => 'Mollie, iDEAL',
            'rows' => [
                ['label' => 'Method', 'value' => 'iDEAL'],
                ['label' => 'Status', 'value' => 'Pending confirmation'],
                ['label' => 'Reference', 'value' => 'tr_8sK3n0qP2x'],
            ],
            'action' => ['label' => 'View in Mollie', 'href' => '#'],
        ],
        [
            'title' => 'Customer',
            'description' => 'Els Bakker',
            'rows' => [
                ['label' => 'Email', 'value' => 'els.bakker@example.com'],
                ['label' => 'Orders placed', 'value' => '7'],
                ['label' => 'Customer since', 'value' => 'Mar 2024'],
            ],
            'action' => ['label' => 'View customer', 'href' => '#'],
        ],
        [
            'title' => 'Fulfilment',
            'description' => 'PostNL, Standard',
            'rows' => [
                ['label' => 'Warehouse', 'value' => 'Utrecht DC'],
                ['label' => 'Promised by', 'value' => 'Aug 26, 2026'],
                ['label' => 'Address', 'value' => 'Kerkstraat 12, 3512 AA Utrecht'],
            ],
            'action' => null,
        ],
    ];

    $activity ??= [
        ['actor' => 'Maya Chen', 'initials' => 'MC', 'action' => 'changed the status to', 'target' => 'Processing', 'time' => '12 minutes ago', 'datetime' => now()->subMinutes(12)->toIso8601String()],
        ['actor' => 'System', 'initials' => '⚙', 'action' => 'received a payment webhook for', 'target' => 'tr_8sK3n0qP2x', 'time' => '22 minutes ago', 'datetime' => now()->subMinutes(22)->toIso8601String()],
        ['actor' => 'Noah Williams', 'initials' => 'NW', 'action' => 'added a note:', 'target' => 'Customer asked to combine with order #1039.', 'time' => 'Yesterday', 'datetime' => now()->subDay()->toIso8601String()],
        ['actor' => 'Els Bakker', 'initials' => 'EB', 'action' => 'placed this order', 'target' => '', 'time' => 'Aug 22, 2026', 'datetime' => '2026-08-22T09:14:00+02:00'],
    ];
@endphp

<main
    id="main-content"
    data-slot="admin-record-page"
    data-surface="admin"
    data-visual-contracts="VC-006"
    {{ $attributes->merge(['class' => 'min-h-screen bg-background text-foreground pb-16']) }}
>
    <div
        data-slot="admin-record-header"
        class="sticky top-0 z-20 border-b border-border bg-background px-4 py-4 sm:px-6"
    >
        <div class="flex flex-wrap items-center justify-between gap-4">
            <x-ui.breadcrumb>
                <x-ui.breadcrumb.list>
                    <x-ui.breadcrumb.item>
                        <x-ui.breadcrumb.link :href="$indexHref">{{ __($indexLabel) }}</x-ui.breadcrumb.link>
                    </x-ui.breadcrumb.item>
                    <x-ui.breadcrumb.separator />
                    <x-ui.breadcrumb.item>
                        <x-ui.breadcrumb.page>{{ __($title) }}</x-ui.breadcrumb.page>
                    </x-ui.breadcrumb.item>
                </x-ui.breadcrumb.list>
            </x-ui.breadcrumb>

            @if ($navigation)
                <nav class="flex shrink-0 items-center gap-2" aria-label="{{ __('Record navigation') }}">
                    @if (! empty($navigation['position']))
                        <span class="text-xs text-muted-foreground">{{ __($navigation['position']) }}</span>
                    @endif
                    <x-ui.button
                        variant="outline"
                        size="icon-sm"
                        :href="$navigation['previous']['href'] ?? null"
                        :disabled="empty($navigation['previous'])"
                        :icon-label="__('Previous record:record', ['record' => $navigation['previous']['label'] ?? ''])"
                    >
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 rtl:rotate-180" aria-hidden="true"><path d="m15 18-6-6 6-6" /></svg>
                    </x-ui.button>
                    <x-ui.button
                        variant="outline"
                        size="icon-sm"
                        :href="$navigation['next']['href'] ?? null"
                        :disabled="empty($navigation['next'])"
                        :icon-label="__('Next record: :record', ['record' => $navigation['next']['label'] ?? ''])"
                    >
                        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-4 rtl:rotate-180" aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg>
                    </x-ui.button>
                </nav>
            @endif
        </div>

        <div class="mt-4 flex flex-wrap items-start justify-between gap-x-6 gap-y-4">
            <div class="min-w-0">
                <div class="flex flex-wrap items-center gap-x-2 gap-y-2">
                    <h1 class="text-xl font-semibold tracking-tight">{{ __($title) }}</h1>
                    <x-ui.status-select :value="$status" :options="$statusOptions" />
                    @if ($dirty)
                        <x-ui.badge variant="soft-warning">{{ __('Unsaved changes') }}</x-ui.badge>
                    @endif
                </div>
                <p class="mt-2 text-xs text-muted-foreground">{{ __($subtitle) }}</p>
            </div>

            <div class="flex shrink-0 flex-wrap items-center gap-2">
                @if ($dirty)
                    <x-ui.button variant="ghost" size="sm">{{ __('Discard') }}</x-ui.button>
                    <x-ui.button variant="secondary" size="sm">{{ __('Save changes') }}</x-ui.button>
                @endif

                @foreach ($actions['secondary'] ?? [] as $action)
                    <x-ui.button
                        variant="outline"
                        size="sm"
                        :type="($action['kind'] ?? 'link') === 'submit' ? 'submit' : 'button'"
                        :href="($action['kind'] ?? 'link') === 'link' ? ($action['url'] ?? '#') : null"
                        :target="($action['newTab'] ?? false) ? '_blank' : null"
                        :rel="($action['newTab'] ?? false) ? 'noopener noreferrer' : null"
                    >
                        {{ __($action['label'] ?? '') }}
                    </x-ui.button>
                @endforeach

                @if (! empty($actions['primary']))
                    <x-ui.button size="sm">{{ __($actions['primary']['label'] ?? '') }}</x-ui.button>
                @endif

                @if (! empty($actions['menu']))
                    <x-ui.dropdown :anchored="true">
                        <x-ui.dropdown.trigger
                            :aria-label="__('More actions for :record', ['record' => $title])"
                            class="inline-flex size-9 items-center justify-center rounded-md border border-border text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                        >
                            <svg aria-hidden="true" viewBox="0 0 16 16" fill="currentColor" class="size-4">
                                <circle cx="3" cy="8" r="1.25" /><circle cx="8" cy="8" r="1.25" /><circle cx="13" cy="8" r="1.25" />
                            </svg>
                        </x-ui.dropdown.trigger>
                        <x-ui.dropdown.content align="end">
                            @foreach ($actions['menu'] as $action)
                                <x-ui.dropdown.item :href="($action['kind'] ?? 'link') === 'link' ? ($action['url'] ?? '#') : null">
                                    {{ __($action['label'] ?? '') }}
                                </x-ui.dropdown.item>
                            @endforeach
                        </x-ui.dropdown.content>
                    </x-ui.dropdown>
                @endif
            </div>
        </div>
    </div>

    <div class="mx-auto max-w-6xl px-4 py-6 sm:px-6">
        @if (! empty($alerts))
            <div class="mb-6 space-y-2" data-slot="admin-record-alerts">
                @foreach ($alerts as $alert)
                    <x-ui.alert :variant="$alert['tone'] ?? 'warning'">
                        <div class="text-sm font-semibold">{{ __($alert['title'] ?? '') }}</div>
                        @if (! empty($alert['description']))
                            <p class="mt-2 max-w-2xl text-xs leading-5 text-pretty opacity-90">{{ __($alert['description']) }}</p>
                        @endif
                    </x-ui.alert>
                @endforeach
            </div>
        @endif

        <div class="grid items-start gap-6 lg:grid-cols-[minmax(0,1fr)_20rem]">
            <div class="min-w-0">
                <x-ui.tabs default="details">
                    <x-ui.tabs.list aria-label="{{ __('Record sections') }}">
                        <x-ui.tabs.trigger value="details">{{ __('Details') }}</x-ui.tabs.trigger>
                        <x-ui.tabs.trigger value="activity">{{ __('Activity') }}</x-ui.tabs.trigger>
                    </x-ui.tabs.list>

                    <x-ui.tabs.content value="details">
                        <x-ui.card>
                            <x-ui.card.content class="p-0">
                                <x-ui.table>
                                    <x-ui.table.header>
                                        <x-ui.table.row>
                                            <x-ui.table.head>{{ __('Item') }}</x-ui.table.head>
                                            <x-ui.table.head class="text-end">{{ __('Qty') }}</x-ui.table.head>
                                            <x-ui.table.head class="text-end">{{ __('Total') }}</x-ui.table.head>
                                        </x-ui.table.row>
                                    </x-ui.table.header>
                                    <x-ui.table.body>
                                        @foreach ($lines as $line)
                                            <x-ui.table.row>
                                                <x-ui.table.cell>
                                                    <span class="block font-medium">{{ $line['name'] ?? '' }}</span>
                                                    @if (! empty($line['meta']))
                                                        <span class="block text-xs text-muted-foreground">{{ $line['meta'] }}</span>
                                                    @endif
                                                </x-ui.table.cell>
                                                <x-ui.table.cell class="text-end tabular-nums">{{ $line['quantity'] ?? '' }}</x-ui.table.cell>
                                                <x-ui.table.cell class="text-end font-medium tabular-nums">{{ $line['total'] ?? '' }}</x-ui.table.cell>
                                            </x-ui.table.row>
                                        @endforeach
                                    </x-ui.table.body>
                                </x-ui.table>

                                <x-ui.separator />

                                <dl class="space-y-2 p-4">
                                    @foreach ($totals as $total)
                                        <div class="flex items-center justify-between gap-4 text-sm">
                                            <dt @class(['text-muted-foreground', 'font-medium text-foreground' => $total['emphasis'] ?? false])>{{ __($total['label'] ?? '') }}</dt>
                                            <dd @class(['tabular-nums', 'font-semibold text-foreground' => $total['emphasis'] ?? false])>{{ $total['value'] ?? '' }}</dd>
                                        </div>
                                    @endforeach
                                </dl>
                            </x-ui.card.content>
                        </x-ui.card>
                    </x-ui.tabs.content>

                    <x-ui.tabs.content value="activity">
                        <x-ui.card>
                            <x-ui.card.content class="pt-6">
                                <x-ui.audit-log
                                    variant="plain"
                                    :grouped="false"
                                    :label="__('Record activity')"
                                    :empty-label="__('No activity has been recorded yet.')"
                                    :events="collect($activity)->map(fn (array $event): array => [
                                        'actor' => ['name' => $event['actor'] ?? '', 'initials' => $event['initials'] ?? ''],
                                        'action' => __($event['action'] ?? ''),
                                        'subject' => $event['target'] ?? '',
                                        'at' => $event['datetime'] ?? null,
                                    ])->all()"
                                />
                            </x-ui.card.content>
                        </x-ui.card>
                    </x-ui.tabs.content>
                </x-ui.tabs>
            </div>

            <aside class="space-y-6" data-slot="admin-record-side-rail">
                @foreach ($sideCards as $card)
                    <x-ui.card>
                        <x-ui.card.header>
                            <x-ui.card.title>{{ __($card['title'] ?? '') }}</x-ui.card.title>
                            @if (! empty($card['description']))
                                <x-ui.card.description>{{ __($card['description']) }}</x-ui.card.description>
                            @endif
                        </x-ui.card.header>
                        <x-ui.card.content>
                            <dl class="space-y-2">
                                @foreach ($card['rows'] ?? [] as $row)
                                    <div class="flex items-start justify-between gap-4 text-sm">
                                        <dt class="shrink-0 text-muted-foreground">{{ __($row['label'] ?? '') }}</dt>
                                        <dd class="min-w-0 text-end break-words text-foreground">{{ $row['value'] ?? '' }}</dd>
                                    </div>
                                @endforeach
                            </dl>
                        </x-ui.card.content>
                        @if (! empty($card['action']))
                            <x-ui.card.footer>
                                <x-ui.button variant="ghost" size="sm" :href="$card['action']['href'] ?? '#'">
                                    {{ __($card['action']['label'] ?? '') }}
                                </x-ui.button>
                            </x-ui.card.footer>
                        @endif
                    </x-ui.card>
                @endforeach
            </aside>
        </div>
    </div>
</main>

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
v4
Foundation
≥ 1.0.0