feat(redesign): design-system tokens, 23 Vue components, game-aware shell + Fleet/Solo dashboard
All checks were successful
Test Asgard Runner / test (push) Successful in 4s

Tokens ported 1:1 from the Claude Design bundle (colors/game-themes/type/spacing/elevation/motion/fonts) with the data-theme/data-game theming contract via useThemeGame (+ cc-skin-swap repaint guard). 23 design-system components reimplemented as Vue SFCs (core/forms/data/navigation/feedback/brand). DashboardLayout rebuilt as the game-aware shell (GameSwitcher, grouped nav with permission gating preserved, agent-health footer, topbar). DashboardView: Fleet + Solo with per-game GAME_FIELDS rows and the themed ECharts PlayersChart; Solo wired to the real server store, Fleet on representative data pending the multi-instance backend. All four game skins (Rust/Dune/Conan/Soulmask). vue-tsc + vite build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Vantz Stockwell
2026-06-11 02:12:35 -04:00
parent ef128b47d2
commit f91ef84832
42 changed files with 3577 additions and 299 deletions

View File

@@ -0,0 +1,62 @@
<script setup lang="ts">
/**
* StatCard — KPI tile with icon, big mono value, and optional delta + note row.
* Green delta = up/good, red = down/bad, muted = flat.
*/
import { computed } from 'vue'
import Icon from '@/components/ds/core/Icon.vue'
const props = withDefaults(
defineProps<{
label: string
value: string | number
unit?: string
icon?: string
delta?: string | number
deltaDir?: 'up' | 'down' | 'flat'
note?: string
}>(),
{ deltaDir: 'up' },
)
const deltaIcon = computed(() =>
props.deltaDir === 'up' ? 'trending-up' : props.deltaDir === 'down' ? 'trending-down' : 'minus',
)
const showFoot = computed(() => props.delta != null || !!props.note)
</script>
<template>
<div class="cc-stat">
<div class="cc-stat__top">
<div v-if="icon" class="cc-stat__ico">
<Icon :name="icon" :size="15" :stroke-width="2.25" />
</div>
<div class="cc-stat__label">{{ label }}</div>
</div>
<div class="cc-stat__value">
{{ value }}<span v-if="unit" class="cc-stat__unit">{{ unit }}</span>
</div>
<div v-if="showFoot" class="cc-stat__foot">
<span v-if="delta != null" :class="['cc-stat__delta', 'cc-stat__delta--' + deltaDir]">
<Icon :name="deltaIcon" :size="13" :stroke-width="2.5" />{{ delta }}
</span>
<span v-if="note" class="cc-stat__note">{{ note }}</span>
</div>
</div>
</template>
<style>
.cc-stat { background: var(--surface-base); border-radius: var(--radius-lg); box-shadow: var(--ring-default); padding: 14px 16px; display: flex; flex-direction: column; gap: 10px; min-width: 0; position: relative; overflow: hidden; }
.cc-stat__top { display: flex; align-items: center; gap: 8px; }
.cc-stat__ico { width: 28px; height: 28px; border-radius: var(--radius-sm); display: flex; align-items: center; justify-content: center; background: var(--accent-soft); color: var(--accent-text); flex: none; }
.cc-stat__label { font-size: var(--text-xs); font-weight: 500; color: var(--text-tertiary); letter-spacing: .01em; }
.cc-stat__value { font-family: var(--font-mono); font-weight: 600; font-size: 28px; letter-spacing: -0.02em; color: var(--text-primary); font-variant-numeric: tabular-nums; line-height: 1; display: flex; align-items: baseline; gap: 4px; }
.cc-stat__unit { font-size: 14px; color: var(--text-muted); font-weight: 500; }
.cc-stat__foot { display: flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: var(--text-xs); }
.cc-stat__delta { display: inline-flex; align-items: center; gap: 3px; font-weight: 600; }
.cc-stat__delta--up { color: var(--status-online); }
.cc-stat__delta--down { color: var(--status-offline); }
.cc-stat__delta--flat { color: var(--text-tertiary); }
.cc-stat__note { color: var(--text-tertiary); }
</style>