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
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:
53
frontend/src/components/ds/data/ResourceMeter.vue
Normal file
53
frontend/src/components/ds/data/ResourceMeter.vue
Normal file
@@ -0,0 +1,53 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* ResourceMeter — labeled utilization bar (CPU, RAM, disk, network).
|
||||
* tone="auto" colors by threshold: green <70%, amber <90%, red ≥90%.
|
||||
*/
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
label: string
|
||||
icon?: string
|
||||
value?: number
|
||||
sub?: string
|
||||
tone?: 'auto' | 'ok' | 'warn' | 'danger' | 'accent'
|
||||
}>(),
|
||||
{ value: 0, tone: 'auto' },
|
||||
)
|
||||
|
||||
const pct = computed(() => Math.max(0, Math.min(100, props.value)))
|
||||
|
||||
const resolvedTone = computed(() => {
|
||||
if (props.tone !== 'auto') return props.tone
|
||||
return pct.value >= 90 ? 'danger' : pct.value >= 70 ? 'warn' : 'ok'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="['cc-meter', 'cc-meter--' + resolvedTone]">
|
||||
<div class="cc-meter__top">
|
||||
<span class="cc-meter__label">{{ label }}</span>
|
||||
<span class="cc-meter__val">
|
||||
{{ pct }}%<span v-if="sub" class="cc-meter__sub">{{ sub }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="cc-meter__track">
|
||||
<div class="cc-meter__fill" :style="{ width: pct + '%' }" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.cc-meter { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
|
||||
.cc-meter__top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
|
||||
.cc-meter__label { font-size: var(--text-xs); color: var(--text-secondary); display: flex; align-items: center; gap: 6px; }
|
||||
.cc-meter__val { font-family: var(--font-mono); font-size: var(--text-xs); font-weight: 600; color: var(--text-primary); font-variant-numeric: tabular-nums; }
|
||||
.cc-meter__sub { color: var(--text-muted); font-weight: 400; margin-left: 4px; }
|
||||
.cc-meter__track { height: 6px; border-radius: var(--radius-pill); background: var(--surface-active); overflow: hidden; }
|
||||
.cc-meter__fill { height: 100%; border-radius: var(--radius-pill); transition: width var(--dur-slow) var(--ease-out), background var(--dur-base); }
|
||||
.cc-meter--accent .cc-meter__fill { background: var(--accent); }
|
||||
.cc-meter--ok .cc-meter__fill { background: var(--status-online); }
|
||||
.cc-meter--warn .cc-meter__fill { background: var(--status-warn); }
|
||||
.cc-meter--danger .cc-meter__fill { background: var(--status-offline); }
|
||||
</style>
|
||||
Reference in New Issue
Block a user