diff --git a/.env.example b/.env.example index 3cc866d6d..1de573440 100644 --- a/.env.example +++ b/.env.example @@ -6,10 +6,6 @@ VITE_MACROSTRAT_API_DOMAIN='https://macrostrat.org' VITE_ROCKD_API_URL='https://dev.rockd.org/api/v2/' -# For matomo analytics -VITE_MATOMO_API_URL='' -VITE_MATOMO_API_TOKEN='' - # Needed for map ingestion system # SECRET_KEY='Replace with api signing key' diff --git a/package.json b/package.json index 173a3df9a..f1ec63d38 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "@macrostrat/mapbox-react": "^2.5.0", "@macrostrat/mapbox-utils": "^1.4.0", "@macrostrat/style-system": "^0.2.0", - "@macrostrat/ui-components": "^4.1.2", + "@macrostrat/ui-components": "^4.4.4", "@supabase/postgrest-js": "^1.11.0", "@universal-middleware/express": "^0.0.2", "@vitejs/plugin-react": "^4.0.4", diff --git a/pages/explore/+Page.client.ts b/pages/explore/+Page.client.ts index 3536e51bb..e07e8c38c 100644 --- a/pages/explore/+Page.client.ts +++ b/pages/explore/+Page.client.ts @@ -1,12 +1,12 @@ import { useMapRef } from "@macrostrat/mapbox-react"; -import { Spinner, Icon, Divider, Button } from "@blueprintjs/core"; +import { Spinner, Icon, Button } from "@blueprintjs/core"; import { SETTINGS } from "~/settings"; import {buildInspectorStyle } from "@macrostrat/map-interface"; import { buildMacrostratStyle } from "@macrostrat/map-styles"; import { mergeStyles } from "@macrostrat/mapbox-utils"; import { useDarkMode, DarkModeButton } from "@macrostrat/ui-components"; import mapboxgl from "mapbox-gl"; -import { useCallback, useEffect, useState, useMemo } from "react"; +import { useCallback, useEffect, useState } from "react"; import h from "./main.module.sass"; import { useRockdAPI, Image, pageCarousel, createCheckins } from "~/components"; import "@macrostrat/style-system"; @@ -18,6 +18,9 @@ import { } from "@macrostrat/map-interface"; import { mapboxAccessToken } from "~/settings"; +import { AutoComplete } from "./autocomplete"; +import { deletePins } from "./utils"; +import { FeatureDetails } from "./featuredcheckins"; export function Page() { return h( @@ -410,278 +413,6 @@ function createFilteredCheckins(filteredData, setInspectPosition) { return createCheckins(filteredData?.filteredData, mapRef, setInspectPosition); } -function AutoComplete({setFilteredData, autocompleteOpen, setAutocompleteOpen}) { - const mapRef = useMapRef(); - const map = mapRef.current; - const [input, setInput] = useState(''); - const [close, setClose] = useState(false); - const [page, setPage] = useState(1); - - // test - const [peopleIds, setPeople] = useState([]); - const [structures, setStructures] = useState([]); - const [lithologyAttributes, setLithologyAttributes] = useState([]); - const [stratNameOrphans, setStratNameOrphans] = useState([]); - const [lithologyIds, setLithologies] = useState([]); - // const [taxaIds, setTaxa] = useState([]); // fails - // const [intervalIds, setIntervals] = useState([]); // fails - // const [stratNameConcepts, setStratNameConcepts] = useState([]); // fails - // const [minerals, setMinerals] = useState([]); // fails - // const [lithologyTypes, setLithologyTypes] = useState([]); // doesn't exist - // const [lithologyClasses, setLithologyClasses] = useState([]); // doesn't exist - - const lithParam = "lith_id=" + lithologyIds.map(item => item.id).join(','); - const peopleParam = "person_id=" + peopleIds.map(item => item.id).join(','); - const stratNameOrphanParam = "strat_name_orphan_id=" + stratNameOrphans.map(item => item.id).join(','); - const lithologyAttributeParam = "lith_att_id=" + lithologyAttributes.map(item => item.id).join(','); - const structureParam = "structure_id=" + structures.map(item => item.id).join(','); - // const taxaParam = "taxon_id=" + taxaIds.map(item => item.id).join(','); // fails - // const intervalParam = "int_id=" + intervalIds.map(item => item.id).join(','); // fails - // const stratNameConceptParam = "strat_name_concept_id=" + stratNameConcepts.map(item => item.id).join(','); // fails - // const mineralParam = "mineral_id=" + minerals.map(item => item.id).join(','); // fails - // const lithologyTypeParam = "=" + lithologyTypes.map(item => item.id).join(','); // doesn't exist - // const lithologyClassParam = "=" + lithologyClasses.map(item => item.id).join(','); // doesn't exist - - // develop query - const finalParams = useMemo(() => { - const params = [ - lithParam, - peopleParam, - lithologyAttributeParam, - stratNameOrphanParam, - structureParam - ].filter(param => /\d/.test(param)); - - return params.join('&'); - }, [lithologyIds, peopleIds, lithologyAttributes, stratNameOrphans, structures]); - - const queryString = useMemo(() => { - return finalParams ? `/protected/checkins?${finalParams}` : null; - }, [finalParams]); - - - // get data - const data = useRockdAPI(queryString + "&page=" + page)?.success.data; - const nextData = useRockdAPI(queryString + "&page=" + (page + 1))?.success.data; - - // add markers for filtered checkins - let coordinates = []; - let lngs = []; - let lats = []; - - useEffect(() => { - if(data && data.length > 0 && queryString) { - setFilteredData({ - current: data, - next: { - data: nextData, - page: page, - setPage: setPage - } - }); - - data.forEach((checkin) => { - coordinates.push([checkin.lng, checkin.lat]); - lngs.push(checkin.lng); - lats.push(checkin.lat); - }); - - deletePins('.filtered_pin'); - - if (!close) { - let stop = 0; - coordinates.forEach((coord) => { - stop++; - // marker - const el = document.createElement('div'); - el.className = 'filtered_pin'; - el.style.backgroundColor = 'green'; - el.style.borderRadius = '50%'; - el.style.border = '2px solid white'; - el.style.width = '15px'; - el.style.height = '15px'; - - // Create marker - new mapboxgl.Marker(el) - .setLngLat(coord) - .addTo(map); - }); - } - - map.fitBounds([ - [ Math.max(...lngs), Math.max(...lats) ], - [ Math.min(...lngs), Math.min(...lats) ] - ], { - maxZoom: 12, - duration: 0, - padding: 75 - }); - } else { - deletePins('.filtered_pin'); - - setFilteredData(null); - } - }, [data, nextData, queryString]); - - // rest - const handleInputChange = (event) => { - setAutocompleteOpen(true); - setInput(event.target.value); - setClose(false); - setPage(1); - }; - - let result = null; - - try { - result = useRockdAPI("/autocomplete/" + input); - } catch (e) { - return null; - } - - let searchBar = h('div.search-bar', [ - h('input', { type: "text", placeholder: "Search name", onChange: handleInputChange }), - h('div.x-icon', [ - h(Icon, { icon: "cross", onClick: () => { - let input = document.querySelector('input'); - input.value = ""; - setAutocompleteOpen(false); - setClose(true); - setFilteredData(null); - setPage(1); - deletePins('.filtered_pin'); - } - }), - ]), - ]); - - const sectionConfigs = [ - { label: 'People', data: peopleIds, setter: setPeople }, - { label: 'Strat Name Orphans', data: stratNameOrphans, setter: setStratNameOrphans }, - { label: 'Structures', data: structures, setter: setStructures }, - { label: 'Lithologies', data: lithologyIds, setter: setLithologies }, - { label: 'Lithology Attributes', data: lithologyAttributes, setter: setLithologyAttributes }, - // { label: 'Taxa', data: taxaIds, setter: setTaxa }, - // { label: 'Intervals', data: intervalIds, setter: setIntervals }, - // { label: 'Lithology Types', data: lithologyTypes, setter: setLithologyTypes }, - // { label: 'Lithology Classes', data: lithologyClasses, setter: setLithologyClasses }, - // { label: 'Strat Name Concepts', data: stratNameConcepts, setter: setStratNameConcepts }, - // { label: 'Minerals', data: minerals, setter: setMinerals }, - ]; - - const sections = sectionConfigs - .filter(({ data }) => data.length > 0) - .map(({ label, data, setter }) => - h('div', [ - h('h3', label), - createFilteredItems(data, setter, setPage) - ]) - ); - - const filterContainer = sections.length != 0 ? h("div.filter-container", [ - h('h2', "Filters"), - h('ul', [ - sections - ]), - ]) : null; - - if(!result || close) return h('div', {className: "autocomplete"}, [ - searchBar - ]); - result = result.success.data; - - let results; - - if(autocompleteOpen) { - const lithologies = renderSection("Lithologies", "lithologies", result?.lithologies, setLithologies, lithologyIds, setAutocompleteOpen); - const strat_name_orphans = renderSection("Stratigraphic Name Orphans", "strat_name_orphans", result?.strat_name_orphans, setStratNameOrphans, stratNameOrphans, setAutocompleteOpen); - const structures_items = renderSection("Structures", "structures", result?.structures, setStructures, structures, setAutocompleteOpen); - const lithology_attributes = renderSection("Lithology Attributes", "lithology_attributes", result?.lithology_attributes, setLithologyAttributes, lithologyAttributes, setAutocompleteOpen); - const people = renderSection("People", "people", result?.people, setPeople, peopleIds, setAutocompleteOpen); - // sections commented out that don't work or don't exist - // const intervals = renderSection("Intervals", "intervals", result?.intervals, setIntervals, intervalIds, setAutocompleteOpen); - // const lithology_types = renderSection("Lithology Types", "lithology_types", result?.lithology_types, setLithologyTypes, lithologyTypes, setAutocompleteOpen); - // const lithology_classes = renderSection("Lithology Classes", "lithology_classes", result?.lithology_classes, setLithologyClasses, lithologyClasses, setAutocompleteOpen); - // const strat_name_concepts = renderSection("Stratigraphic Name Concepts", "strat_name_concepts", result?.strat_name_concepts, setStratNameConcepts, stratNameConcepts, setAutocompleteOpen); - // const minerals_items = renderSection("Minerals", "minerals", result?.minerals, setMinerals, minerals, setAutocompleteOpen); - // const taxa = renderSection("Taxa", "taxa", result?.taxa, setTaxa, taxaIds, setAutocompleteOpen); - - // result - results = h('div.results', [ - people, - lithologies, - lithology_attributes, - strat_name_orphans, - structures_items, - // minerals_items, - // taxa, - // intervals, - // strat_name_concepts, - // lithology_types, - // lithology_classes, - ]); - } - - /* - useEffect(() => { - setLithologyData(useRockdAPI("/proctected/checkins?lith_id=" + lithologies.map(item => item.id).join(',') + "&all=100")); - }, [lithologies]); - */ - - const wrapper = h('div.autocomplete-wrapper', [ - filterContainer, - results, - ]); - - return h('div.autocomplete', [ - searchBar, - wrapper, - ]); -} - -function createFilteredItems(arr, set, setPage) { - return arr.map((item) => { - return h("li.filter-item", [ - h('div', item.name), - h(Icon, { className: 'red-cross', icon: "cross", style: {color: "red"}, onClick: () => { - set(arr.filter((person) => person != item)); - setPage(1); - } - }) - ]) - }) -} - -function createFilteredNames(result, set, existing, setAutocompleteOpen) { - return result.map((item) => - h('li', { - onClick: () => { - if (!existing.includes(item)) { - setAutocompleteOpen(false); - set(existing.concat([item])); - } - } - }, item.name) - ) -} - -function deletePins(str) { - let previous = document.querySelectorAll(str); - previous.forEach((marker) => { - marker.remove(); - }); -} - -function renderSection(label, key, resultList, setFn, existingIds, setAutocompleteOpen) { - return resultList?.length > 0 - ? h(`div.${key}`, [ - h('h2', label), - h('ul', createFilteredNames(resultList, setFn, existingIds, setAutocompleteOpen)) - ]) - : null; -} - - export function MapContainer({style, mapPosition, onSelectPosition, setSelectedCheckin, overlay}) { return h( "div.map-container", diff --git a/pages/explore/autocomplete.ts b/pages/explore/autocomplete.ts new file mode 100644 index 000000000..6a5ba8097 --- /dev/null +++ b/pages/explore/autocomplete.ts @@ -0,0 +1,271 @@ +import { useMapRef } from "@macrostrat/mapbox-react"; +import { Icon } from "@blueprintjs/core"; +import mapboxgl from "mapbox-gl"; +import { useEffect, useState, useMemo } from "react"; +import h from "./main.module.sass"; +import { useRockdAPI } from "~/components"; +import { deletePins } from "./utils"; + +export function AutoComplete({setFilteredData, autocompleteOpen, setAutocompleteOpen}) { + const mapRef = useMapRef(); + const map = mapRef.current; + const [input, setInput] = useState(''); + const [close, setClose] = useState(false); + const [page, setPage] = useState(1); + + // test + const [peopleIds, setPeople] = useState([]); + const [structures, setStructures] = useState([]); + const [lithologyAttributes, setLithologyAttributes] = useState([]); + const [stratNameOrphans, setStratNameOrphans] = useState([]); + const [lithologyIds, setLithologies] = useState([]); + // const [taxaIds, setTaxa] = useState([]); // fails + // const [intervalIds, setIntervals] = useState([]); // fails + // const [stratNameConcepts, setStratNameConcepts] = useState([]); // fails + // const [minerals, setMinerals] = useState([]); // fails + // const [lithologyTypes, setLithologyTypes] = useState([]); // doesn't exist + // const [lithologyClasses, setLithologyClasses] = useState([]); // doesn't exist + + const lithParam = "lith_id=" + lithologyIds.map(item => item.id).join(','); + const peopleParam = "person_id=" + peopleIds.map(item => item.id).join(','); + const stratNameOrphanParam = "strat_name_orphan_id=" + stratNameOrphans.map(item => item.id).join(','); + const lithologyAttributeParam = "lith_att_id=" + lithologyAttributes.map(item => item.id).join(','); + const structureParam = "structure_id=" + structures.map(item => item.id).join(','); + // const taxaParam = "taxon_id=" + taxaIds.map(item => item.id).join(','); // fails + // const intervalParam = "int_id=" + intervalIds.map(item => item.id).join(','); // fails + // const stratNameConceptParam = "strat_name_concept_id=" + stratNameConcepts.map(item => item.id).join(','); // fails + // const mineralParam = "mineral_id=" + minerals.map(item => item.id).join(','); // fails + // const lithologyTypeParam = "=" + lithologyTypes.map(item => item.id).join(','); // doesn't exist + // const lithologyClassParam = "=" + lithologyClasses.map(item => item.id).join(','); // doesn't exist + + // develop query + const finalParams = useMemo(() => { + const params = [ + lithParam, + peopleParam, + lithologyAttributeParam, + stratNameOrphanParam, + structureParam + ].filter(param => /\d/.test(param)); + + return params.join('&'); + }, [lithologyIds, peopleIds, lithologyAttributes, stratNameOrphans, structures]); + + const queryString = useMemo(() => { + return finalParams ? `/protected/checkins?${finalParams}` : null; + }, [finalParams]); + + + // get data + const data = useRockdAPI(queryString + "&page=" + page)?.success.data; + const nextData = useRockdAPI(queryString + "&page=" + (page + 1))?.success.data; + + // add markers for filtered checkins + let coordinates = []; + let lngs = []; + let lats = []; + + useEffect(() => { + if(data && data.length > 0 && queryString) { + setFilteredData({ + current: data, + next: { + data: nextData, + page: page, + setPage: setPage + } + }); + + data.forEach((checkin) => { + coordinates.push([checkin.lng, checkin.lat]); + lngs.push(checkin.lng); + lats.push(checkin.lat); + }); + + deletePins('.filtered_pin'); + + if (!close) { + let stop = 0; + coordinates.forEach((coord) => { + stop++; + // marker + const el = document.createElement('div'); + el.className = 'filtered_pin'; + el.style.backgroundColor = 'green'; + el.style.borderRadius = '50%'; + el.style.border = '2px solid white'; + el.style.width = '15px'; + el.style.height = '15px'; + + // Create marker + new mapboxgl.Marker(el) + .setLngLat(coord) + .addTo(map); + }); + } + + map.fitBounds([ + [ Math.max(...lngs), Math.max(...lats) ], + [ Math.min(...lngs), Math.min(...lats) ] + ], { + maxZoom: 12, + duration: 0, + padding: 75 + }); + } else { + deletePins('.filtered_pin'); + + setFilteredData(null); + } + }, [data, nextData, queryString]); + + // rest + const handleInputChange = (event) => { + setAutocompleteOpen(true); + setInput(event.target.value); + setClose(false); + setPage(1); + }; + + let result = null; + + try { + result = useRockdAPI("/autocomplete/" + input); + } catch (e) { + return null; + } + + let searchBar = h('div.search-bar', [ + h('input', { type: "text", placeholder: "Search name", onChange: handleInputChange }), + h('div.x-icon', [ + h(Icon, { icon: "cross", onClick: () => { + let input = document.querySelector('input'); + input.value = ""; + setAutocompleteOpen(false); + setClose(true); + setFilteredData(null); + setPage(1); + deletePins('.filtered_pin'); + } + }), + ]), + ]); + + const sectionConfigs = [ + { label: 'People', data: peopleIds, setter: setPeople }, + { label: 'Strat Name Orphans', data: stratNameOrphans, setter: setStratNameOrphans }, + { label: 'Structures', data: structures, setter: setStructures }, + { label: 'Lithologies', data: lithologyIds, setter: setLithologies }, + { label: 'Lithology Attributes', data: lithologyAttributes, setter: setLithologyAttributes }, + // { label: 'Taxa', data: taxaIds, setter: setTaxa }, + // { label: 'Intervals', data: intervalIds, setter: setIntervals }, + // { label: 'Lithology Types', data: lithologyTypes, setter: setLithologyTypes }, + // { label: 'Lithology Classes', data: lithologyClasses, setter: setLithologyClasses }, + // { label: 'Strat Name Concepts', data: stratNameConcepts, setter: setStratNameConcepts }, + // { label: 'Minerals', data: minerals, setter: setMinerals }, + ]; + + const sections = sectionConfigs + .filter(({ data }) => data.length > 0) + .map(({ label, data, setter }) => + h('div', [ + h('h3', label), + createFilteredItems(data, setter, setPage) + ]) + ); + + const filterContainer = sections.length != 0 ? h("div.filter-container", [ + h('h2', "Filters"), + h('ul', [ + sections + ]), + ]) : null; + + if(!result || close) return h('div', {className: "autocomplete"}, [ + searchBar + ]); + result = result.success.data; + + let results; + + if(autocompleteOpen) { + const lithologies = renderSection("Lithologies", "lithologies", result?.lithologies, setLithologies, lithologyIds, setAutocompleteOpen); + const strat_name_orphans = renderSection("Stratigraphic Name Orphans", "strat_name_orphans", result?.strat_name_orphans, setStratNameOrphans, stratNameOrphans, setAutocompleteOpen); + const structures_items = renderSection("Structures", "structures", result?.structures, setStructures, structures, setAutocompleteOpen); + const lithology_attributes = renderSection("Lithology Attributes", "lithology_attributes", result?.lithology_attributes, setLithologyAttributes, lithologyAttributes, setAutocompleteOpen); + const people = renderSection("People", "people", result?.people, setPeople, peopleIds, setAutocompleteOpen); + // sections commented out that don't work or don't exist + // const intervals = renderSection("Intervals", "intervals", result?.intervals, setIntervals, intervalIds, setAutocompleteOpen); + // const lithology_types = renderSection("Lithology Types", "lithology_types", result?.lithology_types, setLithologyTypes, lithologyTypes, setAutocompleteOpen); + // const lithology_classes = renderSection("Lithology Classes", "lithology_classes", result?.lithology_classes, setLithologyClasses, lithologyClasses, setAutocompleteOpen); + // const strat_name_concepts = renderSection("Stratigraphic Name Concepts", "strat_name_concepts", result?.strat_name_concepts, setStratNameConcepts, stratNameConcepts, setAutocompleteOpen); + // const minerals_items = renderSection("Minerals", "minerals", result?.minerals, setMinerals, minerals, setAutocompleteOpen); + // const taxa = renderSection("Taxa", "taxa", result?.taxa, setTaxa, taxaIds, setAutocompleteOpen); + + // result + results = h('div.results', [ + people, + lithologies, + lithology_attributes, + strat_name_orphans, + structures_items, + // minerals_items, + // taxa, + // intervals, + // strat_name_concepts, + // lithology_types, + // lithology_classes, + ]); + } + + /* + useEffect(() => { + setLithologyData(useRockdAPI("/proctected/checkins?lith_id=" + lithologies.map(item => item.id).join(',') + "&all=100")); + }, [lithologies]); + */ + + const wrapper = h('div.autocomplete-wrapper', [ + filterContainer, + results, + ]); + + return h('div.autocomplete', [ + searchBar, + wrapper, + ]); +} + +function createFilteredItems(arr, set, setPage) { + return arr.map((item) => { + return h("li.filter-item", [ + h('div', item.name), + h(Icon, { className: 'red-cross', icon: "cross", style: {color: "red"}, onClick: () => { + set(arr.filter((person) => person != item)); + setPage(1); + } + }) + ]) + }) +} + +function renderSection(label, key, resultList, setFn, existingIds, setAutocompleteOpen) { + return resultList?.length > 0 + ? h(`div.${key}`, [ + h('h2', label), + h('ul', createFilteredNames(resultList, setFn, existingIds, setAutocompleteOpen)) + ]) + : null; +} + +function createFilteredNames(result, set, existing, setAutocompleteOpen) { + return result.map((item) => + h('li', { + onClick: () => { + if (!existing.includes(item)) { + setAutocompleteOpen(false); + set(existing.concat([item])); + } + } + }, item.name) + ) +} \ No newline at end of file diff --git a/pages/explore/featuredcheckins.ts b/pages/explore/featuredcheckins.ts new file mode 100644 index 000000000..e2515e803 --- /dev/null +++ b/pages/explore/featuredcheckins.ts @@ -0,0 +1,91 @@ +import { useMapRef } from "@macrostrat/mapbox-react"; +import { Spinner } from "@blueprintjs/core"; +import { useEffect, useState } from "react"; +import h from "./main.module.sass"; +import { useRockdAPI, pageCarousel, createCheckins } from "~/components/general"; +import "@macrostrat/style-system"; + +export function FeatureDetails({setInspectPosition}) { + const [page, setPage] = useState(1); + const mapRef = useMapRef(); + const map = mapRef.current; + const [bounds, setBounds] = useState(map?.getBounds()); + let checkins = []; + let result; + let nextData; + + if (bounds) { + result = getCheckins(bounds.getSouth(), bounds.getNorth(), bounds.getWest(), bounds.getEast(), page); + nextData = getCheckins(bounds.getSouth(), bounds.getNorth(), bounds.getWest(), bounds.getEast(), page + 1); + } else { + result = getCheckins(0, 0, 0, 0, 1); + nextData = getCheckins(0, 0, 0, 0, 2); + } + + if (!bounds && map) { + setBounds(map.getBounds()); + } + + useEffect(() => { + if (!map) return; + + const handleMapReady = () => { + const newBounds = map.getBounds(); + setBounds(newBounds); + setPage(1); + }; + + if (map.isStyleLoaded()) { + handleMapReady(); + } else { + map.once("load", handleMapReady); + } + + const onMoveEnd = () => { + const newBounds = map.getBounds(); + setBounds(newBounds); + setPage(1); + }; + + map.on("moveend", onMoveEnd); + + return () => { + map.off("moveend", onMoveEnd); + map.off("load", handleMapReady); + }; + }, [map]); + + + result = result?.success?.data; + if (result == null || result.length === 0) return h(Spinner, { className: "loading-spinner" }); + + const pages = pageCarousel({page, setPage, nextData: nextData?.success.data}); + + result.sort((a, b) => { + if (a.photo === null && b.photo !== null) return 1; + if (a.photo !== null && b.photo === null) return -1; + return 0; + }); + + checkins = createCheckins(result, mapRef, setInspectPosition); + + return h("div", {className: 'checkin-container'}, [ + checkins, + pages + ]); +} + +function getCheckins(lat1, lat2, lng1, lng2, page) { + // abitrary bounds around click point + let minLat = Math.floor(lat1 * 100) / 100; + let maxLat = Math.floor(lat2 * 100) / 100; + let minLng = Math.floor(lng1 * 100) / 100; + let maxLng = Math.floor(lng2 * 100) / 100; + + // change use map coords + return useRockdAPI("/protected/checkins?minlat=" + minLat + + "&maxlat=" + maxLat + + "&minlng=" + minLng + + "&maxlng=" + maxLng + + "&page=" + page); +} \ No newline at end of file diff --git a/pages/explore/utils.ts b/pages/explore/utils.ts new file mode 100644 index 000000000..ce964c339 --- /dev/null +++ b/pages/explore/utils.ts @@ -0,0 +1,6 @@ +export function deletePins(str) { + let previous = document.querySelectorAll(str); + previous.forEach((marker) => { + marker.remove(); + }); +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 80d6b09d9..5d6bdb474 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2646,7 +2646,7 @@ __metadata: "@macrostrat/mapbox-utils": "npm:^1.4.0" "@macrostrat/revision-info-webpack": "npm:^1.0.0" "@macrostrat/style-system": "npm:^0.2.0" - "@macrostrat/ui-components": "npm:^4.1.2" + "@macrostrat/ui-components": "npm:^4.4.4" "@mdx-js/rollup": "npm:^2.3.0" "@supabase/postgrest-js": "npm:^1.11.0" "@types/esprima": "npm:^4" @@ -2712,7 +2712,7 @@ __metadata: languageName: node linkType: hard -"@macrostrat/ui-components@npm:^4.1.1, @macrostrat/ui-components@npm:^4.1.2, @macrostrat/ui-components@npm:^4.1.3": +"@macrostrat/ui-components@npm:^4.1.1, @macrostrat/ui-components@npm:^4.1.3": version: 4.1.3 resolution: "@macrostrat/ui-components@npm:4.1.3" dependencies: @@ -2774,6 +2774,38 @@ __metadata: languageName: node linkType: hard +"@macrostrat/ui-components@npm:^4.4.4": + version: 4.4.4 + resolution: "@macrostrat/ui-components@npm:4.4.4" + dependencies: + "@blueprintjs/core": "npm:^5.10.2" + "@blueprintjs/datetime2": "npm:^2.3.11" + "@blueprintjs/select": "npm:^5.3.10" + "@macrostrat/hyper": "npm:^3.0.6" + "@types/react": "npm:^18.3.12" + "@types/react-dom": "npm:^18" + axios: "npm:^1.7.9" + chroma-js: "npm:^2.4.2||^3.0.0" + classnames: "npm:^2.3.0" + d3-array: "npm:^3.2.4" + immutability-helper: "npm:^3.1.1" + query-string: "npm:^9.0.0" + react-color: "npm:^2.19.3" + react-dropzone: "npm:^11.4.2" + react-intersection-observer: "npm:^8.32.1" + react-json-tree: "npm:^0.19.0" + ui-box: "npm:^5.4.1" + underscore: "npm:^1.13.1" + use-async-effect: "npm:^2.2.1" + use-element-dimensions: "npm:^2.1.3" + zustand: "npm:^5.0.3" + peerDependencies: + react: ^16.8.6 || ^17 || ^18 || ^19 + react-dom: ^16.8.6 || ^17 || ^18 || ^19 + checksum: 10c0/ff2f642079b08ab0ddb3d0bcf626b191cb85cf2d2f94ff1ff2111b61b98679abe8aed65f26ca9ef05ce5f937876870d846924641696f2b46e7cdff7c6ef8547b + languageName: node + linkType: hard + "@mantine/core@npm:^4.2.1": version: 4.2.12 resolution: "@mantine/core@npm:4.2.12"