mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
layer control
This commit is contained in:
parent
2fec9b05d7
commit
5fbfdfec43
@ -6,7 +6,7 @@ import { ItemViewPopup } from './Subcomponents/ItemViewPopup'
|
||||
import { useItems, useSetItemsApi, useSetItemsData } from './hooks/useItems'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ItemFormPopupProps, ItemFormPopup } from './Subcomponents/ItemFormPopup'
|
||||
import { useFilterTags, useSearchPhrase } from './hooks/useFilter'
|
||||
import { useFilterTags, useIsLayerVisible, useSearchPhrase } from './hooks/useFilter'
|
||||
import { useGetItemTags } from './hooks/useTags'
|
||||
import { useAddMarker, useAddPopup, useLeafletRefs } from './hooks/useLeafletRefs'
|
||||
import { Popup } from 'leaflet'
|
||||
@ -32,6 +32,8 @@ export const Layer = (props: LayerProps) => {
|
||||
|
||||
const map = useMap();
|
||||
|
||||
const isLayerVisible = useIsLayerVisible();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@ -91,6 +93,7 @@ export const Layer = (props: LayerProps) => {
|
||||
? item :
|
||||
item.name.toLowerCase().includes(searchPhrase.toLowerCase()) || item.text.toLowerCase().includes(searchPhrase.toLowerCase())
|
||||
}).
|
||||
filter(item => item.layer && isLayerVisible(item.layer)).
|
||||
map((item: Item) => {
|
||||
const tags = getItemTags(item);
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ export default function AddButton({ setSelectNewItemPosition }: { setSelectNewIt
|
||||
|
||||
|
||||
return (
|
||||
<div className="tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-500 tw-absolute tw-right-5 tw-bottom-5" >
|
||||
<div className="tw-dropdown tw-dropdown-top tw-dropdown-end tw-dropdown-hover tw-z-500 tw-absolute tw-right-4 tw-bottom-4" >
|
||||
<label tabIndex={0} className="tw-z-500 tw-btn tw-btn-circle tw-shadow tw-bg-base-100">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="2" stroke="currentColor" className="tw-w-5 tw-h-5">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
|
||||
51
src/Components/Map/Subcomponents/LayerControl.tsx
Normal file
51
src/Components/Map/Subcomponents/LayerControl.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import * as React from 'react'
|
||||
import { useLayers } from '../hooks/useLayers';
|
||||
import { useAddVisibleLayer, useIsLayerVisible, useToggleVisibleLayer } from '../hooks/useFilter';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
export function LayerControl() {
|
||||
|
||||
const [open, setOpen] = React.useState(false);
|
||||
|
||||
const layers = useLayers();
|
||||
|
||||
useEffect(() => {
|
||||
layers.map(layer =>
|
||||
addVisibleLayer(layer)
|
||||
)
|
||||
|
||||
}, [layers])
|
||||
|
||||
const isLayerVisible = useIsLayerVisible();
|
||||
const toggleVisibleLayer = useToggleVisibleLayer();
|
||||
const addVisibleLayer = useAddVisibleLayer();
|
||||
|
||||
return (
|
||||
<div className="tw-card tw-bg-base-100 tw-shadow-xl tw-absolute tw-bottom-4 tw-left-4 tw-z-1000 " onClick={e=> e.stopPropagation()}>
|
||||
{
|
||||
open ?
|
||||
<div className="tw-card-body tw-p-2 tw-w-32 tw-transition-all tw-duration-300" onClick={e=> e.stopPropagation()}>
|
||||
<label className="tw-h-6 tw-w-6 tw-rounded-2xl tw-items-center tw-inline-flex tw-cursor-pointer tw- tw-absolute tw-right-0 tw-top-0 tw-bg-white tw-text-gray-600" onClick={()=>setOpen(false)}><p className='tw-text-center '>✕</p></label>
|
||||
|
||||
<ul className='tw-flex-row tw-pb-1'>
|
||||
{
|
||||
layers.map(layer =>
|
||||
<li key={layer.name}><label className="tw-label tw-justify-normal tw-pt-1 tw-pb-0"><input type="checkbox" className="tw-checkbox tw-checkbox-xs tw-checkbox-success" checked={isLayerVisible(layer)} onChange={() => toggleVisibleLayer(layer)} /><span className='tw-text-sm tw-label-text tw-mx-2'>{layer.name}</span></label></li>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
:
|
||||
<div className="tw-card-body tw-p-2 tw-h-10 tw-w-10 tw-transition-all tw-duration-300 hover:tw-cursor-pointer" onClick={() => setOpen(true)}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={2} stroke="currentColor" className="w-6 h-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -15,6 +15,7 @@ import { FilterProvider } from "./hooks/useFilter";
|
||||
import { FilterControl } from "./Subcomponents/FilterControl";
|
||||
import { PermissionsProvider } from "./hooks/usePermissions";
|
||||
import { LeafletRefsProvider } from "./hooks/useLeafletRefs";
|
||||
import { LayerControl } from "./Subcomponents/LayerControl";
|
||||
|
||||
|
||||
export interface MapEventListenerProps {
|
||||
@ -77,6 +78,8 @@ function UtopiaMap({
|
||||
<div className={(selectNewItemPosition != null ? "crosshair-cursor-enabled" : undefined)}>
|
||||
<MapContainer ref={mapDivRef} style={{ height: height, width: width }} center={center} zoom={zoom} zoomControl={false}>
|
||||
<FilterControl></FilterControl>
|
||||
<LayerControl></LayerControl>
|
||||
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://tile.osmand.net/hd/{z}/{x}/{y}.png" />
|
||||
|
||||
@ -1,30 +1,45 @@
|
||||
import { useCallback, useReducer, createContext, useContext } from "react";
|
||||
import * as React from "react";
|
||||
import {Tag} from "../../../types";
|
||||
import { LayerProps, Tag } from "../../../types";
|
||||
import { useLayers } from "./useLayers";
|
||||
|
||||
type ActionType =
|
||||
| { type: "ADD_TAG"; tag: Tag }
|
||||
| { type: "REMOVE_TAG"; id: string }
|
||||
| { type: "RESET_TAGS"};
|
||||
| { type: "RESET_TAGS" }
|
||||
| { type: "TOGGLE_LAYER"; layer: LayerProps }
|
||||
| { type: "ADD_LAYER"; layer: LayerProps }
|
||||
| { type: "RESET_LAYERS" }
|
||||
;
|
||||
|
||||
type UseFilterManagerResult = ReturnType<typeof useFilterManager>;
|
||||
|
||||
const FilterContext = createContext<UseFilterManagerResult>({
|
||||
filterTags: [],
|
||||
searchPhrase: "",
|
||||
visibleLayers: [],
|
||||
addFilterTag: () => { },
|
||||
removeFilterTag: () => { },
|
||||
resetFilterTags: () => { },
|
||||
setSearchPhrase: () => { },
|
||||
addVisibleLayer: () => { },
|
||||
toggleVisibleLayer: () => { },
|
||||
resetVisibleLayers: () => { },
|
||||
isLayerVisible: () => true
|
||||
});
|
||||
|
||||
function useFilterManager(initialTags: Tag[]): {
|
||||
filterTags: Tag[];
|
||||
searchPhrase: string;
|
||||
visibleLayers: LayerProps[];
|
||||
addFilterTag: (tag: Tag) => void;
|
||||
removeFilterTag: (id: string) => void;
|
||||
resetFilterTags: () => void;
|
||||
setSearchPhrase: (phrase: string) => void;
|
||||
addVisibleLayer: (layer: LayerProps) => void;
|
||||
toggleVisibleLayer: (layer: LayerProps) => void;
|
||||
resetVisibleLayers: () => void;
|
||||
isLayerVisible: (layer: LayerProps) => boolean;
|
||||
} {
|
||||
const [filterTags, dispatchTags] = useReducer((state: Tag[], action: ActionType) => {
|
||||
switch (action.type) {
|
||||
@ -39,13 +54,38 @@ function useFilterManager(initialTags: Tag[]): {
|
||||
else return state;
|
||||
case "REMOVE_TAG":
|
||||
return state.filter(({ id }) => id !== action.id);
|
||||
case "RESET_TAGS":
|
||||
case "RESET_TAGS":
|
||||
return initialTags;
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}, initialTags);
|
||||
|
||||
const initialLayers = useLayers()
|
||||
|
||||
const [visibleLayers, dispatchLayers] = useReducer((state: LayerProps[], action: ActionType) => {
|
||||
switch (action.type) {
|
||||
case "ADD_LAYER":
|
||||
const exist1 = state.find((layer) =>
|
||||
layer.name === action.layer.name ? true : false
|
||||
);
|
||||
if (!exist1) return [
|
||||
...state,
|
||||
action.layer,
|
||||
];
|
||||
else return state;
|
||||
case "TOGGLE_LAYER":
|
||||
const exist2 = state.some((layer) =>
|
||||
layer.name === action.layer.name);
|
||||
if(exist2) return state.filter(({name}) => name != action.layer.name);
|
||||
else return [... state, action.layer];
|
||||
case "RESET_LAYERS":
|
||||
return initialLayers;
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}, initialLayers);
|
||||
|
||||
const [searchPhrase, searchPhraseSet] = React.useState<string>("");
|
||||
|
||||
const addFilterTag = (tag: Tag) => {
|
||||
@ -69,11 +109,38 @@ function useFilterManager(initialTags: Tag[]): {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setSearchPhrase = useCallback((phrase:string) => {
|
||||
const addVisibleLayer = (layer: LayerProps) => {
|
||||
dispatchLayers({
|
||||
type: "ADD_LAYER",
|
||||
layer,
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
const toggleVisibleLayer = (layer: LayerProps) => {
|
||||
dispatchLayers({
|
||||
type: "TOGGLE_LAYER",
|
||||
layer,
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
const resetVisibleLayers = useCallback(() => {
|
||||
dispatchLayers({
|
||||
type: "RESET_LAYERS",
|
||||
});
|
||||
}, []);
|
||||
|
||||
const isLayerVisible = useCallback((layer: LayerProps) => {
|
||||
return visibleLayers.some(l => l.name === layer.name)
|
||||
}, [visibleLayers]);
|
||||
|
||||
const setSearchPhrase = useCallback((phrase: string) => {
|
||||
searchPhraseSet(phrase)
|
||||
}, []);
|
||||
|
||||
return { filterTags, addFilterTag, removeFilterTag, resetFilterTags, setSearchPhrase, searchPhrase };
|
||||
return { filterTags, addFilterTag, removeFilterTag, resetFilterTags, setSearchPhrase, searchPhrase, visibleLayers, toggleVisibleLayer, resetVisibleLayers, isLayerVisible, addVisibleLayer };
|
||||
}
|
||||
|
||||
export const FilterProvider: React.FunctionComponent<{
|
||||
@ -112,4 +179,30 @@ export const useSearchPhrase = (): UseFilterManagerResult["searchPhrase"] => {
|
||||
export const useSetSearchPhrase = (): UseFilterManagerResult["setSearchPhrase"] => {
|
||||
const { setSearchPhrase } = useContext(FilterContext);
|
||||
return setSearchPhrase;
|
||||
};
|
||||
|
||||
export const useVisibleLayer = (): UseFilterManagerResult["visibleLayers"] => {
|
||||
const { visibleLayers } = useContext(FilterContext);
|
||||
return visibleLayers;
|
||||
};
|
||||
|
||||
export const useAddVisibleLayer = (): UseFilterManagerResult["addVisibleLayer"] => {
|
||||
const { addVisibleLayer } = useContext(FilterContext);
|
||||
return addVisibleLayer;
|
||||
};
|
||||
|
||||
|
||||
export const useToggleVisibleLayer = (): UseFilterManagerResult["toggleVisibleLayer"] => {
|
||||
const { toggleVisibleLayer } = useContext(FilterContext);
|
||||
return toggleVisibleLayer;
|
||||
};
|
||||
|
||||
export const useResetVisibleLayers = (): UseFilterManagerResult["resetVisibleLayers"] => {
|
||||
const { resetVisibleLayers } = useContext(FilterContext);
|
||||
return resetVisibleLayers;
|
||||
};
|
||||
|
||||
export const useIsLayerVisible = (): UseFilterManagerResult["isLayerVisible"] => {
|
||||
const { isLayerVisible } = useContext(FilterContext);
|
||||
return isLayerVisible;
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user