From 1451491ec571712e428a2823fbefb97ceccc9a25 Mon Sep 17 00:00:00 2001 From: geoffsee <> Date: Fri, 18 Jul 2025 13:07:13 -0400 Subject: [PATCH] add search and layer control --- .../src/components/landing-component/Map.tsx | 167 +++++++++++++++++- .../components/landing-component/MapNext.tsx | 8 +- 2 files changed, 169 insertions(+), 6 deletions(-) diff --git a/packages/client/src/components/landing-component/Map.tsx b/packages/client/src/components/landing-component/Map.tsx index b1d0d4e..bb2e1c9 100644 --- a/packages/client/src/components/landing-component/Map.tsx +++ b/packages/client/src/components/landing-component/Map.tsx @@ -1,7 +1,8 @@ -import ReactMap from 'react-map-gl/mapbox'; // ↔ v5+ uses this import path import 'mapbox-gl/dist/mapbox-gl.css'; -import { Box, HStack, Button, Input, Center } from '@chakra-ui/react'; -import { useState, useEffect, useCallback } from 'react'; +import { Box, Button, HStack, Input } from '@chakra-ui/react'; +import { useCallback, useEffect, useState } from 'react'; + +import clientChatStore from '../../stores/ClientChatStore.ts'; import MapNext from './MapNext.tsx'; @@ -30,17 +31,175 @@ interface AuthParams { token: string | null; } +export type Layer = { name: string; value: string }; +export type Layers = Layer[]; + // public key const key = 'cGsuZXlKMUlqb2laMlZ2Wm1aelpXVWlMQ0poSWpvaVkycDFOalo0YkdWNk1EUTRjRE41YjJnNFp6VjNNelp6YXlKOS56LUtzS1l0X3VGUGdCSDYwQUFBNFNn'; +const layers = [ + { name: 'Bathymetry', value: 'mapbox://styles/geoffsee/cmd1qz39x01ga01qv5acea02y' }, + { name: 'Satellite', value: 'mapbox://styles/mapbox/satellite-v9' }, +]; + +function LayerSelector(props: { onClick: (e) => Promise }) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + + + {isOpen && ( + + {layers.map(layer => ( + { + setIsOpen(false); + await props.onClick(e); + }} + > + {layer.name} + + ))} + + )} + + ); +} + function Map(props: { visible: boolean }) { + const [isSearchOpen, setIsSearchOpen] = useState(false); + const [selectedLayer, setSelectedLayer] = useState(layers[0]); + const [searchInput, setSearchInput] = useState(''); + const [searchResults, setSearchResults] = useState([]); + + // const handleSearchClick = useCallback(async () => { + // console + // }, []); + // + + async function selectSearchResult({ lat, lon }) { + // clientChatStore.mapState.latitude = searchResult.lat; + // clientChatStore.mapState.longitude = searchResult.lon; + await clientChatStore.setMapView(lon, lat, 15); + } + + async function handleSc(e) { + if (isSearchOpen && searchInput.length > 1) { + try { + console.log(`trying to geocode ${searchInput}`); + const geocode = await fetch('https://geocode.geoffsee.com', { + method: 'POST', + mode: 'cors', + body: JSON.stringify({ + location: searchInput, + }), + }); + const coordinates = await geocode.json(); + const { lat, lon } = coordinates; + console.log(`got geocode coordinates: ${coordinates}`); + setSearchResults([{ lat, lon }]); + } catch (e) { + // continue without + } + } else { + setIsSearchOpen(!isSearchOpen); + } + } + + useEffect(() => { + console.log(selectedLayer); + }, [selectedLayer]); + + function handleLayerChange(e) { + setSelectedLayer(layers.find(layer => layer.value === e.target.id)); + } + return ( /* Full-screen wrapper — fills the viewport and becomes the positioning context */ {/* Button bar — absolutely positioned inside the wrapper */} - + + + + {isSearchOpen && ( + + setSearchInput(e.target.value)} + color="white" + bg="background.secondary" + border="none" + borderRadius="0" + _focus={{ + outline: 'none', + }} + _placeholder={{ + color: '#d1cfcf', + }} + /> + {searchResults.length > 0 && ( + + {searchResults.map((result, index) => ( + { + // setSearchInput(result); + console.log(`selecting result ${result.lat}, ${result.lon}`); + await selectSearchResult(result); + setSearchResults([]); + setIsSearchOpen(false); + }} + > + {`${result.lat}, ${result.lon}`} + + ))} + + )} + + )} + + + + {/*