{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cluster-state",
  "type": "registry:ui",
  "title": "ClusterState",
  "description": "Distributed consensus cluster topology visualizer (Leader, Followers, Candidates, Quorum status).",
  "registryDependencies": [
    "https://ui.arpitbhayani.me/r/aui.json"
  ],
  "files": [
    {
      "path": "ui/cluster-state.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ClusterNodeItem {\n  id: string;\n  role: \"leader\" | \"follower\" | \"candidate\" | \"offline\";\n  term?: number;\n  latency?: string;\n  state?: string;\n}\n\nexport interface ClusterStateProps extends React.HTMLAttributes<HTMLDivElement> {\n  title?: string;\n  nodes: ClusterNodeItem[];\n  requiredQuorum?: number;\n  onNodeClick?: (nodeId: string) => void;\n}\n\nexport function ClusterState({\n  title = \"Cluster Topology\",\n  nodes,\n  requiredQuorum,\n  onNodeClick,\n  className,\n  ...props\n}: ClusterStateProps) {\n  const totalNodes = nodes.length;\n  const activeNodes = nodes.filter((n) => n.role !== \"offline\").length;\n  const quorum = requiredQuorum ?? Math.floor(totalNodes / 2) + 1;\n  const isQuorumReached = activeNodes >= quorum;\n\n  const getNodeRoleStyle = (role: string) => {\n    switch (role) {\n      case \"leader\":\n        return \"border-primary bg-primary/10 ring-1 ring-primary\";\n      case \"candidate\":\n        return \"border-amber-500 bg-amber-500/10\";\n      case \"offline\":\n        return \"border-dashed border-border opacity-50 bg-muted\";\n      default:\n        return \"border-border bg-card\";\n    }\n  };\n\n  return (\n    <div\n      className={cn(\n        \"rounded-lg border border-border bg-card p-4 space-y-4 my-4 shadow-xs\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"flex flex-wrap items-center justify-between gap-2\">\n        <span className=\"font-mono text-xs font-medium text-foreground\">\n          {title}\n        </span>\n        <div\n          className={cn(\n            \"font-mono text-xs font-medium px-2 py-0.5 rounded border\",\n            isQuorumReached\n              ? \"bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border-emerald-500/20\"\n              : \"bg-rose-500/10 text-rose-600 dark:text-rose-400 border-rose-500/20\"\n          )}\n        >\n          Quorum: {activeNodes}/{totalNodes} {isQuorumReached ? \"Achieved\" : \"Lost\"} (Need {quorum})\n        </div>\n      </div>\n\n      <div className=\"grid grid-cols-2 sm:grid-cols-3 md:grid-cols-5 gap-3\">\n        {nodes.map((node) => (\n          <div\n            key={node.id}\n            className={cn(\n              \"flex flex-col p-3 rounded-md border transition-all cursor-pointer hover:-translate-y-0.5\",\n              getNodeRoleStyle(node.role)\n            )}\n            onClick={() => onNodeClick?.(node.id)}\n          >\n            <div className=\"flex items-center justify-between mb-1.5\">\n              <span className=\"font-mono text-sm font-medium text-foreground\">\n                {node.id}\n              </span>\n              <span\n                className={cn(\n                  \"w-2 h-2 rounded-full\",\n                  node.role === \"leader\" && \"bg-primary shadow-xs\",\n                  node.role === \"offline\" && \"bg-muted-foreground\",\n                  node.role !== \"leader\" && node.role !== \"offline\" && \"bg-emerald-500\"\n                )}\n              />\n            </div>\n            <span\n              className={cn(\n                \"font-mono text-xs font-medium uppercase tracking-wider mb-1\",\n                node.role === \"leader\" ? \"text-primary\" : \"text-muted-foreground\"\n              )}\n            >\n              {node.role}\n            </span>\n            {typeof node.term === \"number\" && (\n              <span className=\"font-mono text-xs text-muted-foreground\">\n                Term {node.term}\n              </span>\n            )}\n            {node.latency && (\n              <span className=\"font-mono text-xs text-muted-foreground font-medium\">\n                {node.latency}\n              </span>\n            )}\n          </div>\n        ))}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui"
    }
  ]
}