feat(ui): V2 Design-Fundament — UI-Komponenten konsolidieren und tokenisieren
## Neue wiederverwendbare Komponenten in components/ui/:
- StatusDot.vue — Animierte Status-Punkte (work/think/idle/block/queue)
- PageHeading.vue — Standardisierter Gradient-Seiten-Header
- EmptyState.vue — Shared Empty-State mit Icon/Title/Description/Action
- ActivityTimeline.vue — Wiederverwendbarer Aktivitäts-Feed
- SectionHeader.vue — Spalten-/Sektions-Header (dot + label + count)
## Token-Konformität hergestellt:
- Badge.vue: +12 nexus-token-basierte Varianten (work/think/blocked/queue/done/review/iris/bao/agent/priority*)
- Card.vue: glass-panel/raised/subtle Varianten via nexus-tokens.css
- button/index.ts: +gradient, +icon, +ghostSubtle, +danger Varianten
- nexus-tokens.css: Buttons + --clr-* Semantic Colors (iris/bao/agent/review/stale/other)
## Hartkodierte Farben eliminiert (0 verbleibend):
- dashboard/v2/*: alle #hex → var(--)* ersetzt
- components/ui/*: alle #hex → var(--)* ersetzt
Task: ea7c2063
Build: ✅ grün
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* StatusDot — Nexus V2 animierter Status-Indikator
|
||||
*
|
||||
* Kapselt die pulse-keyframes aus nexus-tokens.css.
|
||||
* Status-Farben und Pulse-Animationen stammen ausschließlich aus Tokens.
|
||||
*
|
||||
* Props:
|
||||
* status – 'work' | 'think' | 'idle' | 'block' | 'queue'
|
||||
* size – 'sm' (8px) | 'md' (9px) | 'lg' (12px), default 'md'
|
||||
* pulse – Animation aktiv (default: true für work/think/block)
|
||||
* label – Text-Label rechts neben dem Dot (optional)
|
||||
*/
|
||||
|
||||
withDefaults(defineProps<{
|
||||
status: 'work' | 'think' | 'idle' | 'block' | 'queue'
|
||||
size?: 'sm' | 'md' | 'lg'
|
||||
pulse?: boolean
|
||||
label?: string
|
||||
}>(), {
|
||||
size: 'md',
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span class="status-dot-wrapper">
|
||||
<span
|
||||
class="dot"
|
||||
:class="[status, size, { pulse: pulse !== false }]"
|
||||
:aria-label="label || status"
|
||||
role="status"
|
||||
></span>
|
||||
<span v-if="label" class="dot-label">{{ label }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.status-dot-wrapper {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.dot {
|
||||
display: inline-block;
|
||||
border-radius: 50%;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.dot.sm { width: 7px; height: 7px; }
|
||||
.dot.md { width: 9px; height: 9px; }
|
||||
.dot.lg { width: 12px; height: 12px; }
|
||||
|
||||
/* Farben aus nexus-tokens.css — Single Source of Truth */
|
||||
.dot.work { background: var(--st-work); }
|
||||
.dot.think { background: var(--st-think); }
|
||||
.dot.idle { background: var(--st-idle); }
|
||||
.dot.block { background: var(--st-block); }
|
||||
.dot.queue { background: var(--st-queue); }
|
||||
|
||||
/* Pulse-Animationen (Keyframes in tokens.css definiert) */
|
||||
.dot.work.pulse { animation: pulse-work 1.8s infinite; box-shadow: 0 0 0 0 rgba(61,220,151,.55); }
|
||||
.dot.think.pulse { animation: pulse-think 1.8s infinite; box-shadow: 0 0 0 0 rgba(52,214,245,.55); }
|
||||
.dot.block.pulse { animation: pulse-block 1.4s infinite; box-shadow: 0 0 0 0 rgba(251,113,133,.55); }
|
||||
|
||||
.dot-label {
|
||||
font-size: 12.5px;
|
||||
font-weight: 600;
|
||||
color: var(--tx-2);
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user