Files
nexus/frontend/src/components/dashboard/v2/AlertBar.vue
T
AzuTear 64459ccdb3
CI - Build & Test / Backend (.NET) (push) Successful in 25s
CI - Build & Test / Frontend (Vue/TS) (push) Has been cancelled
CI - Build & Test / Security Check (push) Has been cancelled
feat: wire dashboard v2 to backend data
2026-06-14 15:44:05 +02:00

193 lines
3.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
/**
* AlertBar — Status-Übersicht im V2 Dashboard
*
* Props:
* activeCount Agents mit status 'work'
* thinkCount Agents mit status 'think'
* idleCount Agents mit status 'idle'
* blockerCount Blocker-Anzahl
* todayCost Kosten heute (z.B. "$6.40")
* todayTokens Token heute (z.B. "282k")
*/
import { icons } from '../../../composables/icons'
defineProps<{
activeCount: number
thinkCount: number
idleCount: number
blockerCount: number
todayCost: string
todayTokens: string
blockerLabel?: string
}>()
defineEmits<{
blockerClick: []
}>()
</script>
<template>
<div class="alertbar glass-panel">
<!-- Active (arbeitet) -->
<div class="seg">
<span class="dot work"></span>
<span class="seg-label">{{ activeCount }} arbeiten</span>
</div>
<!-- Think (plant) -->
<div class="seg">
<span class="dot think"></span>
<span class="seg-label">{{ thinkCount }} planen</span>
</div>
<!-- Idle (bereit) -->
<div class="seg">
<span class="dot idle"></span>
<span class="seg-label">{{ idleCount }} bereit</span>
</div>
<!-- Separator -->
<div class="sep"></div>
<!-- Kosten heute -->
<div class="seg tx2">
<span class="seg-icon" v-html="icons.coin || ''"></span>
heute <span class="cost-value">{{ todayCost }}</span> · {{ todayTokens }}
</div>
<!-- Blocker Alert (rechts) -->
<button
v-if="blockerCount > 0"
class="blk"
@click="$emit('blockerClick')"
>
<span class="dot block"></span>
{{ blockerLabel || `${blockerCount} Blocker` }}
</button>
</div>
</template>
<style scoped>
.alertbar {
display: flex;
align-items: center;
gap: 14px;
padding: 11px 16px;
border-radius: var(--r);
flex-wrap: wrap;
}
.seg {
display: flex;
align-items: center;
gap: 8px;
font-size: 12.5px;
font-weight: 600;
color: var(--tx);
white-space: nowrap;
}
.seg-label {
color: var(--tx-2);
}
.seg-icon :deep(svg) {
width: 14px;
height: 14px;
flex: 0 0 auto;
color: var(--a-mid);
}
.tx2 .seg-icon :deep(svg) {
color: var(--tx-3);
}
.dot {
width: 9px;
height: 9px;
border-radius: 50%;
flex: 0 0 auto;
}
.dot.work {
background: var(--st-work);
box-shadow: 0 0 0 0 rgba(61,220,151,.55);
animation: pulse-work 1.8s infinite;
}
.dot.think {
background: var(--st-think);
box-shadow: 0 0 0 0 rgba(52,214,245,.55);
animation: pulse-think 1.8s infinite;
}
.dot.idle {
background: var(--st-idle);
}
.dot.block {
background: var(--st-block);
box-shadow: 0 0 0 0 rgba(251,113,133,.55);
animation: pulse-block 1.8s infinite;
}
.sep {
width: 1px;
height: 20px;
background: var(--line-2);
flex: 0 0 auto;
}
.cost-value {
font-family: 'JetBrains Mono', monospace;
font-variant-numeric: tabular-nums;
background: var(--grad);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.blk {
margin-left: auto;
display: inline-flex;
align-items: center;
gap: 9px;
padding: 6px 12px;
border-radius: 9px;
background: rgba(251,113,133,.12);
border: 1px solid rgba(251,113,133,.3);
font-size: 12.5px;
font-weight: 600;
color: #fda4b0;
cursor: pointer;
transition: background .15s;
font-family: 'Manrope', sans-serif;
white-space: nowrap;
}
.blk:hover {
background: rgba(251,113,133,.22);
}
@media (max-width: 767px) {
.alertbar {
flex-wrap: wrap;
gap: 8px;
padding: 10px;
}
.seg {
flex: 0 0 calc(50% - 4px);
}
.sep {
display: none;
}
.blk {
margin-left: 0;
}
}
</style>