summaryrefslogtreecommitdiffhomepage
path: root/src/features/account-usage/ui/UsageBar.svelte
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-10-14 17:04:35 +0900
committerAdam Malczewski <[email protected]>2026-10-14 17:04:35 +0900
commit10e78065201c8387494b8aafabb987da87183b3a (patch)
treef038f368459acbd3b817974100fb4bd4817ecbff /src/features/account-usage/ui/UsageBar.svelte
parent551a7a050e8cd25e795026a1060c9d5b5ea028bf (diff)
downloaddispatch-web-10e78065201c8387494b8aafabb987da87183b3a.tar.gz
dispatch-web-10e78065201c8387494b8aafabb987da87183b3a.zip
feat(account-usage): sidebar Usage view with Claude/Codex quota bars + on-track pace markers
Consumes GET /usage (transport-contract 0.25.0). DaisyUI progress bars per quota window with a dot at the elapsed fraction of the window (the 'on track' level), ahead/under-pace labels, reset countdowns, stale/unavailable/not-configured states.
Diffstat (limited to 'src/features/account-usage/ui/UsageBar.svelte')
-rw-r--r--src/features/account-usage/ui/UsageBar.svelte49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/features/account-usage/ui/UsageBar.svelte b/src/features/account-usage/ui/UsageBar.svelte
new file mode 100644
index 0000000..f4298c1
--- /dev/null
+++ b/src/features/account-usage/ui/UsageBar.svelte
@@ -0,0 +1,49 @@
+<script lang="ts">
+ import type { UsageBarView } from "../logic/view-model";
+
+ let { bar }: { bar: UsageBarView } = $props();
+
+ const progressClass = $derived(
+ {
+ success: "progress-success",
+ warning: "progress-warning",
+ error: "progress-error",
+ neutral: "",
+ }[bar.tone],
+ );
+</script>
+
+<div class="flex flex-col gap-0.5" data-testid="usage-bar" data-limit-id={bar.id}>
+ <div class="flex items-baseline justify-between gap-2 text-xs">
+ <span class="truncate font-medium">{bar.label}</span>
+ <span class="shrink-0 font-mono tabular-nums">{bar.valueLabel}</span>
+ </div>
+ <div class="relative flex items-center">
+ <progress
+ class="progress h-2 w-full {progressClass}"
+ value={bar.percent}
+ max="100"
+ aria-label="{bar.label} usage"
+ ></progress>
+ {#if bar.pacePercent !== null}
+ <!-- Pace marker: where usage would be if spread evenly to the reset. -->
+ <span
+ class="pointer-events-none absolute top-1/2 size-2.5 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-base-100 bg-base-content"
+ style="left: {bar.pacePercent}%"
+ data-testid="pace-marker"
+ title="On-track pace: {Math.round(bar.pacePercent)}%"
+ aria-hidden="true"
+ ></span>
+ {/if}
+ </div>
+ {#if bar.resetLabel || bar.paceLabel}
+ <div class="flex justify-between gap-2 text-[11px] opacity-60">
+ <span>{bar.resetLabel ?? ""}</span>
+ {#if bar.paceLabel}
+ <span class:text-warning={bar.aheadOfPace} class:opacity-100={bar.aheadOfPace}
+ >{bar.paceLabel}</span
+ >
+ {/if}
+ </div>
+ {/if}
+</div>