feat(ui,api): strip board redesign - island, rail by day, context view, server search, vault graph
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
<script lang="ts">
|
||||
import type { LimitWindow } from "$lib/api/types";
|
||||
import { fmtCountdown, fmtMoney, fmtRelative, fmtTokens } from "$lib/format";
|
||||
import { limitLabel } from "$lib/limits";
|
||||
import { cn } from "$lib/utils";
|
||||
|
||||
let {
|
||||
contextTokens,
|
||||
contextWindow,
|
||||
windows,
|
||||
spend = null,
|
||||
now,
|
||||
compact = false,
|
||||
}: {
|
||||
contextTokens: number;
|
||||
contextWindow: number;
|
||||
windows: LimitWindow[];
|
||||
spend?: number | null;
|
||||
now: number;
|
||||
compact?: boolean;
|
||||
} = $props();
|
||||
|
||||
const TONE: Record<string, string> = {
|
||||
allowed: "bg-primary",
|
||||
allowed_warning: "bg-primary",
|
||||
rejected: "bg-destructive",
|
||||
};
|
||||
const contextPct = $derived(
|
||||
Math.min(100, Math.round((contextTokens / contextWindow) * 100))
|
||||
);
|
||||
const known = (w: LimitWindow) =>
|
||||
w.utilization !== null && w.utilization !== undefined;
|
||||
const pct = (w: LimitWindow) =>
|
||||
Math.min(100, Math.round((w.utilization ?? 0) * 100));
|
||||
</script>
|
||||
|
||||
<div
|
||||
class={cn(
|
||||
"grid gap-x-6 gap-y-4",
|
||||
compact
|
||||
? "@lg:grid-cols-5 grid-cols-2"
|
||||
: "grid-cols-2 sm:grid-cols-3 lg:grid-cols-5"
|
||||
)}
|
||||
>
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="label-quiet">Context</span>
|
||||
<span class="tabular font-semibold text-2xl leading-none tracking-tight">
|
||||
{fmtTokens(contextTokens)}
|
||||
<span class="font-normal text-muted-foreground text-sm">
|
||||
/ {fmtTokens(contextWindow)}
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-label="context share"
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={contextPct}
|
||||
class="h-0.5 w-full overflow-hidden rounded-full bg-muted"
|
||||
role="progressbar"
|
||||
>
|
||||
<span
|
||||
class="block h-full rounded-full bg-primary transition-[width] duration-500"
|
||||
style="width: {contextPct}%"
|
||||
></span>
|
||||
</span>
|
||||
</div>
|
||||
{#each windows as w (w.window)}
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="label-quiet">{limitLabel(w.window)}</span>
|
||||
{#if known(w)}
|
||||
<span
|
||||
class={cn(
|
||||
"tabular font-semibold text-2xl leading-none tracking-tight",
|
||||
w.status === "rejected" && "text-destructive"
|
||||
)}
|
||||
>
|
||||
{pct(w)}
|
||||
<span class="font-normal text-muted-foreground text-sm">%</span>
|
||||
<span class="font-normal text-muted-foreground text-xs">
|
||||
{fmtCountdown(w.resets_at, now).replace("resets ", "")}
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-label="{limitLabel(w.window)} utilization"
|
||||
aria-valuemax="100"
|
||||
aria-valuemin="0"
|
||||
aria-valuenow={pct(w)}
|
||||
class="h-0.5 w-full overflow-hidden rounded-full bg-muted"
|
||||
role="progressbar"
|
||||
>
|
||||
<span
|
||||
class={cn(
|
||||
"block h-full rounded-full transition-[width] duration-500",
|
||||
TONE[w.status]
|
||||
)}
|
||||
style="width: {pct(w)}%"
|
||||
></span>
|
||||
</span>
|
||||
{:else}
|
||||
<span class="text-muted-foreground text-sm leading-none">
|
||||
no report
|
||||
</span>
|
||||
<span class="text-muted-foreground text-xs">
|
||||
last seen {fmtRelative(w.ts, now)}
|
||||
</span>
|
||||
{/if}
|
||||
</div>
|
||||
{/each}
|
||||
{#if spend !== null}
|
||||
<div class="flex flex-col gap-1.5">
|
||||
<span class="label-quiet">Spend · 24 h</span>
|
||||
<span class="tabular font-semibold text-2xl leading-none tracking-tight">
|
||||
{fmtMoney(spend)}
|
||||
</span>
|
||||
<span class="text-muted-foreground text-xs">API-price equivalent</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user