{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "cost-breakdown",
  "title": "Cost Breakdown",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/cost-breakdown/CostBreakdown.vue",
      "content": "<script setup lang=\"ts\">\n// Three-panel cost breakdown: a stacked-by-week bar over time on top,\n// and two side-by-side categorical pie charts below (cost share by\n// lane + by carrier). The patterns repeat across spend dashboards;\n// swap `weeklySeries`, `byLane`, and `byCarrier` to repoint.\n//\n// All three panels are theme-aware: bar colors come from\n// chartColors via the wrappers; pies surface inline value labels so\n// the panels read at a glance without leaning on the legend alone.\nimport { computed } from 'vue'\nimport { BarChart, PieChart } from '@/components/ui/charts'\n\ninterface WeekRow {\n  week: string\n  detentionOrigin: number\n  combinedDndOrigin: number\n  demurrageOrigin: number\n  detentionDest: number\n  demurrageDest: number\n  combinedDndDest: number\n}\n\n// 17 weeks of cost data. Heavy spike in mid-Feb mirrors a closing\n// quarter cleanup or a port-disruption incident.\nconst weeklySeries: WeekRow[] = [\n  {\n    week: 'Jan 26 - Feb 1',\n    detentionOrigin: 2800,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 0,\n    detentionDest: 0,\n    demurrageDest: 0,\n    combinedDndDest: 0,\n  },\n  {\n    week: 'Feb 2 - Feb 8',\n    detentionOrigin: 1100,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 0,\n    detentionDest: 0,\n    demurrageDest: 0,\n    combinedDndDest: 0,\n  },\n  {\n    week: 'Feb 9 - Feb 15',\n    detentionOrigin: 1800,\n    combinedDndOrigin: 3100,\n    demurrageOrigin: 800,\n    detentionDest: 1800,\n    demurrageDest: 4300,\n    combinedDndDest: 1100,\n  },\n  {\n    week: 'Feb 16 - Feb 22',\n    detentionOrigin: 0,\n    combinedDndOrigin: 22000,\n    demurrageOrigin: 12500,\n    detentionDest: 0,\n    demurrageDest: 1900,\n    combinedDndDest: 35500,\n  },\n  {\n    week: 'Feb 23 - Mar 1',\n    detentionOrigin: 0,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 3300,\n    detentionDest: 800,\n    demurrageDest: 6800,\n    combinedDndDest: 4400,\n  },\n  {\n    week: 'Mar 2 - Mar 8',\n    detentionOrigin: 2400,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 6400,\n    detentionDest: 1200,\n    demurrageDest: 2800,\n    combinedDndDest: 6600,\n  },\n  {\n    week: 'Mar 9 - Mar 15',\n    detentionOrigin: 0,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 600,\n    detentionDest: 1300,\n    demurrageDest: 5300,\n    combinedDndDest: 5400,\n  },\n  {\n    week: 'Mar 16 - Mar 22',\n    detentionOrigin: 5400,\n    combinedDndOrigin: 0,\n    demurrageOrigin: 6000,\n    detentionDest: 600,\n    demurrageDest: 4200,\n    combinedDndDest: 1400,\n  },\n  {\n    week: 'Mar 23 - Mar 29',\n    detentionOrigin: 0,\n    combinedDndOrigin: 11000,\n    demurrageOrigin: 4900,\n    detentionDest: 0,\n    demurrageDest: 4300,\n    combinedDndDest: 2200,\n  },\n  {\n    week: 'Mar 30 - Apr 5',\n    detentionOrigin: 7700,\n    combinedDndOrigin: 14000,\n    demurrageOrigin: 5400,\n    detentionDest: 1700,\n    demurrageDest: 6300,\n    combinedDndDest: 7200,\n  },\n  {\n    week: 'Apr 6 - Apr 12',\n    detentionOrigin: 1200,\n    combinedDndOrigin: 3100,\n    demurrageOrigin: 1500,\n    detentionDest: 0,\n    demurrageDest: 4800,\n    combinedDndDest: 6300,\n  },\n  {\n    week: 'Apr 13 - Apr 19',\n    detentionOrigin: 0,\n    combinedDndOrigin: 3300,\n    demurrageOrigin: 3200,\n    detentionDest: 3500,\n    demurrageDest: 5000,\n    combinedDndDest: 5700,\n  },\n  {\n    week: 'Apr 20 - Apr 26',\n    detentionOrigin: 1700,\n    combinedDndOrigin: 5300,\n    demurrageOrigin: 2500,\n    detentionDest: 600,\n    demurrageDest: 3800,\n    combinedDndDest: 4800,\n  },\n  {\n    week: 'Apr 27 - May 3',\n    detentionOrigin: 6000,\n    combinedDndOrigin: 15000,\n    demurrageOrigin: 5500,\n    detentionDest: 600,\n    demurrageDest: 800,\n    combinedDndDest: 2400,\n  },\n  {\n    week: 'May 4 - May 10',\n    detentionOrigin: 1900,\n    combinedDndOrigin: 2200,\n    demurrageOrigin: 3300,\n    detentionDest: 3500,\n    demurrageDest: 3700,\n    combinedDndDest: 1100,\n  },\n  {\n    week: 'May 11 - May 17',\n    detentionOrigin: 1900,\n    combinedDndOrigin: 1200,\n    demurrageOrigin: 800,\n    detentionDest: 700,\n    demurrageDest: 600,\n    combinedDndDest: 1200,\n  },\n]\n\nconst stackKeys = [\n  { key: 'detentionOrigin', label: 'Detention at origin' },\n  { key: 'combinedDndOrigin', label: 'Combined at origin' },\n  { key: 'demurrageOrigin', label: 'Demurrage at origin' },\n  { key: 'detentionDest', label: 'Detention at destination' },\n  { key: 'demurrageDest', label: 'Demurrage at destination' },\n  { key: 'combinedDndDest', label: 'Combined at destination' },\n] as const\n\nconst stackedOption = computed(() => ({\n  series: stackKeys.map(() => ({ stack: 'total' as const })),\n  yAxis: {\n    type: 'value' as const,\n    axisLabel: { formatter: (v: number) => (v >= 1000 ? `$${Math.round(v / 1000)}K` : `$${v}`) },\n  },\n}))\n\nconst byLane = [\n  { name: 'LANE-01', value: 119800 },\n  { name: 'LANE-02', value: 39000 },\n  { name: 'LANE-03', value: 53100 },\n  { name: 'LANE-04', value: 32000 },\n  { name: 'LANE-05', value: 24700 },\n  { name: 'LANE-06', value: 23500 },\n  { name: 'LANE-07', value: 20300 },\n  { name: 'LANE-08', value: 18300 },\n  { name: 'LANE-09', value: 14700 },\n  { name: 'OTHER', value: 8100 },\n]\n\nconst byCarrier = [\n  { name: 'C-ALPHA', value: 144200 },\n  { name: 'C-BETA', value: 69800 },\n  { name: 'C-GAMMA', value: 32700 },\n  { name: 'C-DELTA', value: 31800 },\n  { name: 'C-EPSILON', value: 27800 },\n  { name: 'C-ZETA', value: 22600 },\n  { name: 'OTHER', value: 10100 },\n]\n\nconst totalAll = computed(() =>\n  weeklySeries.reduce(\n    (acc, w) =>\n      acc +\n      w.detentionOrigin +\n      w.combinedDndOrigin +\n      w.demurrageOrigin +\n      w.detentionDest +\n      w.demurrageDest +\n      w.combinedDndDest,\n    0,\n  ),\n)\n\nconst pieOption = {\n  legend: { show: false },\n  series: [\n    {\n      radius: ['0%', '70%'],\n      label: {\n        show: true,\n        formatter: (p: any) => `$${(p.value / 1000).toFixed(1)}k\\n(${p.percent}%)`,\n        fontSize: 10,\n        color: 'var(--background)',\n      },\n      labelLine: { show: false },\n    },\n  ],\n}\n\nconst fmtUsd = (n: number) => `$${(n / 1000).toFixed(1)}k`\n</script>\n\n<template>\n  <div class=\"space-y-6\">\n    <!-- Weekly trend (top) -->\n    <section class=\"bg-card border-border rounded-lg border p-5\">\n      <div class=\"mb-3 flex items-baseline justify-between gap-4\">\n        <div>\n          <h3 class=\"text-[15px] font-semibold tracking-tight\">Cost per day</h3>\n          <p class=\"text-muted-foreground mt-0.5 text-xs\">17-week rollup. Hover a stack to inspect the breakdown.</p>\n        </div>\n        <div class=\"text-right\">\n          <div class=\"text-muted-foreground font-mono text-xs tracking-wider uppercase\">Total</div>\n          <div class=\"text-lg font-semibold tabular-nums\">{{ fmtUsd(totalAll) }}</div>\n        </div>\n      </div>\n      <BarChart\n        :data=\"weeklySeries\"\n        x-field=\"week\"\n        :y-field=\"[\n          'detentionOrigin',\n          'combinedDndOrigin',\n          'demurrageOrigin',\n          'detentionDest',\n          'demurrageDest',\n          'combinedDndDest',\n        ]\"\n        :option=\"stackedOption\"\n        height=\"320\"\n      />\n    </section>\n\n    <!-- Dual pie breakdown (bottom) -->\n    <div class=\"grid gap-6 lg:grid-cols-2\">\n      <section class=\"bg-card border-border rounded-lg border p-5\">\n        <h3 class=\"text-[15px] font-semibold tracking-tight\">Cost share by lane</h3>\n        <p class=\"text-muted-foreground mt-0.5 mb-4 text-xs\">Top 9 lanes + a grouped 'Other' bucket.</p>\n        <PieChart :data=\"byLane\" :option=\"pieOption\" height=\"320\" />\n      </section>\n\n      <section class=\"bg-card border-border rounded-lg border p-5\">\n        <h3 class=\"text-[15px] font-semibold tracking-tight\">Cost share by carrier</h3>\n        <p class=\"text-muted-foreground mt-0.5 mb-4 text-xs\">Top 6 carriers + a grouped 'Other' bucket.</p>\n        <PieChart :data=\"byCarrier\" :option=\"pieOption\" height=\"320\" />\n      </section>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/CostBreakdown.vue"
    }
  ],
  "dependencies": [
    "echarts",
    "vue-echarts"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/bar-chart.json",
    "https://uipkge.dev/r/vue/pie-chart.json"
  ],
  "description": "Three-panel spend dashboard. Stacked weekly bar chart over time on top, plus two side-by-side categorical pies below (share by lane / share by carrier). Theme-aware via registry tokens.",
  "categories": [
    "dashboard",
    "analytics"
  ]
}