mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
useTags hook
This commit is contained in:
parent
1b3aef9906
commit
b532eca956
@ -1,27 +1,17 @@
|
||||
import * as React from 'react'
|
||||
import { Marker } from 'react-leaflet'
|
||||
import { Item, Tag } from '../../types'
|
||||
import { Item, Tag, Layer as LayerProps } from '../../types'
|
||||
import MarkerIconFactory from '../../Utils/MarkerIconFactory'
|
||||
import { Popup } from './Popup'
|
||||
import { useLayers, useAddLayer } from './useLayers'
|
||||
|
||||
|
||||
export interface LayerProps {
|
||||
data?: Item[],
|
||||
children?: React.ReactNode
|
||||
name: string,
|
||||
menuIcon: string,
|
||||
menuColor: string,
|
||||
menuText: string,
|
||||
markerIcon: string,
|
||||
markerShape: string,
|
||||
markerDefaultColor: string,
|
||||
tags?: Tag[]
|
||||
}
|
||||
import { Popup } from './Subcomponents/Popup'
|
||||
import { useLayers, useAddLayer } from './hooks/useLayers'
|
||||
import { useTags } from './hooks/useTags'
|
||||
|
||||
export const Layer = (props: LayerProps) => {
|
||||
|
||||
const tags = useTags();
|
||||
|
||||
// create a JS-Map with all Tags
|
||||
let tagMap = new Map(props.tags?.map(key => [key.id, key]));
|
||||
let tagMap = new Map(tags?.map(key => [key.id, key]));
|
||||
|
||||
// returns all tags for passed item
|
||||
const getTags = (item: Item) => {
|
||||
@ -32,14 +22,10 @@ export const Layer = (props: LayerProps) => {
|
||||
return tags;
|
||||
};
|
||||
|
||||
|
||||
const addLayer = useAddLayer();
|
||||
addLayer(props);
|
||||
const layers = useLayers();
|
||||
console.log(layers);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{layers.get(props.name)?.data?.map((place: Item) => {
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
import * as React from 'react'
|
||||
import DynamicHeroIcon from '../../Utils/DynamicHeroIcon'
|
||||
import { useLayers } from './useLayers'
|
||||
import DynamicHeroIcon from '../../../Utils/DynamicHeroIcon'
|
||||
import { useLayers } from '../hooks/useLayers'
|
||||
|
||||
|
||||
export interface AddButtonProps {
|
||||
setSelectMode: React.Dispatch<React.SetStateAction<any>>
|
||||
}
|
||||
|
||||
export default function AddButton(props: AddButtonProps) {
|
||||
export default function AddButton({setSelectMode} : {setSelectMode: React.Dispatch<React.SetStateAction<any>>}) {
|
||||
|
||||
const layers = useLayers();
|
||||
|
||||
return (
|
||||
<div className="dropdown dropdown-top dropdown-end dropdown-hover z-500 absolute right-5 bottom-5" >
|
||||
<button tabIndex={0} className="z-500 border-0 m-0 mt-2 p-0 w-14 h-14 cursor-pointer bg-white rounded-full hover:bg-gray-100 mouse drop-shadow-md transition ease-in duration-200 focus:outline-none">
|
||||
@ -28,7 +25,7 @@ export default function AddButton(props: AddButtonProps) {
|
||||
<button tabIndex={0}
|
||||
className="z-500 border-0 p-0 mb-2 mt-2 w-10 h-10 cursor-pointer rounded-full mouse drop-shadow-md transition ease-in duration-200 focus:outline-none"
|
||||
style={{ backgroundColor: layer.menuColor }}
|
||||
onClick={() => { props.setSelectMode(layer) }}>
|
||||
onClick={() => { setSelectMode(layer) }}>
|
||||
<DynamicHeroIcon icon={layer.menuIcon} />
|
||||
</button>
|
||||
</div>
|
||||
@ -2,9 +2,8 @@ import * as React from 'react'
|
||||
import { LatLng } from 'leaflet'
|
||||
import { Popup as LeafletPopup, useMap } from 'react-leaflet'
|
||||
import { useState } from 'react'
|
||||
import { useAddItem } from './useLayers'
|
||||
import { Item } from './UtopiaMap'
|
||||
import { Geometry, Layer} from '../../types'
|
||||
import { useAddItem } from '../hooks/useLayers'
|
||||
import { Geometry, Layer, Item} from '../../../types'
|
||||
|
||||
export interface NewItemPopupProps {
|
||||
position: LatLng,
|
||||
@ -1,7 +1,7 @@
|
||||
import * as React from 'react'
|
||||
import { Popup as LeafletPopup} from 'react-leaflet'
|
||||
import { Item, Tag } from '../../types'
|
||||
import { replaceURLs } from '../../Utils/ReplaceURLs'
|
||||
import { Item, Tag } from '../../../types'
|
||||
import { replaceURLs } from '../../../Utils/ReplaceURLs'
|
||||
|
||||
export interface UtopiaPopupProps {
|
||||
item: Item,
|
||||
20
src/Components/Map/Tags.tsx
Normal file
20
src/Components/Map/Tags.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import * as React from 'react'
|
||||
import { useEffect } from 'react';
|
||||
import { Tag } from '../../types';
|
||||
import { useAddTag } from './hooks/useTags'
|
||||
|
||||
export function Tags({data} : {data: Tag[]}) {
|
||||
const addTag = useAddTag();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
data.map(tag => {
|
||||
console.log("Tag added: " + tag.name);
|
||||
addTag(tag)
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<></>
|
||||
)
|
||||
}
|
||||
@ -1,26 +1,17 @@
|
||||
import { TileLayer, MapContainer, useMapEvents } from "react-leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import * as React from "react";
|
||||
import { Item, Tag, API, Layer } from "../../types"
|
||||
import { Item, Tag, API, Layer, UtopiaMap as UtopiaMapProps } from "../../types"
|
||||
import "../../index.css"
|
||||
import { LatLng } from "leaflet";
|
||||
import MarkerClusterGroup from 'react-leaflet-cluster'
|
||||
import AddButton from "./AddButton";
|
||||
import { useState } from "react";
|
||||
import NewItemPopup, { NewItemPopupProps } from "./NewItemPopup";
|
||||
import { LayersProvider } from "./useLayers";
|
||||
import AddButton from "./Subcomponents/AddButton";
|
||||
import { useState } from "react";
|
||||
import NewItemPopup, { NewItemPopupProps } from "./Subcomponents/NewItemPopup";
|
||||
import { LayersProvider } from "./hooks/useLayers";
|
||||
import { TagsProvider } from "./hooks/useTags";
|
||||
|
||||
|
||||
export interface UtopiaMapProps {
|
||||
height?: string,
|
||||
width?: string,
|
||||
center?: LatLng,
|
||||
zoom?: number,
|
||||
tags?: Tag[],
|
||||
children?: React.ReactNode,
|
||||
api?: API
|
||||
}
|
||||
|
||||
|
||||
export interface MapEventListenerProps {
|
||||
selectMode: Layer | null,
|
||||
@ -54,39 +45,37 @@ function UtopiaMap({
|
||||
const [selectMode, setSelectMode] = useState<Layer | null>(null);
|
||||
const [newItemPopup, setNewItemPopup] = useState<NewItemPopupProps | null>(null);
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<LayersProvider initialLayers={new Map()}>
|
||||
<div className={(selectMode != null ? "crosshair-cursor-enabled" : undefined)}>
|
||||
<MapContainer style={{ height: height, width: width }} center={center} zoom={zoom}>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||
<MarkerClusterGroup showCoverageOnHover chunkedLoading maxClusterRadius={50}>
|
||||
{children}
|
||||
</MarkerClusterGroup>
|
||||
<MapEventListener setSelectMode={setSelectMode} selectMode={selectMode} setNewItemPopup={setNewItemPopup} />
|
||||
{newItemPopup &&
|
||||
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup}/>
|
||||
}
|
||||
<AddButton setSelectMode={setSelectMode}></AddButton>
|
||||
</MapContainer>
|
||||
{selectMode != null &&
|
||||
<div className="button z-500 absolute right-5 top-5 drop-shadow-md">
|
||||
<div className="alert bg-white text-green-900">
|
||||
<div>
|
||||
<span>Select {selectMode.name} position!</span>
|
||||
<TagsProvider initialTags={[]}>
|
||||
<LayersProvider initialLayers={new Map()}>
|
||||
<div className={(selectMode != null ? "crosshair-cursor-enabled" : undefined)}>
|
||||
<MapContainer style={{ height: height, width: width }} center={center} zoom={zoom}>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
|
||||
<MarkerClusterGroup showCoverageOnHover chunkedLoading maxClusterRadius={50}>
|
||||
{children}
|
||||
</MarkerClusterGroup>
|
||||
<MapEventListener setSelectMode={setSelectMode} selectMode={selectMode} setNewItemPopup={setNewItemPopup} />
|
||||
{newItemPopup &&
|
||||
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup} />
|
||||
}
|
||||
<AddButton setSelectMode={setSelectMode}></AddButton>
|
||||
</MapContainer>
|
||||
{selectMode != null &&
|
||||
<div className="button z-500 absolute right-5 top-5 drop-shadow-md">
|
||||
<div className="alert bg-white text-green-900">
|
||||
<div>
|
||||
<span>Select {selectMode.name} position!</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
</div>
|
||||
</LayersProvider>
|
||||
</div>
|
||||
</LayersProvider>
|
||||
</TagsProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export { UtopiaMap, Item, Tag, API };
|
||||
|
||||
export { UtopiaMap, Item, Tag, API };
|
||||
@ -1,4 +1,4 @@
|
||||
import {Item, Tag} from "utopia-ui"
|
||||
import {Item, Tag} from "../../types"
|
||||
|
||||
export const tags : Tag[] = [
|
||||
{
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { useCallback, useReducer, createContext, useContext } from "react";
|
||||
import * as React from "react";
|
||||
import { Item, Layer } from "../../types";
|
||||
import { Item, Layer } from "../../../types";
|
||||
|
||||
type ActionType =
|
||||
| { type: "ADD LAYER"; layer: Layer }
|
||||
73
src/Components/Map/hooks/useTags.tsx
Normal file
73
src/Components/Map/hooks/useTags.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import { useCallback, useReducer, createContext, useContext } from "react";
|
||||
import * as React from "react";
|
||||
import { Tag } from "../../../types";
|
||||
|
||||
type ActionType =
|
||||
| { type: "ADD"; tag: Tag }
|
||||
| { type: "REMOVE"; id: number };
|
||||
|
||||
type UseTagManagerResult = ReturnType<typeof useTagsManager>;
|
||||
|
||||
const TagContext = createContext<UseTagManagerResult>({
|
||||
tags: [],
|
||||
addTag: () => {},
|
||||
removeTag: () => {}
|
||||
});
|
||||
|
||||
function useTagsManager (initialTags: Tag[]): {
|
||||
tags: Tag[];
|
||||
addTag: (tag: Tag) => void;
|
||||
removeTag: (id: number) => void;
|
||||
} {
|
||||
const [tags, dispatch] = useReducer((state: Tag[], action: ActionType) => {
|
||||
switch (action.type) {
|
||||
case "ADD":
|
||||
return [
|
||||
...state,
|
||||
action.tag,
|
||||
];
|
||||
case "REMOVE":
|
||||
return state.filter(({ id }) => id !== action.id);
|
||||
default:
|
||||
throw new Error();
|
||||
}
|
||||
}, initialTags);
|
||||
|
||||
const addTag = useCallback((tag: Tag) => {
|
||||
dispatch({
|
||||
type: "ADD",
|
||||
tag,
|
||||
});
|
||||
}, []);
|
||||
|
||||
const removeTag = useCallback((id: number) => {
|
||||
dispatch({
|
||||
type: "REMOVE",
|
||||
id,
|
||||
});
|
||||
}, []);
|
||||
return { tags, addTag, removeTag };
|
||||
}
|
||||
|
||||
export const TagsProvider: React.FunctionComponent<{
|
||||
initialTags: Tag[], children?: React.ReactNode
|
||||
}> = ({ initialTags, children }) => (
|
||||
<TagContext.Provider value={useTagsManager(initialTags)}>
|
||||
{children}
|
||||
</TagContext.Provider>
|
||||
);
|
||||
|
||||
export const useTags = (): Tag[] => {
|
||||
const { tags } = useContext(TagContext);
|
||||
return tags;
|
||||
};
|
||||
|
||||
export const useAddTag = (): UseTagManagerResult["addTag"] => {
|
||||
const { addTag } = useContext(TagContext);
|
||||
return addTag;
|
||||
};
|
||||
|
||||
export const useRemoveTag = (): UseTagManagerResult["removeTag"] => {
|
||||
const { removeTag } = useContext(TagContext);
|
||||
return removeTag;
|
||||
};
|
||||
@ -1 +1,3 @@
|
||||
export { UtopiaMap, Item, Tag, API } from './UtopiaMap'
|
||||
export { Layer } from './Layer';
|
||||
export { Tags } from "./Tags";
|
||||
@ -1,2 +1 @@
|
||||
export { UtopiaMap, Item, Tag, API } from './Components/Map/index'
|
||||
export { Layer } from './Components/Map/Layer';
|
||||
export { UtopiaMap, Layer, Tags, Item, Tag, API } from './Components/Map/index'
|
||||
|
||||
39
src/types.ts
39
src/types.ts
@ -1,3 +1,28 @@
|
||||
import { LatLng } from "leaflet";
|
||||
|
||||
export interface UtopiaMap {
|
||||
height?: string,
|
||||
width?: string,
|
||||
center?: LatLng,
|
||||
zoom?: number,
|
||||
tags?: Tag[],
|
||||
children?: React.ReactNode,
|
||||
api?: API
|
||||
}
|
||||
|
||||
export interface Layer {
|
||||
data?: Item[],
|
||||
children?: React.ReactNode
|
||||
name: string,
|
||||
menuIcon: string,
|
||||
menuColor: string,
|
||||
menuText: string,
|
||||
markerIcon: string,
|
||||
markerShape: string,
|
||||
markerDefaultColor: string,
|
||||
tags?: Tag[]
|
||||
}
|
||||
|
||||
export class Item {
|
||||
id: number;
|
||||
date_created?: string;
|
||||
@ -32,20 +57,6 @@ export interface Tag {
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
||||
export interface Layer {
|
||||
data?: Item[],
|
||||
children?: React.ReactNode
|
||||
name: string,
|
||||
menuIcon: string,
|
||||
menuColor: string,
|
||||
menuText: string,
|
||||
markerIcon: string,
|
||||
markerShape: string,
|
||||
markerDefaultColor: string,
|
||||
tags?: Tag[]
|
||||
}
|
||||
|
||||
export interface API {
|
||||
getAll(): Promise<void>,
|
||||
add(item : Item): Promise<void>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user