Files
riotpiao.com/components/cluster/Ribbon.tsx
T

55 lines
1.8 KiB
TypeScript
Raw Normal View History

2026-08-18 18:33:49 -07:00
'use client'
import { useEffect, useState } from 'react'
import { cluster, nodes } from '@/lib/clusterMock'
import { SlotMeter } from './SlotMeter'
/** Fake liveness so the layout can be judged in motion. Replaced by SSE in Phase 2. */
function useDrift() {
const [age, setAge] = useState<number>(cluster.snapshotAge)
const [slots, setSlots] = useState(3)
useEffect(() => {
const tick = setInterval(() => setAge((a) => (a > 6 ? 0.4 : +(a + 0.9).toFixed(1))), 900)
const churn = setInterval(() => setSlots(() => 1 + Math.floor(Math.random() * 5)), 3400)
return () => {
clearInterval(tick)
clearInterval(churn)
}
}, [])
return { age, slots }
}
export function Ribbon() {
const { age, slots } = useDrift()
return (
<div className="flex flex-wrap items-center gap-x-6 gap-y-2 border-b border-wire bg-void px-4 py-2.5 font-data text-[11px]">
<span className="flex items-center gap-2 text-chalk">
<span className="h-1.5 w-1.5 rounded-full bg-flux" />
{cluster.distro}
</span>
<span className="text-dim">
k8s <span className="text-chalk">{cluster.kubernetes}</span>
</span>
<span className="text-dim">
nodes <span className="text-chalk">{nodes.length}</span>
</span>
<span className="text-dim">
snapshot <span className="text-chalk">{age.toFixed(1)}s</span>
</span>
<span className="ml-auto flex items-center gap-3">
<span className="uppercase tracking-[0.16em] text-dim">seq</span>
<SlotMeter used={slots} />
<span className="tabular-nums text-chalk">{slots}/8</span>
</span>
<span className="border border-lamp/40 px-1.5 py-0.5 uppercase tracking-[0.16em] text-lamp">
placeholder data
</span>
</div>
)
}