| |
| |
| |
| |
|
|
| import React, { useEffect, useState } from 'react' |
| import { motion } from 'framer-motion' |
| import styles from './RangeMap.module.css' |
|
|
| export default function RangeMap({ range, commonName, color }) { |
| const [ready, setReady] = useState(false) |
| const [MapContainer, setMapContainer] = useState(null) |
| const [TileLayer, setTileLayer] = useState(null) |
| const [Circle, setCircle] = useState(null) |
| const [Popup, setPopup] = useState(null) |
|
|
| useEffect(() => { |
| import('react-leaflet').then(rl => { |
| setMapContainer(() => rl.MapContainer) |
| setTileLayer(() => rl.TileLayer) |
| setCircle(() => rl.Circle) |
| setPopup(() => rl.Popup) |
| setReady(true) |
| }) |
| }, []) |
|
|
| if (!range) return null |
|
|
| return ( |
| <motion.div |
| className={styles.wrapper} |
| initial={{ opacity: 0, y: 12 }} |
| animate={{ opacity: 1, y: 0 }} |
| transition={{ duration: 0.5, delay: 0.2 }} |
| > |
| <p className={styles.label}>Range Map</p> |
| <div className={styles.mapContainer}> |
| {ready && MapContainer ? ( |
| <MapContainer |
| center={range.center} |
| zoom={3} |
| scrollWheelZoom={false} |
| style={{ height: '100%', width: '100%' }} |
| zoomControl={false} |
| > |
| <TileLayer |
| attribution="" |
| url="https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png" |
| /> |
| <Circle |
| center={range.center} |
| radius={800000} |
| pathOptions={{ |
| color: color ?? '#9a749a', |
| fillColor: color ?? '#9a749a', |
| fillOpacity: 0.18, |
| weight: 1.5, |
| }} |
| > |
| <Popup>{commonName} — approximate range</Popup> |
| </Circle> |
| </MapContainer> |
| ) : ( |
| <div className={styles.mapPlaceholder}>Loading map…</div> |
| )} |
| </div> |
| <p className={styles.rangeDesc}>{range.description}</p> |
| </motion.div> |
| ) |
| } |
|
|