55 lines
1.5 KiB
Svelte
55 lines
1.5 KiB
Svelte
<script lang="ts">
|
|
import type { Snippet } from 'svelte';
|
|
import Icon from '$lib/icons/Icon.svelte';
|
|
|
|
interface Props {
|
|
/** Icon-registry name shown above the title (omit for a text-only state). */
|
|
icon?: string;
|
|
/** Primary line. */
|
|
title?: string;
|
|
/** Secondary explanatory line. */
|
|
hint?: string;
|
|
/** Error styling (danger-coloured icon) + assertive `role="alert"`. */
|
|
error?: boolean;
|
|
/** Extra content (e.g. a call-to-action button) rendered below the hint. */
|
|
children?: Snippet;
|
|
}
|
|
|
|
let { icon, title, hint, error = false, children }: Props = $props();
|
|
</script>
|
|
|
|
<div class="empty-state" class:empty-state--error={error} role={error ? 'alert' : undefined}>
|
|
{#if icon}<Icon name={icon} class="empty-state__icon" />{/if}
|
|
{#if title}<p class="empty-state__title">{title}</p>{/if}
|
|
{#if hint}<p class="empty-state__hint">{hint}</p>{/if}
|
|
{@render children?.()}
|
|
</div>
|
|
|
|
<style>
|
|
/* Layout comes from the global `.empty-state` (styles/ported/content.css);
|
|
these refine the icon/title/hint elements consistently across views. */
|
|
.empty-state :global(.empty-state__icon) {
|
|
font-size: var(--text-5xl);
|
|
color: var(--color-text-faint);
|
|
margin-bottom: var(--space-2);
|
|
}
|
|
|
|
.empty-state--error :global(.empty-state__icon) {
|
|
color: var(--color-danger-text);
|
|
}
|
|
|
|
.empty-state__title {
|
|
margin: 0;
|
|
font-size: var(--text-lg);
|
|
font-weight: var(--weight-semibold);
|
|
color: var(--color-text-heading);
|
|
}
|
|
|
|
.empty-state__hint {
|
|
margin: 0;
|
|
max-width: 28rem;
|
|
font-size: var(--text-sm);
|
|
color: var(--color-text-muted);
|
|
}
|
|
</style>
|