Redesign UI with new token system, primitives, and motion
Restraint-first design language: neutral gray surfaces + one blue accent (cyan/amber/red reserved for state), 8pt spacing, softer radii, one ambient + one raised shadow, standardized motion tokens. Alfa Slab One demoted to BrandMark only; Inter carries all page copy. New primitives (Button, Card, Badge, Stat, SectionHeader, Skeleton, EmptyState, Tabs, Breadcrumbs, StatusPip, Field, Input, Select, Textarea) plus motion utilities (tweenNumber, viewTransition) and a global toast system. All eight route surfaces rewritten on top: Fleet gains an overview hero, Server detail restructures into tabs, Deployments gets a collapsible drift summary + per-server pipeline visual, and the scripts/configs/plugins/betas flows adopt the new form primitives. Sticky translucent nav with backdrop blur, view-transition cross-fades between routes, staggered card entrance on Fleet, breathing status pip halo, tabular-numeric player counts. Gmail-style g-key nav shortcuts. Mobile stacks below 720px; prefers-reduced-motion neutralizes durations. Legacy tokens preserved as aliases so any un-migrated code still renders.
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
<script lang="ts">
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
label?: string;
|
||||
hint?: string | null;
|
||||
error?: string | null;
|
||||
required?: boolean;
|
||||
forId?: string;
|
||||
children?: Snippet;
|
||||
}
|
||||
|
||||
let { label, hint = null, error = null, required = false, forId, children }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="field">
|
||||
{#if label}
|
||||
<label class="label" for={forId}>
|
||||
{label}
|
||||
{#if required}<span class="req" aria-hidden="true">*</span>{/if}
|
||||
</label>
|
||||
{/if}
|
||||
<div class="control" class:has-error={!!error}>
|
||||
{@render children?.()}
|
||||
</div>
|
||||
{#if error}
|
||||
<div class="msg msg-error" role="alert">{error}</div>
|
||||
{:else if hint}
|
||||
<div class="msg msg-hint">{hint}</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-2);
|
||||
min-width: 0;
|
||||
}
|
||||
.label {
|
||||
font-size: var(--text-xs);
|
||||
font-weight: var(--weight-semibold);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: var(--tracking-label);
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
.req { color: var(--state-danger); margin-left: 3px; }
|
||||
.control { display: flex; flex-direction: column; }
|
||||
.msg {
|
||||
font-size: var(--text-xs);
|
||||
}
|
||||
.msg-hint { color: var(--text-tertiary); }
|
||||
.msg-error { color: var(--state-danger); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user