mirror of
https://github.com/hanzoai/bootnode.git
synced 2026-10-25 02:31:30 +00:00
74 files imported `lucide-react` directly, pinned ^1.26.0, while @luxfi/ui — which this console renders alongside — resolves 1.27. Two Lucide copies from two resolutions in one bundle is how a set stops being one set. Two more glyphs were not from any icon library at all: the node list drew its network in/out arrows as the literal characters "↓" and "↑", and the chain onboarding selector drew its tick as "✓". Those are font glyphs — they take the text metrics, not the icon box, so they sit on a different baseline and scale with the font, not `size-*`. One source now: `@luxfi/ui/icons`, Lucide as @hanzo/gui standardises on it and @luxfi/ui themes it. `lucide-react` is out of package.json, so per-surface drift is no longer expressible; @luxfi/ui comes in at 7.4.3, which is where `./icons` lives. The three text glyphs are ArrowDown / ArrowUp / Check. All 121 distinct icon names this console uses were checked against the 6014 symbols @luxfi/ui/icons exports before the rewrite — zero missing, with a negative control. `next build` is clean: 78 routes, Next 16.2.11 + Turbopack. The d3 chart roots (node-globe, node-map, globe-view, donut-chart, fleet-map) keep their <svg>: those are plots, not glyphs. The command menu's "↑↓" stays — it is a keyboard legend inside <kbd>, and it means the keys. Co-authored-by: Hanzo Dev <[email protected]>
77 lines
2.5 KiB
TypeScript
77 lines
2.5 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useState } from "react"
|
|
import Link from "next/link"
|
|
import { ArrowRight, Circle } from "@luxfi/ui/icons"
|
|
import {
|
|
NETWORK_LABEL,
|
|
fetchFleetOverview,
|
|
fleetStatus,
|
|
type LuxFleetOverview,
|
|
} from "@/lib/fleet"
|
|
|
|
const DOT: Record<string, string> = {
|
|
operational: "text-green-500",
|
|
degraded: "text-yellow-500",
|
|
down: "text-red-500",
|
|
}
|
|
|
|
/** Compact live fleet status strip for the landing hero. Public, read-only. */
|
|
export function FleetStrip() {
|
|
const [ov, setOv] = useState<LuxFleetOverview | null>(null)
|
|
|
|
useEffect(() => {
|
|
let alive = true
|
|
const ctrl = new AbortController()
|
|
const load = () =>
|
|
fetchFleetOverview(ctrl.signal)
|
|
.then((d) => alive && setOv(d))
|
|
.catch(() => {})
|
|
load()
|
|
const t = setInterval(load, 20_000)
|
|
return () => {
|
|
alive = false
|
|
ctrl.abort()
|
|
clearInterval(t)
|
|
}
|
|
}, [])
|
|
|
|
if (!ov) return null
|
|
|
|
const totals = ov.totals ?? {}
|
|
|
|
return (
|
|
<Link
|
|
href="/fleet"
|
|
className="group mt-8 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 rounded-xl border border-zinc-800 bg-background/60 px-5 py-3 backdrop-blur transition-colors hover:border-zinc-700"
|
|
>
|
|
<span className="flex items-center gap-2 text-sm font-medium">
|
|
<span className="relative flex h-2.5 w-2.5">
|
|
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-green-500 opacity-60" />
|
|
<span className="relative inline-flex h-2.5 w-2.5 rounded-full bg-green-500" />
|
|
</span>
|
|
Live fleet
|
|
</span>
|
|
{ov.networks.map((f) => {
|
|
const s = fleetStatus(f)
|
|
return (
|
|
<span key={f.network} className="flex items-center gap-1.5 text-sm">
|
|
<Circle className={`h-2 w-2 fill-current ${DOT[s]}`} />
|
|
<span className="text-muted-foreground">{NETWORK_LABEL[f.network]}</span>
|
|
<span className="font-mono">
|
|
{f.nodes_ready}/{f.validators || f.nodes_total}
|
|
</span>
|
|
</span>
|
|
)
|
|
})}
|
|
<span className="hidden items-center gap-1.5 text-sm text-muted-foreground sm:flex">
|
|
<span className="font-mono text-foreground">{totals.total_peers ?? 0}</span> peers
|
|
</span>
|
|
<span className="flex items-center gap-1 text-sm text-primary opacity-80 group-hover:opacity-100">
|
|
View fleet
|
|
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
|
|
</span>
|
|
</Link>
|
|
)
|
|
}
|