+ Lots of work was done but specifically within the GlobalMap.jsx

+ Two new component files were also added
+ Some slight adjustments to Theme.jsx
This commit is contained in:
2025-08-19 16:45:03 -07:00
parent 5d3a8ec344
commit 3d52160dfc
7 changed files with 170 additions and 13 deletions
@@ -0,0 +1,47 @@
import { useMap } from "react-leaflet";
import L from "leaflet";
import { useEffect, useState } from "react";
import { createPortal } from "react-dom";
// props contain title of btn (which can be an icon), the onClick fn (what should happen)
// when the settings btn is clicked, and it's positioning with the default being topright
export default function MapButtonControls({settingsBtn, position = "topright"}) {
const map = useMap(); // retrieves the map instance that is mounted
const [container, setContainer] = useState(null);
useEffect(() => {
// extending the leaflet control class
const customControl = L.Control.extend({
onAdd: () => {
// create button element with className 'leaflet-bar'
const dv = L.DomUtil.create("div", "layer-selector");
dv.style.cursor = "pointer";
// prevent map interactions when clicking on settings btn
L.DomEvent.disableClickPropagation(dv);
// L.DomEvent.on(dv, "click", onClick); // pass your own onClick fn
// pass button to container for react to render
setContainer(dv);
return dv;
},
onRemove: () => {
setContainer(null);
}
});
// instantiate new customControl object
const control = new customControl({ position });
// method inside og class that we extended above
control.addTo(map);
return () => {
control.remove();
};
}, [map, position, settingsBtn ]);
return container ? createPortal(
settingsBtn,
container)
: null;
}
@@ -0,0 +1,84 @@
import { Box, Checkbox, Separator , CloseButton, Text, chakra, Field, IconButton, Icon, Input, Fieldset, Flex } from "@chakra-ui/react";
import { useState } from "react";
import { FiSettings } from "react-icons/fi";
import { IoIosArrowDown } from "react-icons/io";
import { IoIosArrowUp } from "react-icons/io";
export default function MapSettingsButton() {
const [open, setOpen] = useState(false);
return open ? (
<Box width="240px" display="flex" flexDir="column" gap="2" p="2" bg="white" borderRadius="5px" boxShadow="0 0 0 2px rgba(119, 119, 119, 0.4)">
<Header {...{open, setOpen}}/>
<Separator />
<ThermalAnomalies />
<Lightning />
</Box>
):(
<IconButton boxShadow="0 0 0 2px rgba(119, 119, 119, 0.4)" size="sm" variant="subtle" onClick={() => setOpen(true)}>
<FiSettings />
</IconButton>
);
}
function Header(props) {
const { setOpen } = props;
return (
<chakra.div display="flex" dir="row" alignItems="center" justifyContent="space-between" pl="12">
<Text textStyle="lg">Select Layers</Text>
<CloseButton size="sm" colorPalette='red' onClick={() => setOpen(false)}/>
</chakra.div>
);
}
function ThermalAnomalies() {
const [checked, setChecked] = useState(false);
return (
<Box p="2" borderRadius="3px" bg={checked ? "blue.200":"blue.100"} color={checked ? "blue.700":"text"} border="1px solid" borderColor={checked ? "blue.600":"border"} >
<Checkbox.Root colorPalette="blue">
<Checkbox.HiddenInput onClick={() => setChecked(!checked)}/>
<Checkbox.Control bg={checked ? undefined:"white"}/>
<Checkbox.Label >Thermal Anomalies</Checkbox.Label>
</Checkbox.Root>
</Box>
);
}
function Lightning() {
const [open, setOpen] = useState(false);
const [checked, setChecked] = useState(false);
return (
<Box p="2" borderRadius="3px" bg={checked ? "blue.200":"blue.100"} color={checked ? "blue.700":"text"} border="1px solid" borderColor={checked ? "blue.600":"border"} >
<Checkbox.Root colorPalette="blue">
<Checkbox.HiddenInput onClick={() => {setChecked(!checked); console.log("I'm clicked!")}}/>
<Checkbox.Control bg={checked ? undefined:"white"}/>
<Checkbox.Label >Lightning</Checkbox.Label>
</Checkbox.Root>
<Icon pt="1" size="md" variant="none" onClick={() => setOpen(!open)}>
{open ? (<IoIosArrowUp />):(<IoIosArrowDown />)}
</Icon>
{open && (<LightningOptions />)}
</Box>
);
}
function LightningOptions() {
return (
<Fieldset.Root size="xs">
<Field.Root pl="10" gap={0} >
<Field.Label>Radius (km)</Field.Label>
<Input height="1.25rem" width="4rem" bg="white" border="none" borderRadius="6px" fontStyle="italic" placeholder="max"/>
</Field.Root>
<Field.Root pl="10" gap={0} >
<Field.Label>Date Range</Field.Label>
<Flex dir="row" gap="1">
<Input height="1.25rem" width="4rem" bg="white" border="none" borderRadius="6px" fontStyle="italic" placeholder="min"/>
<Text fontStyle="italic">to</Text>
<Input height="1.25rem" width="4rem" bg="white" border="none" borderRadius="6px" fontStyle="italic" placeholder="max"/>
</Flex>
</Field.Root>
</Fieldset.Root>
);
}
@@ -1,19 +1,23 @@
import React from "react";
import { MapContainer, TileLayer, Marker, Popup } from "react-leaflet";
import MapButtonControls from "../CanvasComponents/MapButtonControls";
import MapSettingsButton from "../CanvasComponents/MapSettingsButton";
export default function GlobalMap() {
const position = [45.61142478054226, -122.49630033167544]; // [latitude, longitude]
return (
<MapContainer center={position} zoom={3} style={{ height: "100%", width: "100%" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; OpenStreetMap contributors'
/>
<Marker position={position}>
<Popup>
CVO Home of the volcanoligists
</Popup>
</Marker>
</MapContainer>
<MapContainer center={position} zoom={3} style={{ height: "100%", width: "100%" }}>
<TileLayer
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
attribution='&copy; OpenStreetMap contributors'
/>
<MapButtonControls settingsBtn = {<MapSettingsButton />} position="topright" />
<Marker position={position}>
<Popup>
CVO Home of the volcanoligists
</Popup>
</Marker>
</MapContainer>
);
}