48 lines
3.3 KiB
TypeScript
48 lines
3.3 KiB
TypeScript
"use client"
|
|
|
|
import { useEffect, useRef } from "react"
|
|
import { Badge } from "@/components/ui/badge"
|
|
|
|
export function NetworkMapLegend() {
|
|
const details = useRef<HTMLDetailsElement>(null)
|
|
useEffect(() => {
|
|
if (window.matchMedia("(max-width: 767px)").matches && details.current) details.current.open = false
|
|
}, [])
|
|
return (
|
|
<details ref={details} open data-map-legend className="absolute left-3 top-3 z-20 max-w-[calc(100%-1.5rem)] rounded-lg border bg-popover text-popover-foreground shadow-sm">
|
|
<summary className="cursor-pointer px-3 py-2 text-xs font-semibold focus-visible:outline-2 focus-visible:outline-ring">Легенда карты</summary>
|
|
<div role="region" aria-label="Легенда карты" className="flex max-h-[42vh] w-44 max-w-full flex-col gap-2 overflow-y-auto border-t px-3 py-2 text-[11px]">
|
|
<div>
|
|
<p className="mb-1.5 font-medium text-muted-foreground">Статус устройства</p>
|
|
<div className="grid grid-cols-2 gap-x-2 gap-y-1.5">
|
|
{[["var(--status-online)", "Онлайн"], ["var(--status-degraded)", "Внимание"], ["var(--status-offline)", "Оффлайн"], ["var(--muted-foreground)", "Неизвестно"]].map(([color, label]) => (
|
|
<span key={label} className="flex items-center gap-1.5"><span aria-hidden className="size-2 shrink-0 rounded-full" style={{ background: color }} />{label}</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<div className="flex flex-col gap-1.5">
|
|
<p className="font-medium text-muted-foreground">Тип узла</p>
|
|
{[["JH", "JumpHost", "var(--chart-1)"], ["EN", "Exit Node", "var(--chart-3)"], ["HR", "Home Router", "var(--chart-2)"]].map(([label, name, color]) => (
|
|
<span key={label} className="flex items-center gap-2"><Badge variant="secondary" style={{ color }} className="min-w-8 justify-center text-[10px]">{label}</Badge><span>{name}</span></span>
|
|
))}
|
|
<span className="flex items-center gap-2"><span aria-hidden className="mx-1 size-3 rounded-full border border-current" />WAN · аплинк</span>
|
|
<span className="flex items-center gap-2"><span aria-hidden className="mx-1 size-3 rounded border border-current" />Сервис / страна</span>
|
|
</div>
|
|
<div className="flex flex-col gap-1.5">
|
|
<p className="font-medium text-muted-foreground">Связи и измерения</p>
|
|
{[
|
|
["GRE", "var(--status-online)", undefined],
|
|
["GRE + IPsec", "var(--status-online)", "7 4"],
|
|
["Поток NetFlow", "var(--chart-4)", "6 5"],
|
|
["WAN → JH · модель", "var(--muted-foreground)", "5 4"],
|
|
].map(([label, color, dash]) => (
|
|
<span key={label} className="flex items-center gap-2"><svg aria-hidden width="28" height="12" className="shrink-0"><line x1="0" y1="6" x2="28" y2="6" stroke={color} strokeWidth="2" strokeDasharray={dash} /></svg>{label}</span>
|
|
))}
|
|
<p className="text-muted-foreground">RTT · задержка пробы. «—» · нет измерения.</p>
|
|
<p className="text-muted-foreground">NetFlow · трафик за 5 минут, не пропускная способность канала.</p>
|
|
</div>
|
|
</div>
|
|
</details>
|
|
)
|
|
}
|