UNPKG

@availabs/avl-map

Version:

AVAILabs map library, using mapbox-gl

207 lines (174 loc) 5.87 kB
import React from "react" import get from "lodash.get" import { Select, useTheme, ColorBar, useSidebarContext, DummyLegendTools, useLegendReducer } from "@availabs/avl-components" const LayerPanel = ({ layer, layersLoading, ...rest }) => { const [open, setOpen] = React.useState(true), toggleOpen = React.useCallback(e => { setOpen(!open); }, [open, setOpen]); const theme = useTheme(); const filters = React.useMemo(() => { return Object.values(layer.filters) .map(({ name, type, layerId, ...rest }, i) => { switch (type) { default: return ( <div className={ `mt-1 ${ theme.bg } p-1 rounded` } key={ `${ layerId }-${ name }` }> <div className="text-base leading-4 mb-1"> { name } </div> <Select { ...rest }/> </div> ) } }); }, [layer.filters, theme]); return ( <div className={ `${ theme.menuBg } p-1 mb-1 rounded relative` }> <div className={ ` absolute top-0 bottom-0 left-0 right-0 z-10 opacity-50 ${ Boolean(layersLoading[layer.id]) ? "block" : "hidden" } ${ theme.sidebarBg } ` }/> <LayerHeader layer={ layer } { ...rest } open={ open } toggleOpen={ toggleOpen }/> <div style={ { display: open ? "block" : "none" } }> { !layer.legend ? null : <LegendControls layer={ layer } { ...rest }/> } { filters } </div> </div> ) } export default LayerPanel; export const Icon = ({ onClick, cursor="cursor-pointer", className="", style={}, children }) => { const theme = useTheme(); return ( <div onClick={ onClick } className={ ` ${ cursor } ${ className } transition h-6 w-6 hover:${ theme.menuTextActive } flex items-center justify-center ` } style={ { ...style } }> { children } </div> ) } const LayerHeader = ({ layer, toggleOpen, open, MapActions }) => { const theme = useTheme(); return ( <div className={ `flex flex-col px-1 ${ theme.bg } rounded` }> <div className="flex items-center"> <Icon cursor="cursor-move"> <span className="fa fa-bars mr-1"/> </Icon> <div className="font-semibold text-lg leading-5"> { layer.name } </div> <div className="flex-1 flex justify-end"> { !layer.isDynamic ? null : <Icon onClick={ e => MapActions.removeDynamicLayer(layer) }> <span className="fa fa-trash"/> </Icon> } <Icon onClick={ e => MapActions.removeLayer(layer) }> <span className="fa fa-times"/> </Icon> <Icon onClick={ toggleOpen }> <span className={ `fa fa-sm ${ open ? 'fa-minus' : 'fa-plus' }` }/> </Icon> </div> </div> <div className="flex items-center" style={ { marginTop: "-0.25rem" } }> { layer.toolbar.map((tool, i) => <LayerTool MapActions={ MapActions } layer={ layer } tool={ tool } key={ i }/> ) } </div> </div> ) } const LegendControls = ({ layer, MapActions }) => { const { extendSidebar, passCompProps, closeExtension, open } = useSidebarContext(); const { range, type, types } = get(layer, "legend", {}); const [toolState, dispatch] = useLegendReducer(range.length); const updateLegend = React.useCallback(update => { MapActions.updateLegend(layer, update); }, [layer, MapActions]); const theme = useTheme(), ref = React.useRef(); const onClick = React.useCallback(e => { if (open === 2) return closeExtension(); const rect = ref.current.getBoundingClientRect(); const compProps = { layer, range, updateLegend, dispatch, toolState }; extendSidebar({ Comp: LegendSidebar, compProps, top: `calc(${ rect.top }px - 0.5rem)` }); }, [ref, extendSidebar, closeExtension, open, layer, range, updateLegend, dispatch, toolState]); React.useEffect(() => { passCompProps({ layer, updateLegend, dispatch, toolState, range, type, types }); }, [layer, range, type, types, updateLegend, toolState, passCompProps, dispatch]); return ( <div ref={ ref } className={ ` mt-1 ${ theme.bg } hover:${ theme.accent1 } px-1 pb-1 rounded transition relative cursor-pointer ` } onClick={ onClick }> <div>Legend Controls</div> <ColorBar colors={ range } small/> </div> ) } const LegendSidebar = ({ toolState, ...props }) => { const theme = useTheme(); return ( <div className={ ` p-1 rounded-r cursor-auto ${ theme.sidebarBg } w-full ` }> <div className={ `${ theme.menuBg } relative p-1 rounded` }> <div className={ `rounded p-1 ${ theme.bg }` }> <DummyLegendTools { ...props } { ...toolState }/> </div> </div> </div> ) } const checkDefaultTools = tool => { if (typeof tool !== "string") return tool; switch (tool) { case "toggle-visibility": return { tooltip: "Toogle Visibility", icon: layer => layer.isVisible ? "fa-eye" : "fa-eye-slash", action: ({ toggleVisibility }, layer) => toggleVisibility(layer) }; default: return { tooltip: `Unknown Tool "${ tool }"`, icon: "fa-thumbs-down", action: e => {} }; } } const LayerTool = ({ tool, MapActions, layer }) => { const Tool = React.useMemo(() => { return checkDefaultTools(tool); }, [tool]); const action = React.useCallback(e => { Tool.action(MapActions, layer); }, [Tool, MapActions, layer]); const icon = typeof Tool.icon === "function" ? Tool.icon(layer) : Tool.icon; return ( <Icon onClick={ action }> <span className={ `fa fa-sm ${ icon }` }/> </Icon> ) };