{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "sales-territory-map",
  "title": "Sales Territory Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/sales-territory-map/SalesTerritoryMap.vue",
      "content": "<script lang=\"ts\">\nexport interface SalesTerritory {\n  id: string\n  name: string\n  code: string\n  arr: string\n  attainment: number\n  status: 'attained' | 'ontrack' | 'attention'\n  centerLngLat: [number, number]\n}\n\nexport const DEFAULT_TERRITORIES: SalesTerritory[] = [\n  {\n    id: 'na-enterprise',\n    name: 'North America',\n    code: 'NA-ENT',\n    arr: '$6.4M',\n    attainment: 111,\n    status: 'attained',\n    centerLngLat: [-98.5, 39.8],\n  },\n  {\n    id: 'emea-central',\n    name: 'EMEA Central',\n    code: 'EMEA-C',\n    arr: '$5.8M',\n    attainment: 124,\n    status: 'attained',\n    centerLngLat: [10.4, 51.1],\n  },\n  {\n    id: 'apac-growth',\n    name: 'APAC Growth',\n    code: 'APAC-G',\n    arr: '$4.1M',\n    attainment: 94,\n    status: 'ontrack',\n    centerLngLat: [120.0, 30.0],\n  },\n  {\n    id: 'latam-emerging',\n    name: 'Latin America',\n    code: 'LATAM-E',\n    arr: '$2.1M',\n    attainment: 83,\n    status: 'attention',\n    centerLngLat: [-55.0, -14.0],\n  },\n]\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Map, MapMarker } from '@/components/ui/map'\n\nconst props = withDefaults(\n  defineProps<{\n    territories?: SalesTerritory[]\n    accessToken?: string\n    class?: string\n  }>(),\n  {\n    territories: () => DEFAULT_TERRITORIES,\n    accessToken: '',\n  },\n)\n\nconst selectedId = ref(props.territories[0]?.id ?? '')\nconst selected = computed(() => props.territories.find((t) => t.id === selectedId.value) ?? props.territories[0])\n\nlet mapboxInstance: any = null\nfunction fitTerritories(map: any) {\n  const coords = props.territories.map((t) => t.centerLngLat)\n  if (coords.length < 2) return\n  const lons = coords.map((c) => c[0])\n  const lats = coords.map((c) => c[1])\n  try {\n    map.fitBounds(\n      [\n        [Math.min(...lons), Math.min(...lats)],\n        [Math.max(...lons), Math.max(...lats)],\n      ],\n      { padding: { top: 48, bottom: 48, left: 80, right: 80 }, duration: 0, maxZoom: 1.8 },\n    )\n  } catch {\n    /* map not ready */\n  }\n}\n\nfunction onMapCreated(map: any) {\n  mapboxInstance = map\n  if (typeof map.loaded === 'function' && map.loaded()) fitTerritories(map)\n  else map.once?.('load', () => fitTerritories(map))\n}\n\nfunction selectTerritory(territory: SalesTerritory) {\n  selectedId.value = territory.id\n  mapboxInstance?.flyTo?.({\n    center: territory.centerLngLat,\n    zoom: 2.8,\n    essential: true,\n    duration: 800,\n  })\n}\n\nfunction statusVariant(status: SalesTerritory['status']) {\n  if (status === 'attained') return 'info'\n  if (status === 'ontrack') return 'secondary'\n  return 'warning'\n}\n</script>\n\n<template>\n  <div data-slot=\"sales-territory-map\" :class=\"cn('flex h-full min-h-0 flex-col gap-4', props.class)\">\n    <div class=\"flex flex-wrap items-center justify-between gap-3\">\n      <h2 class=\"text-foreground text-lg font-semibold tracking-tight\">Territories</h2>\n      <p class=\"text-muted-foreground text-xs\">{{ territories.length }} regions</p>\n    </div>\n\n    <div class=\"grid min-h-0 flex-1 grid-cols-1 gap-4 lg:grid-cols-12\">\n      <Card class=\"border-border flex min-h-0 flex-col overflow-hidden shadow-xs lg:col-span-8\">\n        <div class=\"relative min-h-[360px] flex-1 overflow-hidden\">\n          <Map\n            :access-token=\"accessToken\"\n            variant=\"dark\"\n            :center=\"[15, 20]\"\n            :zoom=\"1.2\"\n            class=\"absolute inset-0 size-full\"\n            @created=\"onMapCreated\"\n          >\n            <MapMarker v-for=\"t in territories\" :key=\"t.id\" :lng-lat=\"t.centerLngLat\" anchor=\"center\">\n              <button\n                type=\"button\"\n                class=\"rounded-full border px-2 py-0.5 font-mono text-xs font-semibold shadow-xs\"\n                :class=\"\n                  selectedId === t.id\n                    ? 'border-primary bg-primary text-primary-foreground'\n                    : 'border-border bg-card text-foreground'\n                \"\n                @click.stop=\"selectTerritory(t)\"\n              >\n                {{ t.code }} {{ t.attainment }}%\n              </button>\n            </MapMarker>\n          </Map>\n        </div>\n      </Card>\n\n      <Card class=\"border-border flex min-h-0 flex-col overflow-hidden shadow-xs lg:col-span-4\">\n        <CardHeader class=\"border-border border-b p-4\">\n          <CardTitle class=\"text-sm font-semibold\">Quota</CardTitle>\n        </CardHeader>\n        <CardContent class=\"divide-border min-h-0 flex-1 divide-y overflow-auto p-0\">\n          <button\n            v-for=\"t in territories\"\n            :key=\"t.id\"\n            type=\"button\"\n            :class=\"\n              cn(\n                'hover:bg-accent/50 flex w-full items-center justify-between gap-3 px-4 py-3 text-left transition-colors',\n                selectedId === t.id && 'bg-accent/60',\n              )\n            \"\n            @click=\"selectTerritory(t)\"\n          >\n            <div class=\"min-w-0\">\n              <p class=\"text-foreground truncate text-sm font-medium\">{{ t.code }} · {{ t.name }}</p>\n              <p class=\"text-muted-foreground font-mono text-xs tabular-nums\">{{ t.arr }}</p>\n            </div>\n            <Badge :variant=\"statusVariant(t.status)\" class=\"shrink-0 text-xs tabular-nums\">{{ t.attainment }}%</Badge>\n          </button>\n        </CardContent>\n      </Card>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/SalesTerritoryMap.vue"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/map.json"
  ],
  "description": "Sales territory map. Region pins with quota attainment; select a territory to fly the camera.",
  "categories": [
    "analytics",
    "dashboard"
  ]
}