Skip to main content

General

Error Page code

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

resources/views/components/ui/error-page.blade.php

@props([
    'code' => null,
    'title' => null,
    'description' => null,
    'icon' => null,
    'tint' => null,
    'message' => null,
    'home' => true,
    'back' => true,
])

@php
    /*
    | HTTP error page body: status code, headline, supporting copy and recovery
    | actions. Presets cover the statuses shipped in resources/views/errors —
    | explicit props always win over the preset defaults.
    |
    | code: 403, 404, 419, 429, 500, 503, 4xx, 5xx
    |
    | Usage:
    |   <x-ui.error-page code="404" />
    |   <x-ui.error-page code="403" :message="$exception->getMessage()" />
    |   <x-ui.error-page code="500" :back="false">
    |       <x-slot:actions><x-ui.button href="/status">Status</x-ui.button></x-slot:actions>
    |   </x-ui.error-page>
    */
    $presets = [
        '403' => [
            'icon' => 'lock-key',
            'title' => 'Access denied',
            'description' => "You don't have permission to view this page. If you think that's a mistake, ask an admin to check your role.",
            'tint' => 'bg-amber-50 text-amber-500 dark:bg-amber-950/40 dark:text-amber-400',
        ],
        '404' => [
            'icon' => 'compass',
            'title' => 'Page not found',
            'description' => 'The page you were looking for has moved, been renamed, or never existed. Try the component library or head back home.',
            'tint' => 'bg-brand-50 text-brand-500 dark:bg-brand-950/40 dark:text-brand-400',
        ],
        '419' => [
            'icon' => 'hourglass',
            'title' => 'Your session expired',
            'description' => 'This page sat idle long enough that we cleared the form token. Reload the page and submit again.',
            'tint' => 'bg-accent-50 text-accent-500 dark:bg-accent-950/40 dark:text-accent-400',
        ],
        '429' => [
            'icon' => 'gauge',
            'title' => 'Too many requests',
            'description' => 'You have sent a lot of requests in a short window. Wait a moment before trying again.',
            'tint' => 'bg-amber-50 text-amber-500 dark:bg-amber-950/40 dark:text-amber-400',
        ],
        '500' => [
            'icon' => 'warning-octagon',
            'title' => 'Something went wrong',
            'description' => 'An unexpected error broke this request. It has been logged, so you can try again in a moment.',
            'tint' => 'bg-red-50 text-red-500 dark:bg-red-950/40 dark:text-red-400',
        ],
        '503' => [
            'icon' => 'wrench',
            'title' => 'Down for maintenance',
            'description' => 'We are shipping an update right now. This takes a few minutes, then everything comes back automatically.',
            'tint' => 'bg-amber-50 text-amber-500 dark:bg-amber-950/40 dark:text-amber-400',
        ],
        '4xx' => [
            'icon' => 'warning-circle',
            'title' => 'We could not handle that request',
            'description' => 'Something about this request was not right. Check the address and try again.',
            'tint' => 'bg-amber-50 text-amber-500 dark:bg-amber-950/40 dark:text-amber-400',
        ],
        '5xx' => [
            'icon' => 'warning-octagon',
            'title' => 'Server error',
            'description' => 'Our end failed on this request. It has been logged, so please try again shortly.',
            'tint' => 'bg-red-50 text-red-500 dark:bg-red-950/40 dark:text-red-400',
        ],
    ];

    $code = $code === null ? null : (string) $code;
    $config = $presets[$code] ?? [];

    $icon ??= $config['icon'] ?? 'warning-circle';
    $title ??= $config['title'] ?? 'Something went wrong';
    $description ??= $config['description'] ?? null;
    $tint ??= $config['tint'] ?? 'bg-gray-100 text-gray-400 dark:bg-gray-800 dark:text-gray-500';
    $message = is_string($message) && trim($message) !== '' ? trim($message) : null;
@endphp

<div x-data {{ $attributes->merge(['class' => 'flex flex-col items-center text-center']) }}>
    <span class="flex h-16 w-16 items-center justify-center rounded-2xl {{ $tint }}">
        <x-ui.icon :name="$icon" weight="duotone" size="4xl" />
    </span>

    @if ($code)
        <p class="mt-6 text-sm font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">
            {{ __('Error') }} {{ $code }}
        </p>
    @endif

    <h1 class="mt-3 text-3xl font-semibold tracking-tight text-gray-900 sm:text-4xl dark:text-white">{{ $title }}</h1>

    @if ($description)
        <p class="mt-4 max-w-xl text-base leading-7 text-gray-600 dark:text-gray-400">{{ $description }}</p>
    @endif

    @if ($message)
        <p class="mt-4 max-w-xl rounded-xl bg-white px-4 py-3 text-sm leading-6 text-gray-600 ring-1 ring-gray-200 dark:bg-gray-900 dark:text-gray-300 dark:ring-gray-800">
            {{ $message }}
        </p>
    @endif

    @if (isset($actions) || $home || $back)
        <div class="mt-8 flex flex-wrap items-center justify-center gap-3">
            @isset($actions)
                {{ $actions }}
            @else
                @if ($home)
                    <x-ui.button :href="route('home')" variant="primary" icon="house">{{ __('Back to home') }}</x-ui.button>
                @endif

                @if ($back)
                    <x-ui.button type="button" variant="secondary" icon="arrow-left" x-on:click="window.history.back()">{{ __('Go back') }}</x-ui.button>
                @endif
            @endisset
        </div>
    @endif

    @isset($footer)
        <div class="mt-10 w-full">{{ $footer }}</div>
    @endisset
</div>