summaryrefslogtreecommitdiff
path: root/frontend/src/components/Status.svelte
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-17 14:32:37 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-17 14:32:37 +0800
commit5c0ba37eda80d39e6ceca59bb1d5f4942f858995 (patch)
tree948723f9cedf7ccb0707fa6ee516bd30fe20fd10 /frontend/src/components/Status.svelte
downloadstrategy-lab-5c0ba37eda80d39e6ceca59bb1d5f4942f858995.tar.gz
chore: establish Strategy Lab source baseline (development, not release)
Diffstat (limited to 'frontend/src/components/Status.svelte')
-rw-r--r--frontend/src/components/Status.svelte66
1 files changed, 66 insertions, 0 deletions
diff --git a/frontend/src/components/Status.svelte b/frontend/src/components/Status.svelte
new file mode 100644
index 0000000..019c224
--- /dev/null
+++ b/frontend/src/components/Status.svelte
@@ -0,0 +1,66 @@
+<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}
+ <div class="banner error" role="alert">
+ <span aria-hidden="true">⚠</span>
+ <span>{error}</span>
+ </div>
+{: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)}
+ <div class="banner warn"><span aria-hidden="true">△</span><span>{w}</span></div>
+ {/each}
+ </div>
+{/if}
+
+<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); }
+ }
+ .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>