summaryrefslogtreecommitdiff
path: root/frontend/src/components/Status.svelte
blob: 6ae2cfb7b46143ba465d24c32a304349f1da9571 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<script lang="ts">
  interface Props {
    error?: string | null;
    busy?: boolean;
    busyText?: string;
    empty?: string | boolean | null;
    emptyHint?: string;
    warnings?: string[];
  }
  let { error, busy, busyText = '加载中…', empty, emptyHint, warnings }: Props = $props();
</script>

{#if busy}
  <div class="status" role="status">
    <span class="spinner" aria-hidden="true"></span>
    {busyText}
  </div>
{:else if error}
  <Alert variant="destructive" class="bg-[var(--danger-soft)] text-[var(--destructive)] border-[#f2c7c7]">
    <span aria-hidden="true">⚠</span>
    <span>{error}</span>
  </Alert>
{:else if empty !== null && empty !== undefined && empty !== false}
  <div class="state-empty">
    <p class="empty-title">{empty}</p>
    {#if emptyHint}<p class="hint">{emptyHint}</p>{/if}
  </div>
{/if}
{#if warnings && warnings.length > 0}
  <div class="stack">
    {#each warnings as w, i (i)}
      <Alert variant="default" class="bg-[var(--warn-soft)] text-[var(--warn)] border-[#f0ddb4]"><span aria-hidden="true">△</span><span>{w}</span></Alert>
    {/each}
  </div>
{/if}

<script lang="ts" module>
  import { Alert } from '$lib/components/ui/alert';
</script>

<style>
  .status {
    color: var(--text-3);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.9rem 0;
    font-size: 0.9rem;
  }
  .spinner {
    width: 15px;
    height: 15px;
    border: 2px solid var(--teal);
    border-top-color: transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
  }
  @keyframes spin {
    to { transform: rotate(360deg); }
  }
  .state-empty {
    text-align: center;
    padding: 2.2rem 1rem;
    border: 1px dashed var(--border-strong);
    border-radius: var(--radius);
    color: var(--text-2);
    background: var(--surface);
  }
  .empty-title { font-weight: 600; margin-bottom: 0.2rem; }
</style>