{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "analytics-overview",
  "title": "Analytics Overview",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/analytics-overview/AnalyticsOverview.vue",
      "content": "<script setup lang=\"ts\">\n// Two-pane analytics dashboard: a combo chart (stacked bars with a\n// dot overlay on a dual y-axis) sits above an interactive drill-down\n// line chart. Click a bar in the top pane to filter the bottom pane\n// to that route. The block bakes in a realistic dummy dataset; swap\n// `routes`, `partners`, and `drillSeries` with your own to repoint.\n//\n// Built on `RawChart` rather than `BarChart` because combo charts\n// (bar + scatter + dual y-axes) sit outside the opinionated wrapper's\n// single-series-type contract -- this is the documented escape hatch.\nimport { computed, ref } from 'vue'\nimport { use } from 'echarts/core'\nimport { BarChart as EBar, ScatterChart as EScatter, LineChart as ELine } from 'echarts/charts'\nimport { GridComponent, TooltipComponent, LegendComponent, MarkLineComponent } from 'echarts/components'\nimport {\n  chartColors,\n  chartTextColor,\n  chartAxisColor,\n  chartSplitLineColor,\n  chartTooltipBg,\n  chartTooltipBorder,\n  chartTooltipText,\n} from '@/components/ui/charts/useChartTheme'\nimport { RawChart } from '@/components/ui/charts'\n\nuse([EBar, EScatter, ELine, GridComponent, TooltipComponent, LegendComponent, MarkLineComponent])\n\n// Each route declares the per-partner volume (stack segments) + the\n// avg overlay value (dot on the right y-axis).\nconst partners = ['ALPHA', 'BETA', 'GAMMA', 'DELTA', 'EPSILON'] as const\ntype Partner = (typeof partners)[number]\n\ninterface Route {\n  id: string\n  label: string\n  volumes: Record<Partner, number>\n  overlay: number\n}\n\nconst routes: Route[] = [\n  {\n    id: 'r1',\n    label: 'NODE A → NODE B',\n    volumes: { ALPHA: 90, BETA: 25, GAMMA: 18, DELTA: 12, EPSILON: 8 },\n    overlay: 12,\n  },\n  {\n    id: 'r2',\n    label: 'NODE C → NODE D',\n    volumes: { ALPHA: 4, BETA: 100, GAMMA: 14, DELTA: 12, EPSILON: 24 },\n    overlay: 14.7,\n  },\n  {\n    id: 'r3',\n    label: 'NODE E → NODE F',\n    volumes: { ALPHA: 14, BETA: 38, GAMMA: 18, DELTA: 32, EPSILON: 28 },\n    overlay: 8,\n  },\n  { id: 'r4', label: 'NODE G → NODE H', volumes: { ALPHA: 130, BETA: 0, GAMMA: 0, DELTA: 0, EPSILON: 0 }, overlay: 6 },\n  { id: 'r5', label: 'NODE I → NODE J', volumes: { ALPHA: 0, BETA: 0, GAMMA: 60, DELTA: 0, EPSILON: 70 }, overlay: 17 },\n  { id: 'r6', label: 'NODE K → NODE L', volumes: { ALPHA: 60, BETA: 50, GAMMA: 16, DELTA: 0, EPSILON: 0 }, overlay: 8 },\n  { id: 'r7', label: 'NODE M → NODE N', volumes: { ALPHA: 70, BETA: 0, GAMMA: 0, DELTA: 0, EPSILON: 0 }, overlay: 22 },\n  { id: 'r8', label: 'NODE O → NODE P', volumes: { ALPHA: 0, BETA: 0, GAMMA: 0, DELTA: 0, EPSILON: 110 }, overlay: 29 },\n  { id: 'r9', label: 'NODE Q → NODE R', volumes: { ALPHA: 40, BETA: 0, GAMMA: 60, DELTA: 0, EPSILON: 0 }, overlay: 19 },\n  {\n    id: 'r10',\n    label: 'NODE S → NODE T',\n    volumes: { ALPHA: 60, BETA: 30, GAMMA: 0, DELTA: 0, EPSILON: 0 },\n    overlay: 23,\n  },\n]\n\n// Drill-down monthly series for a few partners. In a real app you'd\n// fetch this per-route on selection; the dummy block shows the same\n// shape regardless of which route is active.\nconst drillMonths = ['Mar 2026', 'Apr 2026', 'May 2026']\nconst drillSeries: Record<string, number[]> = {\n  ALPHA: [22, 25, 20],\n  GAMMA: [19, 17, 18],\n  EPSILON: [-1, 29, -1], // sparse point — left out of line by NaN-like handling\n}\n\nconst overviewMetric = ref<'overlay' | 'volume'>('overlay')\nconst activeRoute = ref<string | null>(null)\nconst drillView = ref<'Month' | 'Quarter'>('Month')\n\nconst overviewOption = computed(() => {\n  const x = routes.map((r) => r.label)\n  const stacks = partners.map((p, i) => ({\n    name: p,\n    type: 'bar' as const,\n    stack: 'vol',\n    barMaxWidth: 36,\n    emphasis: { focus: 'series' as const },\n    itemStyle: { color: chartColors.value[i % chartColors.value.length] },\n    data: routes.map((r) => r.volumes[p]),\n  }))\n  const overlay = {\n    name: 'Avg metric',\n    type: 'scatter' as const,\n    yAxisIndex: 1,\n    symbolSize: 12,\n    itemStyle: { color: chartColors.value[2], borderColor: 'var(--background)', borderWidth: 2 },\n    data: routes.map((r) => r.overlay),\n  }\n\n  return {\n    color: chartColors.value,\n    tooltip: {\n      trigger: 'axis',\n      axisPointer: { type: 'shadow' },\n      backgroundColor: chartTooltipBg.value,\n      borderColor: chartTooltipBorder.value,\n      textStyle: { color: chartTooltipText.value, fontSize: 12 },\n    },\n    legend: {\n      top: 8,\n      icon: 'circle',\n      itemWidth: 8,\n      itemHeight: 8,\n      textStyle: { color: chartTextColor.value, fontSize: 11 },\n    },\n    grid: { left: 56, right: 56, top: 42, bottom: 72, containLabel: false },\n    xAxis: {\n      type: 'category' as const,\n      data: x,\n      axisLine: { lineStyle: { color: chartAxisColor.value } },\n      axisLabel: {\n        interval: 0,\n        rotate: 35,\n        fontSize: 10,\n        color: chartTextColor.value,\n        formatter: (val: string) => val.replace(' → ', '\\n'),\n      },\n      axisTick: { show: false },\n    },\n    yAxis: [\n      {\n        type: 'value' as const,\n        name: 'Volume',\n        nameTextStyle: { color: chartTextColor.value, fontSize: 10 },\n        splitLine: { lineStyle: { color: chartSplitLineColor.value } },\n        axisLabel: { color: chartTextColor.value, fontSize: 10 },\n      },\n      {\n        type: 'value' as const,\n        name: 'Metric',\n        nameTextStyle: { color: chartTextColor.value, fontSize: 10 },\n        splitLine: { show: false },\n        axisLabel: { color: chartTextColor.value, fontSize: 10 },\n      },\n    ],\n    series: [...stacks, overlay],\n  }\n})\n\nconst drillOption = computed(() => {\n  const series = Object.entries(drillSeries).map(([name, values], i) => ({\n    name,\n    type: 'line' as const,\n    smooth: true,\n    symbolSize: 8,\n    connectNulls: false,\n    lineStyle: { width: 2, color: chartColors.value[i % chartColors.value.length] },\n    itemStyle: { color: chartColors.value[i % chartColors.value.length] },\n    data: values.map((v) => (v < 0 ? null : v)),\n  }))\n\n  return {\n    color: chartColors.value,\n    tooltip: {\n      trigger: 'axis',\n      backgroundColor: chartTooltipBg.value,\n      borderColor: chartTooltipBorder.value,\n      textStyle: { color: chartTooltipText.value, fontSize: 12 },\n    },\n    legend: {\n      top: 8,\n      icon: 'circle',\n      itemWidth: 8,\n      itemHeight: 8,\n      textStyle: { color: chartTextColor.value, fontSize: 11 },\n    },\n    grid: { left: 48, right: 24, top: 42, bottom: 48, containLabel: false },\n    xAxis: {\n      type: 'category' as const,\n      data: drillMonths,\n      boundaryGap: false,\n      axisLine: { lineStyle: { color: chartAxisColor.value } },\n      axisLabel: { color: chartTextColor.value, fontSize: 11 },\n      axisTick: { show: false },\n    },\n    yAxis: {\n      type: 'value' as const,\n      splitLine: { lineStyle: { color: chartSplitLineColor.value } },\n      axisLabel: { color: chartTextColor.value, fontSize: 11, formatter: (v: number) => `${v}d` },\n    },\n    series,\n  }\n})\n\nconst activeLabel = computed(() => routes.find((r) => r.id === activeRoute.value)?.label ?? null)\n\nfunction onOverviewClick(params: any) {\n  if (!params?.name) return\n  const r = routes.find((rt) => rt.label === params.name)\n  if (r) activeRoute.value = r.id\n}\n\nfunction resetDrill() {\n  activeRoute.value = null\n}\n</script>\n\n<template>\n  <div class=\"space-y-6\">\n    <!-- Overview pane -->\n    <section class=\"bg-card border-border rounded-lg border p-5\">\n      <div class=\"mb-3 flex items-start justify-between gap-4\">\n        <div>\n          <h2 class=\"text-[15px] font-semibold tracking-tight text-[var(--accent-tint)]\">Overview</h2>\n          <p class=\"text-muted-foreground mt-1 text-xs\">\n            <span class=\"text-foreground font-medium\">Metric</span> measures the avg performance signal aggregated per\n            route.\n          </p>\n        </div>\n        <div class=\"text-muted-foreground text-xs\">\n          <span>Performance Metric:</span>\n          <select\n            v-model=\"overviewMetric\"\n            class=\"border-border text-foreground ml-2 rounded-md border bg-transparent px-2 py-1 font-medium\"\n          >\n            <option value=\"overlay\">Avg metric</option>\n            <option value=\"volume\">Total volume</option>\n          </select>\n        </div>\n      </div>\n      <RawChart :option=\"overviewOption\" height=\"320\" @click=\"onOverviewClick\" />\n      <p class=\"text-muted-foreground mt-2 text-[11px]\">Click a bar to drill into that route's monthly trend.</p>\n    </section>\n\n    <!-- Drill-down pane -->\n    <section class=\"bg-card border-border rounded-lg border p-5\">\n      <div class=\"mb-3 flex items-center justify-between gap-4\">\n        <div class=\"flex items-center gap-3\">\n          <h3 class=\"text-[15px] font-semibold tracking-tight\">\n            <template v-if=\"activeLabel\">\n              <span class=\"text-muted-foreground font-normal\">Drill-down:</span>\n              <span class=\"text-foreground ml-1\">{{ activeLabel }}</span>\n            </template>\n            <span v-else class=\"text-muted-foreground font-normal\">Select a route above to drill in</span>\n          </h3>\n          <button\n            v-if=\"activeRoute\"\n            type=\"button\"\n            class=\"border-border text-muted-foreground hover:text-foreground rounded-md border px-2 py-1 font-mono text-[11px] transition hover:border-[var(--accent-tint-soft)]\"\n            @click=\"resetDrill\"\n          >\n            ← Back to Overview\n          </button>\n        </div>\n        <div class=\"text-muted-foreground text-xs\">\n          <span>View By:</span>\n          <select\n            v-model=\"drillView\"\n            class=\"border-border text-foreground ml-2 rounded-md border bg-transparent px-2 py-1 font-medium\"\n          >\n            <option value=\"Month\">Month</option>\n            <option value=\"Quarter\">Quarter</option>\n          </select>\n        </div>\n      </div>\n      <RawChart v-if=\"activeRoute\" :option=\"drillOption\" height=\"280\" />\n      <div\n        v-else\n        class=\"text-muted-foreground border-border grid h-[260px] place-items-center rounded-md border border-dashed text-xs\"\n      >\n        No route selected. Click a bar above.\n      </div>\n    </section>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/AnalyticsOverview.vue"
    }
  ],
  "dependencies": [
    "echarts",
    "vue-echarts"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/raw-chart.json"
  ],
  "description": "Two-pane analytics dashboard: stacked bar with dot overlay on a dual y-axis above, and an interactive drill-down line chart below. Click a bar to filter the bottom pane to that route.",
  "categories": [
    "dashboard",
    "analytics"
  ]
}