193 lines
3.6 KiB
Vue
193 lines
3.6 KiB
Vue
<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>
|