diff --git a/src/components/BaselayerSections.tsx b/src/components/BaselayerSections.tsx index aa1d52d..be6d80b 100644 --- a/src/components/BaselayerSections.tsx +++ b/src/components/BaselayerSections.tsx @@ -1,12 +1,22 @@ -import { LayerSelectorProps } from './LayerSelector'; +import { useState, useEffect, ReactNode, useRef, useCallback } from 'react'; +import { LayerSelectorProps, NoMatches } from './LayerSelector'; import { CollapsibleSection } from './CollapsibleSection'; -import { EXTERNAL_BASELAYERS } from '../configs/mapSettings'; +import { + EXTERNAL_BASELAYERS, + EXTERNAL_DETAILS_ID, +} from '../configs/mapSettings'; +import { getDefaultExpandedState, filterMapGroups } from '../utils/filterUtils'; type BaselayerSectionsProps = { mapGroups: LayerSelectorProps['mapGroups']; activeBaselayerId: LayerSelectorProps['activeBaselayerId']; isFlipped: LayerSelectorProps['isFlipped']; onBaselayerChange: LayerSelectorProps['onBaselayerChange']; + searchText: string; + markMatchingSearchText: ( + label: string, + shouldHighlight?: boolean + ) => string | ReactNode; }; export function BaselayerSections({ @@ -14,73 +24,78 @@ export function BaselayerSections({ activeBaselayerId, isFlipped, onBaselayerChange, + searchText, + markMatchingSearchText, }: BaselayerSectionsProps) { + const [expandedState, setExpandedState] = useState>( + getDefaultExpandedState(mapGroups, activeBaselayerId) + ); + const externalDetailsRef = useRef(null); + + const { filteredMapGroups, matchedIds } = filterMapGroups( + mapGroups, + searchText + ); + const filteredExternalLayers = EXTERNAL_BASELAYERS.filter((bl) => + bl.name.toLowerCase().includes(searchText.toLowerCase()) + ); + const isEmpty = + filteredMapGroups.length + filteredExternalLayers.length === 0; + + const handleToggle = useCallback( + (id: string) => { + if (expandedState.has(id)) { + setExpandedState((prev) => { + const next = new Set(prev); + next.delete(id); + return next; + }); + } else { + setExpandedState((prev) => new Set(prev).add(id)); + } + }, + [expandedState] + ); + + useEffect(() => { + if (!externalDetailsRef.current) return; + if (searchText.length > 0) { + externalDetailsRef.current.open = true; + } else { + externalDetailsRef.current.open = expandedState.has(EXTERNAL_DETAILS_ID); + } + }, [searchText, externalDetailsRef, expandedState]); + + if (isEmpty) { + return ; + } + return ( <> - {mapGroups.map((group, groupIndex) => ( + {filteredMapGroups.map((group) => ( - {group.maps.map((map, mapIndex) => ( - - {map.bands.map((band, bandIndex) => ( - - {band.layers.map((layer) => ( - - ))} - - ))} - - ))} - + key={group.name} + node={group} + nestedDepth={0} + onBaselayerChange={onBaselayerChange} + activeBaselayerId={activeBaselayerId} + searchText={searchText} + expandedState={expandedState} + markMatchingSearchText={markMatchingSearchText} + matchedIds={matchedIds} + highlightMatch={matchedIds.has(group.name)} + handleToggle={handleToggle} + /> ))} - { - - {EXTERNAL_BASELAYERS.map((bl) => ( + {filteredExternalLayers.length > 0 && ( +
e.preventDefault()}> + handleToggle(EXTERNAL_DETAILS_ID)} + > + Comparison maps + + {filteredExternalLayers.map((bl) => (
onBaselayerChange(bl.layer_id, 'layerMenu')} disabled={bl.disabledState(isFlipped)} /> - +
))} - - } +
+ )} ); } diff --git a/src/components/CenterMapFeature.tsx b/src/components/CenterMapFeature.tsx index 93f0b0a..5a08bdf 100644 --- a/src/components/CenterMapFeature.tsx +++ b/src/components/CenterMapFeature.tsx @@ -101,7 +101,7 @@ export function CenterMapFeature({ className="center-feature-form generic-form" onSubmit={onSubmit} > -