{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "map-timeline-01",
  "title": "Play a timeline example",
  "description": "Play or drag a time slider to add sample bike-share docks to Calgary year by year, composed from the Unmap map, the geojson-layer and time-slider items and your Card.",
  "registryDependencies": [
    "https://registry.unmap.dev/r/map.json",
    "https://registry.unmap.dev/r/geojson-layer.json",
    "https://registry.unmap.dev/r/time-slider.json",
    "card"
  ],
  "files": [
    {
      "path": "registry/blocks/map-timeline-01.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { Map } from \"@/components/ui/map\";\nimport { GeoJSONLayer } from \"@/components/ui/geojson-layer\";\nimport { TimeSlider, type TimeSliderValue } from \"@/components/ui/time-slider\";\nimport { Card, CardContent } from \"@/components/ui/card\";\nimport { cn } from \"@/lib/utils\";\n\nconst COPY = {\n  en: {\n    noKey: \"Add your unmap key to load the map.\",\n    title: \"Bike-share docks by year\",\n    hint: \"Press play or drag the slider to add docks year by year.\",\n    result: (count: number, year: number) => `${count} docks by ${year}`,\n  },\n  fr: {\n    noKey: \"Ajoutez votre clé unmap pour charger la carte.\",\n    title: \"Stations de vélopartage par année\",\n    hint: \"Lancez la lecture ou faites glisser le curseur pour ajouter les stations année par année.\",\n    result: (count: number, year: number) => `${count} stations en service en ${year}`,\n  },\n} as const;\n\nconst FIRST_YEAR = 2019;\nconst LAST_YEAR = 2025;\n\n/**\n * Sample data, not a real network: 24 bike-share docks in Calgary's inner city, each with the year\n * it opened. The places are real; the docks and years are made up. They sit about 300 m apart\n * inside the part of the map that stays clear of the slider, at every width.\n */\nconst DOCKS: [string, number, number, number][] = [\n  [\"Stephen Avenue\", -114.066, 51.0465, 2019],\n  [\"Eau Claire\", -114.071, 51.054, 2019],\n  [\"Beltline\", -114.072, 51.041, 2019],\n  [\"East Village\", -114.052, 51.046, 2019],\n  [\"Chinatown\", -114.063, 51.051, 2020],\n  [\"Downtown West End\", -114.084, 51.049, 2020],\n  [\"Mission\", -114.068, 51.037, 2020],\n  [\"Victoria Park\", -114.059, 51.04, 2020],\n  [\"Connaught\", -114.083, 51.041, 2021],\n  [\"Bridgeland\", -114.046, 51.054, 2021],\n  [\"Inglewood\", -114.044, 51.039, 2021],\n  [\"Hillhurst\", -114.086, 51.055, 2022],\n  [\"Sunnyside\", -114.077, 51.057, 2022],\n  [\"Prince's Island\", -114.069, 51.0565, 2022],\n  [\"Crescent Heights\", -114.062, 51.059, 2023],\n  [\"Calgary Tower\", -114.0631, 51.0442, 2023],\n  [\"Olympic Plaza\", -114.0575, 51.0457, 2023],\n  [\"Central Library\", -114.0545, 51.049, 2023],\n  [\"Kensington Road\", -114.087, 51.0525, 2024],\n  [\"Memorial Park\", -114.0715, 51.0385, 2024],\n  [\"Stampede Park\", -114.054, 51.037, 2024],\n  [\"Riverfront\", -114.0565, 51.0525, 2025],\n  [\"Fort Calgary\", -114.0455, 51.0455, 2025],\n  [\"Cliff Bungalow\", -114.077, 51.0365, 2025],\n];\n\nconst DATA = {\n  type: \"FeatureCollection\" as const,\n  features: DOCKS.map(([name, lng, lat, year]) => ({\n    type: \"Feature\" as const,\n    properties: { name, year },\n    geometry: { type: \"Point\" as const, coordinates: [lng, lat] },\n  })),\n};\n\n/** The year a slider value ends on: the value itself, or the end of a range. */\nfunction yearOf(value: TimeSliderValue): number {\n  return typeof value === \"number\" ? value : value[1];\n}\n\n/**\n * A minimal example: sample bike-share docks on a map of Calgary, added year by year as the\n * slider plays or moves. Filtering happens in the browser: the only requests are the map's own.\n */\nexport function MapTimeline({\n  apiKey,\n  lang = \"en\",\n  className,\n}: {\n  /** Your Unmap browser key. */\n  apiKey: string;\n  /** Language of the copy, the slider and the map labels: \"en\" (default) or \"fr\". */\n  lang?: \"en\" | \"fr\";\n  className?: string;\n}) {\n  const copy = COPY[lang];\n  const [year, setYear] = useState(FIRST_YEAR);\n  const [moved, setMoved] = useState(false);\n  const count = DOCKS.filter((dock) => dock[3] <= year).length;\n\n  return (\n    <div className={cn(\"flex min-w-0 flex-col gap-3\", className)}>\n      <div role=\"region\" aria-label={copy.title} className=\"relative h-96\">\n        <Map apiKey={apiKey} center={[-114.065, 51.04]} zoom={12} lang={lang}>\n          <GeoJSONLayer id=\"docks\" data={DATA} />\n          {/* Above the attribution, across the bottom on a phone, at the left on a wider screen. */}\n          <Card size=\"sm\" className=\"absolute inset-x-3 bottom-10 z-10 sm:right-auto sm:w-80\">\n            <CardContent>\n              <TimeSlider\n                layers={[\"docks-*\"]}\n                property=\"year\"\n                min={FIRST_YEAR}\n                max={LAST_YEAR}\n                value={year}\n                onValueChange={(value) => {\n                  setYear(yearOf(value));\n                  setMoved(true);\n                }}\n                cumulative\n                interval={800}\n                lang={lang}\n              />\n            </CardContent>\n          </Card>\n        </Map>\n      </div>\n      {/* No key, no map: one line says what to add. */}\n      {apiKey.trim() === \"\" ? <p className=\"text-xs text-muted-foreground\">{copy.noKey}</p> : null}\n      <p aria-live=\"polite\" className=\"text-sm text-muted-foreground tabular-nums\">\n        {moved ? <span className=\"font-medium text-foreground\">{copy.result(count, year)}</span> : copy.hint}\n      </p>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/unmap-map-timeline.tsx"
    }
  ],
  "docs": "Import MapTimeline from your components/unmap-map-timeline file and pass apiKey (your Unmap browser key). Use lang=\"fr\" for French. Allow your site origin on the key. Preview: https://unmap.dev/templates/map-timeline",
  "categories": [
    "examples",
    "maps"
  ],
  "type": "registry:block"
}