{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "opentui/usage-monitor",
  "title": "Usage Monitor",
  "description": "Real-time dashboard with diamond header, progress metrics, burn rate, predictions, and status bar",
  "dependencies": [
    "@opentui/react"
  ],
  "files": [
    {
      "path": "registry/opentui/ui/usage-monitor.tsx",
      "content": "/* @jsxImportSource @opentui/react */\nimport React, { useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\n\nexport interface UsageMonitorProps {\n  refreshInterval?: number;\n  separatorChar?: string;\n  children: ReactNode;\n}\n\nexport interface UsageMonitorHeaderProps {\n  title: string;\n  titleColor?: string;\n  decorator?: string;\n  separatorChar?: string;\n  separatorColor?: string;\n}\n\nexport interface UsageMonitorTagsProps {\n  items: string[];\n  bracketColor?: string;\n  separatorColor?: string;\n}\n\nexport interface UsageMonitorSectionProps {\n  icon?: string;\n  title?: string;\n  subtitle?: string;\n  children: ReactNode;\n}\n\nexport interface UsageMonitorMetricProps {\n  icon?: string;\n  label: string;\n  value: number;\n  max: number;\n  percent: number;\n  status: \"green\" | \"yellow\" | \"red\" | \"blue\";\n  format: \"number\" | \"currency\" | \"duration\" | \"percent\" | \"custom\";\n  formatFn?: (v: number, max: number) => string;\n  barWidth?: number;\n  barFillChar?: string;\n  barEmptyChar?: string;\n  barColor?: string;\n  maxDim?: boolean;\n  showMax?: boolean;\n}\n\nexport interface UsageMonitorDistributionMetricProps {\n  icon?: string;\n  label: string;\n  segments: {\n    label: string;\n    percent: number;\n    color?: string;\n  }[];\n  barWidth?: number;\n}\n\nexport interface UsageMonitorStatRowProps {\n  icon?: string;\n  label: string;\n  value: string;\n  valueSuffix?: string;\n  valueColor?: string;\n}\n\nexport interface UsageMonitorPredictionProps {\n  label: string;\n  value: string;\n  valueColor?: string;\n}\n\nexport interface UsageMonitorStatusBarProps {\n  clock?: boolean;\n  clockColor?: string;\n  sessionLabel?: string;\n  sessionColor?: string;\n  exitHint?: string;\n  statusDot?: \"green\" | \"yellow\" | \"red\";\n  separator?: string;\n}\n\nconst formatValue = (\n  value: number,\n  max: number,\n  format: UsageMonitorMetricProps[\"format\"],\n  formatFn?: (v: number, max: number) => string\n): {\n  current: string;\n  maxStr: string;\n} => {\n  if (format === \"custom\" && formatFn) {\n    const result = formatFn(value, max);\n    return { current: result, maxStr: \"\" };\n  }\n  switch (format) {\n    case \"currency\": {\n      return {\n        current: `$${value.toFixed(2)}`,\n        maxStr: `$${max.toFixed(2)}`,\n      };\n    }\n    case \"duration\": {\n      const h = Math.floor(value / 60);\n      const m = value % 60;\n      const maxH = Math.floor(max / 60);\n      const maxM = max % 60;\n      return {\n        current: h > 0 ? `${h}h ${m}m` : `${m}m`,\n        maxStr: maxH > 0 ? `${maxH}h ${maxM}m` : `${maxM}m`,\n      };\n    }\n    case \"percent\": {\n      return {\n        current: `${value.toFixed(1)}%`,\n        maxStr: `${max.toFixed(1)}%`,\n      };\n    }\n    case \"number\": {\n      return {\n        current: value.toLocaleString(),\n        maxStr: max.toLocaleString(),\n      };\n    }\n    default: {\n      return { current: String(value), maxStr: String(max) };\n    }\n  }\n};\n\nconst statusDotChar = (\n  status: \"green\" | \"yellow\" | \"red\"\n): {\n  char: string;\n  color: string;\n} => {\n  switch (status) {\n    case \"green\": {\n      return { char: \"●\", color: \"green\" };\n    }\n    case \"yellow\": {\n      return { char: \"◕\", color: \"yellow\" };\n    }\n    case \"red\": {\n      return { char: \"○\", color: \"red\" };\n    }\n    default: {\n      return { char: \"●\", color: \"green\" };\n    }\n  }\n};\n\nconst UsageMonitorRoot = ({\n  refreshInterval = 1000,\n  separatorChar = \"─\",\n  children,\n}: UsageMonitorProps) => {\n  const [, setTick] = useState(0);\n  useEffect(() => {\n    const id = setInterval(() => setTick((t) => t + 1), refreshInterval);\n    return () => clearInterval(id);\n  }, [refreshInterval]);\n\n  return (\n    <box flexDirection=\"column\">\n      {React.Children.toArray(children).map((child, i, arr) => {\n        const childKey =\n          React.isValidElement(child) && child.key !== null ? child.key : i;\n\n        return (\n          <box key={childKey} flexDirection=\"column\">\n            {child}\n            {i < arr.length - 1 &&\n              React.isValidElement(child) &&\n              (\n                child.type as unknown as {\n                  displayName?: string;\n                }\n              ).displayName !== \"UsageMonitor.StatusBar\" && (\n                <text fg=\"#666\">{separatorChar.repeat(44)}</text>\n              )}\n          </box>\n        );\n      })}\n    </box>\n  );\n};\n\nconst UsageMonitorHeader = ({\n  title,\n  titleColor = \"cyan\",\n  decorator = \"◆ ✦ ◆ ✦\",\n  separatorChar = \"═\",\n  separatorColor,\n}: UsageMonitorHeaderProps) => (\n  <box flexDirection=\"column\">\n    <box flexDirection=\"row\" justifyContent=\"center\">\n      <text fg=\"#666\">{`${decorator}  `}</text>\n      <text fg={titleColor}>\n        <b>{title}</b>\n      </text>\n      <text fg=\"#666\">{`  ${decorator}`}</text>\n    </box>\n    <text fg={separatorColor ?? \"#666\"}>{separatorChar.repeat(44)}</text>\n  </box>\n);\nUsageMonitorHeader.displayName = \"UsageMonitor.Header\";\n\nconst UsageMonitorTags = ({\n  items,\n  bracketColor,\n  separatorColor,\n}: UsageMonitorTagsProps) => (\n  <box flexDirection=\"row\" marginBottom={1}>\n    <text fg={bracketColor ?? \"cyan\"}>{\"[ \"}</text>\n    {items.flatMap((item, i) => [\n      <text key={`${item}-${i}-label`}>{item}</text>,\n      i < items.length - 1 ? (\n        <text key={`${item}-${i}-separator`} fg={separatorColor ?? \"cyan\"}>\n          {\" | \"}\n        </text>\n      ) : null,\n    ])}\n    <text fg={bracketColor ?? \"cyan\"}>{\" ]\"}</text>\n  </box>\n);\n\nconst UsageMonitorSection = ({\n  icon,\n  title,\n  subtitle,\n  children,\n}: UsageMonitorSectionProps) => (\n  <box flexDirection=\"column\" marginBottom={1}>\n    {(icon || title) && (\n      <box flexDirection=\"row\" gap={1}>\n        {icon && <text>{icon}</text>}\n        {title && (\n          <text>\n            <b>{title}</b>\n          </text>\n        )}\n      </box>\n    )}\n    {subtitle && <text fg=\"#666\">{`    ${subtitle}`}</text>}\n    <box flexDirection=\"column\" paddingTop={1}>\n      {children}\n    </box>\n  </box>\n);\n\nconst UsageMonitorMetric = ({\n  icon,\n  label,\n  value,\n  max,\n  percent,\n  status,\n  format,\n  formatFn,\n  barWidth = 22,\n  barFillChar = \"█\",\n  barEmptyChar = \"░\",\n  barColor = \"white\",\n  maxDim = false,\n  showMax = true,\n}: UsageMonitorMetricProps) => {\n  const filled = Math.round((percent / 100) * barWidth);\n  const empty = barWidth - filled;\n  const bar = barFillChar.repeat(filled) + barEmptyChar.repeat(empty);\n  const dot = statusDotChar(status as \"green\" | \"yellow\" | \"red\");\n  const { current, maxStr } = formatValue(value, max, format, formatFn);\n\n  return (\n    <box flexDirection=\"row\" gap={1}>\n      {icon && <text>{icon}</text>}\n      <text fg=\"#666\">{label.padEnd(16)}</text>\n      <text fg={dot.color}>{dot.char}</text>\n      <text fg={barColor}>{`[${bar}]`}</text>\n      <text>{` ${percent.toFixed(1)}%`}</text>\n      <text>{` ${current}`}</text>\n      {showMax && maxStr && (\n        <text fg={maxDim ? \"#666\" : undefined}>{`/ ${maxStr}`}</text>\n      )}\n    </box>\n  );\n};\n\nconst UsageMonitorDistributionMetric = ({\n  icon,\n  label,\n  segments,\n  barWidth = 22,\n}: UsageMonitorDistributionMetricProps) => {\n  const bars = segments.map((seg) => {\n    const count = Math.round((seg.percent / 100) * barWidth);\n    return { ...seg, count };\n  });\n\n  return (\n    <box flexDirection=\"row\" gap={1}>\n      {icon && <text>{icon}</text>}\n      <text fg=\"#666\">{label.padEnd(16)}</text>\n      <text>[</text>\n      {bars.map((seg, i) => (\n        <text key={i} fg={seg.color ?? \"white\"}>\n          {\"█\".repeat(seg.count)}\n        </text>\n      ))}\n      <text>]</text>\n      {segments.map((seg, i) => (\n        <text\n          key={i}\n          fg={seg.color ?? \"white\"}\n        >{`${seg.label} ${seg.percent}%${i < segments.length - 1 ? \" | \" : \"\"}`}</text>\n      ))}\n    </box>\n  );\n};\n\nconst UsageMonitorStats = ({ children }: { children: ReactNode }) => (\n  <box flexDirection=\"column\">{children}</box>\n);\n\nconst UsageMonitorStatRow = ({\n  icon,\n  label,\n  value,\n  valueSuffix,\n  valueColor = \"white\",\n}: UsageMonitorStatRowProps) => (\n  <box flexDirection=\"row\" gap={1}>\n    {icon && <text>{icon}</text>}\n    <text fg=\"#666\">{label.padEnd(16)}</text>\n    <text fg={valueColor}>{value}</text>\n    {valueSuffix && <text>{` ${valueSuffix}`}</text>}\n  </box>\n);\n\nconst UsageMonitorPredictions = ({ children }: { children: ReactNode }) => (\n  <box flexDirection=\"column\">\n    <text>\n      <b>🔮 Predictions:</b>\n    </text>\n    <box flexDirection=\"column\" paddingLeft={4}>\n      {children}\n    </box>\n  </box>\n);\n\nconst UsageMonitorPrediction = ({\n  label,\n  value,\n  valueColor = \"yellow\",\n}: UsageMonitorPredictionProps) => (\n  <box flexDirection=\"row\">\n    <text fg=\"#666\">{label.padEnd(24)}</text>\n    <text fg={valueColor}>{value}</text>\n  </box>\n);\n\nconst UsageMonitorStatusBar = ({\n  clock = false,\n  clockColor,\n  sessionLabel,\n  sessionColor = \"green\",\n  exitHint,\n  statusDot: dot = \"green\",\n  separator = \" | \",\n}: UsageMonitorStatusBarProps) => {\n  const [time, setTime] = useState(() => new Date().toTimeString().slice(0, 8));\n  useEffect(() => {\n    const id = setInterval(\n      () => setTime(new Date().toTimeString().slice(0, 8)),\n      1000\n    );\n    return () => clearInterval(id);\n  }, []);\n\n  const dotInfo = statusDotChar(dot);\n\n  return (\n    <box flexDirection=\"row\" paddingTop={1}>\n      {clock && <text fg={clockColor ?? \"cyan\"}>{`⏰ ${time}`}</text>}\n      {sessionLabel && (\n        <text fg={sessionColor}>{`${separator}📄 ${sessionLabel}`}</text>\n      )}\n      {exitHint && <text fg=\"#666\">{`${separator}${exitHint}`}</text>}\n      <text fg={dotInfo.color}>{`${separator}${dotInfo.char}`}</text>\n    </box>\n  );\n};\nUsageMonitorStatusBar.displayName = \"UsageMonitor.StatusBar\";\n\nexport const UsageMonitor = Object.assign(UsageMonitorRoot, {\n  DistributionMetric: UsageMonitorDistributionMetric,\n  Header: UsageMonitorHeader,\n  Metric: UsageMonitorMetric,\n  Prediction: UsageMonitorPrediction,\n  Predictions: UsageMonitorPredictions,\n  Section: UsageMonitorSection,\n  StatRow: UsageMonitorStatRow,\n  Stats: UsageMonitorStats,\n  StatusBar: UsageMonitorStatusBar,\n  Tags: UsageMonitorTags,\n});\n",
      "type": "registry:ui",
      "target": "components/ui/usage-monitor.tsx"
    }
  ],
  "categories": [
    "templates"
  ],
  "type": "registry:ui"
}