Files
nadir-webui/src/routes/+error.svelte
T

82 lines
2.7 KiB
Svelte
Raw Normal View History

<script lang="ts">
import ArrowLeftIcon from '@lucide/svelte/icons/arrow-left';
import HomeIcon from '@lucide/svelte/icons/home';
import LockIcon from '@lucide/svelte/icons/lock';
import RefreshCwIcon from '@lucide/svelte/icons/refresh-cw';
import SearchXIcon from '@lucide/svelte/icons/search-x';
import TriangleAlertIcon from '@lucide/svelte/icons/triangle-alert';
import { goto, invalidateAll } from '$app/navigation';
import { resolve } from '$app/paths';
import { page } from '$app/state';
import PageMeta from '$lib/components/seo/page-meta.svelte';
import { Button } from '$lib/components/ui/button';
import * as Empty from '$lib/components/ui/empty';
import { m } from '$lib/paraglide/messages';
const status = $derived(page.status);
const message = $derived(page.error?.message ?? '');
const kind = $derived(
status === 404 ? 'not_found' : status === 401 || status === 403 ? 'unauthorized' : 'generic'
);
const title = $derived(
kind === 'not_found'
? m.error_not_found_title()
: kind === 'unauthorized'
? m.error_unauthorized_title()
: m.error_generic_title()
);
const description = $derived(
kind === 'not_found'
? m.error_not_found_description()
: kind === 'unauthorized'
? m.error_unauthorized_description()
: m.error_generic_description()
);
const Icon = $derived(
kind === 'not_found' ? SearchXIcon : kind === 'unauthorized' ? LockIcon : TriangleAlertIcon
);
</script>
<PageMeta {title} {description} noIndex />
2026-06-25 23:11:32 +02:00
<div class="m-auto flex w-full max-w-2xl flex-col gap-4 p-6">
<Empty.Root class="border">
<Empty.Header>
<Empty.Media variant="icon" class="size-12">
<Icon class="size-6" />
</Empty.Media>
<Empty.Title>{title}</Empty.Title>
<Empty.Description>{description}</Empty.Description>
</Empty.Header>
<Empty.Content class="gap-3">
<div class="text-muted-foreground text-xs font-mono">
{m.error_code_label({ status })}
</div>
{#if message}
<details class="w-full max-w-lg text-left">
<summary class="text-muted-foreground cursor-pointer text-xs">
{m.error_details()}
</summary>
<pre
class="bg-muted text-foreground mt-2 max-h-64 overflow-auto rounded-md border p-3 text-xs whitespace-pre-wrap">{message}</pre>
</details>
{/if}
<div class="flex flex-wrap items-center justify-center gap-2">
<Button variant="outline" onclick={() => invalidateAll()}>
<RefreshCwIcon class="size-4" />
{m.error_action_retry()}
</Button>
<Button variant="outline" onclick={() => history.back()}>
<ArrowLeftIcon class="size-4" />
{m.error_action_back()}
</Button>
<Button onclick={() => goto(resolve('/'))}>
<HomeIcon class="size-4" />
{m.error_action_home()}
</Button>
</div>
</Empty.Content>
</Empty.Root>
</div>