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:
2026-09-14 19:48:48 -04:00
parent efd4a4fa66
commit a2d4a38925
34 changed files with 5093 additions and 3144 deletions
+23
View File
@@ -0,0 +1,23 @@
import { tweened, type Tweened } from 'svelte/motion';
import { cubicOut } from 'svelte/easing';
// Svelte's `tweened` store, pre-configured for our design system so number
// changes feel like Apple's counter animations: fast, expressive out-quart,
// tabular-numeric-friendly.
//
// Respects prefers-reduced-motion at construction time — reduced-motion users
// get instant updates instead of interpolation.
const REDUCED_MOTION =
typeof window !== 'undefined' &&
window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
export function tweenedNumber(
initial = 0,
opts: { duration?: number } = {}
): Tweened<number> {
return tweened(initial, {
duration: REDUCED_MOTION ? 0 : (opts.duration ?? 360),
easing: cubicOut
});
}
+27
View File
@@ -0,0 +1,27 @@
// SvelteKit `onNavigate` helper — wraps client-side navigation in the
// browser's View Transitions API so route changes cross-fade cleanly and
// shared-element transitions (Fleet card → Server detail hero) morph.
//
// Chromium ships the API today; Firefox and Safari fall through to a plain
// navigation — same behavior as before, just without the transition.
// Structural type — accepts whatever SvelteKit passes to onNavigate without
// coupling to a specific @sveltejs/kit version's type name.
type NavigationLike = { complete: Promise<unknown> };
export function enableViewTransitions(navigation: NavigationLike): Promise<void> | void {
// Feature-detect without a custom Document extension — the DOM lib type
// varies between TS versions, and any narrowing has to survive both.
const start = (document as unknown as {
startViewTransition?: (cb: () => void | Promise<void>) => unknown;
}).startViewTransition;
if (typeof start !== 'function') return;
return new Promise<void>((resolve) => {
start.call(document, async () => {
resolve();
await navigation.complete;
});
});
}