diff options
| -rw-r--r-- | frontend/src/components/Status.svelte | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/frontend/src/components/Status.svelte b/frontend/src/components/Status.svelte index ce2a753..7f06d95 100644 --- a/frontend/src/components/Status.svelte +++ b/frontend/src/components/Status.svelte @@ -1,5 +1,7 @@ <script lang="ts"> - import { Alert } from '$lib/components/ui/alert'; + import type { Snippet } from 'svelte'; + import { Alert, AlertTitle, AlertDescription } from '$lib/components/ui/alert'; + import { Skeleton } from '$lib/components/ui/skeleton'; import * as Card from '$lib/components/ui/card'; interface Props { @@ -8,25 +10,38 @@ busyText?: string; empty?: string | boolean | null; emptyHint?: string; + emptyCta?: Snippet; + errorCta?: Snippet; warnings?: string[]; + skeletonRows?: number; } - let { error, busy, busyText = '加载中…', empty, emptyHint, warnings }: Props = $props(); + let { error, busy, busyText = '加载中…', empty, emptyHint, emptyCta, errorCta, warnings, skeletonRows = 3 }: Props = $props(); </script> {#if busy} - <div class="text-muted-foreground flex items-center gap-2 py-3 text-sm" role="status"> - <span class="inline-block size-4 rounded-full border-2 border-primary border-t-transparent align-[-0.125em] animate-spin" aria-hidden="true"></span> - {busyText} + <div class="flex flex-col gap-1" data-testid="busy-skeleton" aria-label={busyText} role="status"> + {#each Array.from({ length: skeletonRows }) as _, i (i)} + <Skeleton class="h-10 w-full" /> + {/each} </div> {:else if error} - <Alert variant="destructive"> + <Alert variant="destructive" data-testid="load-error"> <span aria-hidden="true">⚠</span> - <span>{error}</span> + <AlertTitle>加载失败</AlertTitle> + <AlertDescription>{error ?? busyText}</AlertDescription> + {#if errorCta} + <div class="mt-2"> + {@render errorCta()} + </div> + {/if} </Alert> {:else if empty !== null && empty !== undefined && empty !== false} - <Card.Root class="border-dashed text-center py-8 px-4 text-muted-foreground"> - <p class="font-semibold mb-1">{empty}</p> - {#if emptyHint}<p class="text-sm text-muted-foreground">{emptyHint}</p>{/if} + <Card.Root class="border-dashed text-center py-10 px-6" data-testid="empty-state"> + <p class="text-lg font-semibold mb-1">{empty}</p> + {#if emptyHint} + <p class="text-xs text-muted-foreground mb-4">{emptyHint}</p> + {/if} + {#if emptyCta}{@render emptyCta()}{/if} </Card.Root> {/if} {#if warnings && warnings.length > 0} |
