{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "leaflet-disaster-response-map",
  "title": "Leaflet Disaster Response Map",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/leaflet-disaster-response-map/LeafletDisasterResponseMap.vue",
      "content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { computed, ref } from 'vue'\nimport { cn } from '@/lib/utils'\nimport { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { LeafletMap, LeafletMarker, LeafletCircle, type LeafletMapRef } from '@/components/ui/leaflet-map'\n\nexport type FacilityType = 'Shelter' | 'Medical Staging' | 'Command Post'\nexport type FacilityStatus = 'Open' | 'Near Capacity' | 'Closed'\n\nexport interface Facility {\n  id: string\n  name: string\n  type: FacilityType\n  /** [lng, lat] — Mapbox order. */\n  coords: [number, number]\n  capacity: number\n  occupied: number\n  status: FacilityStatus\n}\n\nexport interface LeafletDisasterResponseMapProps {\n  class?: HTMLAttributes['class']\n  facilities?: Facility[]\n}\n\nconst props = defineProps<LeafletDisasterResponseMapProps>()\n\n// Module-level constants: stable references keep LeafletMap's `center` watcher\n// from re-firing setView on every re-render and cancelling flyTo animations.\nconst MAP_CENTER: [number, number] = [-122.2711, 37.8044]\n\n// Wildfire incident origin in the Oakland Hills + a secondary spot fire.\nconst INCIDENT: [number, number] = [-122.165, 37.845]\nconst SPOT_FIRE: [number, number] = [-122.145, 37.856]\n\n// Evacuation perimeter rings (meter radii): hard exclusion + warning zone.\nconst EVAC_RADIUS_M = 1800\nconst WARNING_RADIUS_M = 3600\n\nconst DEFAULT_FACILITIES: Facility[] = [\n  {\n    id: 's-1',\n    name: 'Oakland Civic Shelter',\n    type: 'Shelter',\n    coords: [-122.265, 37.795],\n    capacity: 500,\n    occupied: 340,\n    status: 'Open',\n  },\n  {\n    id: 's-2',\n    name: 'Eastmont Medical Staging',\n    type: 'Medical Staging',\n    coords: [-122.19, 37.77],\n    capacity: 120,\n    occupied: 98,\n    status: 'Near Capacity',\n  },\n  {\n    id: 's-3',\n    name: 'Unified Incident Command Post',\n    type: 'Command Post',\n    coords: [-122.225, 37.852],\n    capacity: 80,\n    occupied: 45,\n    status: 'Open',\n  },\n]\n\nconst facilities = computed(() => props.facilities ?? DEFAULT_FACILITIES)\nconst activeId = ref(DEFAULT_FACILITIES[0]?.id ?? '')\nconst activeFacility = computed(() => facilities.value.find((f) => f.id === activeId.value) ?? facilities.value[0])\n\nconst mapRef = ref<LeafletMapRef | null>(null)\n\nfunction focusFacility(f: Facility) {\n  activeId.value = f.id\n  mapRef.value?.flyTo?.({ center: f.coords, zoom: 12.5, duration: 800 })\n}\n\nfunction focusHazard() {\n  mapRef.value?.flyTo?.({ center: INCIDENT, zoom: 12, duration: 800 })\n}\n</script>\n\n<template>\n  <div data-slot=\"leaflet-disaster-response-map\" :class=\"cn('grid gap-4 lg:grid-cols-[1fr_320px]', props.class)\">\n    <div class=\"border-border bg-card relative h-[480px] overflow-hidden rounded-xl border\">\n      <LeafletMap ref=\"mapRef\" variant=\"light\" :center=\"MAP_CENTER\" :zoom=\"11\" class=\"h-full w-full\">\n        <!-- Evacuation perimeter rings (radii in meters) -->\n        <LeafletCircle\n          :center=\"INCIDENT\"\n          :radius=\"EVAC_RADIUS_M\"\n          color=\"#dc2626\"\n          :weight=\"2\"\n          :opacity=\"0.9\"\n          dash-array=\"6 4\"\n          fill-color=\"#ef4444\"\n          :fill-opacity=\"0.15\"\n          @click=\"focusHazard\"\n        />\n        <LeafletCircle\n          :center=\"INCIDENT\"\n          :radius=\"WARNING_RADIUS_M\"\n          color=\"#d97706\"\n          :weight=\"1.5\"\n          :opacity=\"0.7\"\n          dash-array=\"4 6\"\n          fill-color=\"#f59e0b\"\n          :fill-opacity=\"0.05\"\n        />\n\n        <!-- Active fire origin -->\n        <LeafletMarker :lng-lat=\"INCIDENT\" anchor=\"center\" @click=\"focusHazard\">\n          <div class=\"relative flex cursor-pointer items-center justify-center\">\n            <span class=\"bg-destructive/30 absolute size-9 animate-ping rounded-full\" />\n            <div\n              class=\"bg-destructive flex size-7 items-center justify-center rounded-full font-mono text-xs font-bold text-white shadow-lg ring-2 ring-white\"\n            >\n              🔥\n            </div>\n          </div>\n        </LeafletMarker>\n\n        <!-- Secondary spot fire -->\n        <LeafletMarker :lng-lat=\"SPOT_FIRE\" anchor=\"center\" @click=\"focusHazard\">\n          <div class=\"relative flex cursor-pointer items-center justify-center\">\n            <span class=\"bg-warning/30 absolute size-6 animate-ping rounded-full\" />\n            <div\n              class=\"bg-warning flex size-6 items-center justify-center rounded-full font-mono text-xs font-bold text-white shadow-md ring-2 ring-white\"\n            >\n              🔥\n            </div>\n          </div>\n        </LeafletMarker>\n\n        <!-- Shelters and Medical Staging -->\n        <LeafletMarker\n          v-for=\"f in facilities\"\n          :key=\"f.id\"\n          :lng-lat=\"f.coords\"\n          anchor=\"bottom\"\n          @click=\"focusFacility(f)\"\n        >\n          <div class=\"group flex cursor-pointer flex-col items-center\">\n            <div\n              class=\"flex size-7 items-center justify-center rounded-full shadow-md ring-2\"\n              :class=\"\n                f.type === 'Shelter'\n                  ? 'bg-success text-white ring-emerald-400/40'\n                  : f.type === 'Medical Staging'\n                    ? 'bg-info text-white ring-blue-400/40'\n                    : 'bg-primary text-primary-foreground ring-primary/40'\n              \"\n            >\n              {{ f.type === 'Shelter' ? '🏠' : f.type === 'Medical Staging' ? '✚' : '★' }}\n            </div>\n            <span\n              class=\"border-border bg-background/90 mt-1 rounded border px-1 py-0.5 font-mono text-xs font-bold whitespace-nowrap shadow-xs\"\n            >\n              {{ f.name.split(' ')[0] }}\n            </span>\n          </div>\n        </LeafletMarker>\n      </LeafletMap>\n    </div>\n\n    <!-- Incident Control Dashboard -->\n    <Card class=\"flex flex-col justify-between\">\n      <CardHeader>\n        <div class=\"flex items-center justify-between\">\n          <Badge variant=\"outline\" class=\"border-destructive/30 bg-destructive/10 text-destructive font-mono text-xs\"\n            >LEVEL 3 EVACUATION</Badge\n          >\n          <Badge class=\"border-success/20 bg-success/10 text-success\">{{ activeFacility.status }}</Badge>\n        </div>\n        <CardTitle class=\"mt-2 text-lg\">{{ activeFacility.name }}</CardTitle>\n        <CardDescription class=\"text-xs\"\n          >Capacity: {{ activeFacility.occupied }} / {{ activeFacility.capacity }} beds occupied</CardDescription\n        >\n      </CardHeader>\n      <CardContent class=\"space-y-4\">\n        <!-- Capacity Bar -->\n        <div class=\"border-border space-y-1.5 border-t pt-3\">\n          <div class=\"flex items-center justify-between font-mono text-xs\">\n            <span class=\"text-muted-foreground\">Occupancy Rate</span>\n            <span class=\"text-foreground font-bold\"\n              >{{ Math.round((activeFacility.occupied / activeFacility.capacity) * 100) }}%</span\n            >\n          </div>\n          <div class=\"bg-muted h-2 w-full overflow-hidden rounded-full\">\n            <div\n              class=\"h-full rounded-full transition-[width,background-color]\"\n              :class=\"activeFacility.occupied / activeFacility.capacity > 0.8 ? 'bg-warning' : 'bg-success'\"\n              :style=\"{ width: `${(activeFacility.occupied / activeFacility.capacity) * 100}%` }\"\n            />\n          </div>\n        </div>\n\n        <div class=\"border-border space-y-1 border-t pt-3\">\n          <div class=\"text-muted-foreground mb-1 font-mono text-xs tracking-wider uppercase\">Staged Relief Sites</div>\n          <button\n            v-for=\"f in facilities\"\n            :key=\"f.id\"\n            type=\"button\"\n            class=\"flex w-full items-center justify-between rounded-md px-2 py-1 text-xs transition-colors\"\n            :class=\"\n              activeId === f.id\n                ? 'bg-accent text-accent-foreground font-semibold'\n                : 'hover:bg-muted text-muted-foreground'\n            \"\n            @click=\"focusFacility(f)\"\n          >\n            <span class=\"max-w-[170px] truncate\">{{ f.name }}</span>\n            <span class=\"font-mono text-xs opacity-75\">{{ f.occupied }}/{{ f.capacity }}</span>\n          </button>\n        </div>\n\n        <div class=\"flex gap-2 pt-2\">\n          <Button variant=\"outline\" size=\"sm\" class=\"flex-1 font-mono text-xs\" @click=\"focusHazard\">\n            Exclusion Zone\n          </Button>\n          <Button variant=\"outline\" size=\"sm\" class=\"flex-1 font-mono text-xs\" @click=\"focusFacility(activeFacility)\">\n            Focus Site\n          </Button>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/LeafletDisasterResponseMap.vue"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/card.json",
    "https://uipkge.dev/r/vue/leaflet-map.json"
  ],
  "description": "Incident management map on free OpenStreetMap/Esri tiles — no API key. Evacuation perimeter rings, shelter capacities, and emergency staging points.",
  "categories": [
    "logistics",
    "emergency",
    "map"
  ]
}