diff --git a/client/package-lock.json b/client/package-lock.json index 4702bcc..794430d 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -14,6 +14,7 @@ "@tailwindcss/vite": "^4.1.11", "framer-motion": "^12.23.0", "leaflet": "^1.9.4", + "lucide-react": "^0.539.0", "next-themes": "^0.4.6", "react": "^19.1.0", "react-dom": "^19.1.0", @@ -3894,6 +3895,15 @@ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, + "node_modules/lucide-react": { + "version": "0.539.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.539.0.tgz", + "integrity": "sha512-VVISr+VF2krO91FeuCrm1rSOLACQUYVy7NQkzrOty52Y8TlTPcXcMdQFj9bYzBgXbWCiywlwSZ3Z8u6a+6bMlg==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", diff --git a/client/package.json b/client/package.json index 9cf3193..5185486 100644 --- a/client/package.json +++ b/client/package.json @@ -16,6 +16,7 @@ "@tailwindcss/vite": "^4.1.11", "framer-motion": "^12.23.0", "leaflet": "^1.9.4", + "lucide-react": "^0.539.0", "next-themes": "^0.4.6", "react": "^19.1.0", "react-dom": "^19.1.0", diff --git a/client/src/components/Canvas/CanvasComponents/MapButtonControls.jsx b/client/src/components/Canvas/CanvasComponents/MapButtonControls.jsx new file mode 100644 index 0000000..5bcab69 --- /dev/null +++ b/client/src/components/Canvas/CanvasComponents/MapButtonControls.jsx @@ -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; +} \ No newline at end of file diff --git a/client/src/components/Canvas/CanvasComponents/MapSettingsButton.jsx b/client/src/components/Canvas/CanvasComponents/MapSettingsButton.jsx new file mode 100644 index 0000000..0011f88 --- /dev/null +++ b/client/src/components/Canvas/CanvasComponents/MapSettingsButton.jsx @@ -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 ? ( + +
+ + + + + ):( + setOpen(true)}> + + + ); +} + +function Header(props) { + const { setOpen } = props; + return ( + + Select Layers + setOpen(false)}/> + + ); +} + +function ThermalAnomalies() { + const [checked, setChecked] = useState(false); + + return ( + + + setChecked(!checked)}/> + + Thermal Anomalies + + + ); +} + +function Lightning() { + const [open, setOpen] = useState(false); + const [checked, setChecked] = useState(false); + + return ( + + + {setChecked(!checked); console.log("I'm clicked!")}}/> + + Lightning + + setOpen(!open)}> + {open ? ():()} + + {open && ()} + + ); +} + +function LightningOptions() { + return ( + + + Radius (km) + + + + Date Range + + + to + + + + + ); +} \ No newline at end of file diff --git a/client/src/components/Canvas/views/GlobalMap.jsx b/client/src/components/Canvas/views/GlobalMap.jsx index 6841ee2..7b0f7af 100644 --- a/client/src/components/Canvas/views/GlobalMap.jsx +++ b/client/src/components/Canvas/views/GlobalMap.jsx @@ -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 ( - - - - - CVO — Home of the volcanoligists - - - + + + } position="topright" /> + + + CVO — Home of the volcanoligists + + + ); } \ No newline at end of file diff --git a/client/src/components/Sidebar/Sidebar.jsx b/client/src/components/Sidebar/Sidebar.jsx index c36a92d..c2b151c 100644 --- a/client/src/components/Sidebar/Sidebar.jsx +++ b/client/src/components/Sidebar/Sidebar.jsx @@ -11,6 +11,7 @@ import { MdOutlineSecurity } from "react-icons/md"; import { IoPersonCircleSharp } from "react-icons/io5"; import { useState, useEffect, useMemo } from "react"; import { DASHBOARD_VIEWS } from "@/constants/viewKeys"; +import { KeyRound } from 'lucide-react'; export default function Sidebar({ view, onChangeView, darkMode, setDarkMode }) { const [isOpen, setIsOpen] = useState(true); @@ -23,7 +24,7 @@ export default function Sidebar({ view, onChangeView, darkMode, setDarkMode }) { if (["settings", "personal", "security"].includes(view)) { return [ {icon: IoPersonCircleSharp, name: "Personal Info", view: "personal"}, - {icon: MdOutlineSecurity, name: "Security", view: "security"}, + {icon: KeyRound, name: "Security", view: "security"}, ]; } return [ diff --git a/client/src/theme.js b/client/src/theme.js index 26a033c..33e4ff4 100644 --- a/client/src/theme.js +++ b/client/src/theme.js @@ -149,10 +149,20 @@ const config = defineConfig({ } }, '.leaflet-container': { + fontFamily: "georgia, system-ui, sans-serif !important", _dark: { filter: "invert(100%) hue-rotate(180deg) brightness(95%) contrast(90%)", } }, + ".leaflet-popup-content": { + fontFamily: "georgia, system-ui, sans-serif !important" + }, + ".leaflet-control a": { + fontFamily: "georgia, system-ui, sans-serif !important" + }, + ".leaflet-tooltip": { + fontFamily: "georgia, system-ui, sans-serif !important" + }, ".react-grid-item": { transition: "none !important" }, @@ -166,7 +176,7 @@ const config = defineConfig({ primary: { value: {base: "#2B98F8", _dark: "#2B98F8"}}, primaryLt: { value: {base: "#98cdffff", _dark: "#98cdffff"}}, secondaryBG: { value: {base: "#EDF1F1", _dark: "#121212"}}, - border: {value: {base: "#000000", _dark: "#CBCBCB"}}, + border: {value: {base: "#000000", _dark: "#cbcbcb84"}}, text: {value: {base: "#000000", _dark: "lightgrey"}}, textInverted: {value: "white"}, icon: {value: {base: "#000000", _dark: "lightgrey"}},