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 * as React from 'react'
|
||||||
import { Marker } from 'react-leaflet'
|
import { Marker } from 'react-leaflet'
|
||||||
import { Item, Tag } from '../../types'
|
import { Item, Tag, Layer as LayerProps } from '../../types'
|
||||||
import MarkerIconFactory from '../../Utils/MarkerIconFactory'
|
import MarkerIconFactory from '../../Utils/MarkerIconFactory'
|
||||||
import { Popup } from './Popup'
|
import { Popup } from './Subcomponents/Popup'
|
||||||
import { useLayers, useAddLayer } from './useLayers'
|
import { useLayers, useAddLayer } from './hooks/useLayers'
|
||||||
|
import { useTags } from './hooks/useTags'
|
||||||
|
|
||||||
export interface LayerProps {
|
|
||||||
data?: Item[],
|
|
||||||
children?: React.ReactNode
|
|
||||||
name: string,
|
|
||||||
menuIcon: string,
|
|
||||||
menuColor: string,
|
|
||||||
menuText: string,
|
|
||||||
markerIcon: string,
|
|
||||||
markerShape: string,
|
|
||||||
markerDefaultColor: string,
|
|
||||||
tags?: Tag[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Layer = (props: LayerProps) => {
|
export const Layer = (props: LayerProps) => {
|
||||||
|
|
||||||
|
const tags = useTags();
|
||||||
|
|
||||||
// create a JS-Map with all Tags
|
// 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
|
// returns all tags for passed item
|
||||||
const getTags = (item: Item) => {
|
const getTags = (item: Item) => {
|
||||||
@ -32,13 +22,9 @@ export const Layer = (props: LayerProps) => {
|
|||||||
return tags;
|
return tags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const addLayer = useAddLayer();
|
const addLayer = useAddLayer();
|
||||||
addLayer(props);
|
addLayer(props);
|
||||||
const layers = useLayers();
|
const layers = useLayers();
|
||||||
console.log(layers);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import DynamicHeroIcon from '../../Utils/DynamicHeroIcon'
|
import DynamicHeroIcon from '../../../Utils/DynamicHeroIcon'
|
||||||
import { useLayers } from './useLayers'
|
import { useLayers } from '../hooks/useLayers'
|
||||||
|
|
||||||
|
|
||||||
export interface AddButtonProps {
|
export default function AddButton({setSelectMode} : {setSelectMode: React.Dispatch<React.SetStateAction<any>>}) {
|
||||||
setSelectMode: React.Dispatch<React.SetStateAction<any>>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AddButton(props: AddButtonProps) {
|
|
||||||
|
|
||||||
const layers = useLayers();
|
const layers = useLayers();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="dropdown dropdown-top dropdown-end dropdown-hover z-500 absolute right-5 bottom-5" >
|
<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">
|
<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}
|
<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"
|
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 }}
|
style={{ backgroundColor: layer.menuColor }}
|
||||||
onClick={() => { props.setSelectMode(layer) }}>
|
onClick={() => { setSelectMode(layer) }}>
|
||||||
<DynamicHeroIcon icon={layer.menuIcon} />
|
<DynamicHeroIcon icon={layer.menuIcon} />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -2,9 +2,8 @@ import * as React from 'react'
|
|||||||
import { LatLng } from 'leaflet'
|
import { LatLng } from 'leaflet'
|
||||||
import { Popup as LeafletPopup, useMap } from 'react-leaflet'
|
import { Popup as LeafletPopup, useMap } from 'react-leaflet'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useAddItem } from './useLayers'
|
import { useAddItem } from '../hooks/useLayers'
|
||||||
import { Item } from './UtopiaMap'
|
import { Geometry, Layer, Item} from '../../../types'
|
||||||
import { Geometry, Layer} from '../../types'
|
|
||||||
|
|
||||||
export interface NewItemPopupProps {
|
export interface NewItemPopupProps {
|
||||||
position: LatLng,
|
position: LatLng,
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { Popup as LeafletPopup} from 'react-leaflet'
|
import { Popup as LeafletPopup} from 'react-leaflet'
|
||||||
import { Item, Tag } from '../../types'
|
import { Item, Tag } from '../../../types'
|
||||||
import { replaceURLs } from '../../Utils/ReplaceURLs'
|
import { replaceURLs } from '../../../Utils/ReplaceURLs'
|
||||||
|
|
||||||
export interface UtopiaPopupProps {
|
export interface UtopiaPopupProps {
|
||||||
item: Item,
|
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 { TileLayer, MapContainer, useMapEvents } from "react-leaflet";
|
||||||
import "leaflet/dist/leaflet.css";
|
import "leaflet/dist/leaflet.css";
|
||||||
import * as React from "react";
|
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 "../../index.css"
|
||||||
import { LatLng } from "leaflet";
|
import { LatLng } from "leaflet";
|
||||||
import MarkerClusterGroup from 'react-leaflet-cluster'
|
import MarkerClusterGroup from 'react-leaflet-cluster'
|
||||||
import AddButton from "./AddButton";
|
import AddButton from "./Subcomponents/AddButton";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import NewItemPopup, { NewItemPopupProps } from "./NewItemPopup";
|
import NewItemPopup, { NewItemPopupProps } from "./Subcomponents/NewItemPopup";
|
||||||
import { LayersProvider } from "./useLayers";
|
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 {
|
export interface MapEventListenerProps {
|
||||||
selectMode: Layer | null,
|
selectMode: Layer | null,
|
||||||
@ -54,10 +45,8 @@ function UtopiaMap({
|
|||||||
const [selectMode, setSelectMode] = useState<Layer | null>(null);
|
const [selectMode, setSelectMode] = useState<Layer | null>(null);
|
||||||
const [newItemPopup, setNewItemPopup] = useState<NewItemPopupProps | null>(null);
|
const [newItemPopup, setNewItemPopup] = useState<NewItemPopupProps | null>(null);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<TagsProvider initialTags={[]}>
|
||||||
<LayersProvider initialLayers={new Map()}>
|
<LayersProvider initialLayers={new Map()}>
|
||||||
<div className={(selectMode != null ? "crosshair-cursor-enabled" : undefined)}>
|
<div className={(selectMode != null ? "crosshair-cursor-enabled" : undefined)}>
|
||||||
<MapContainer style={{ height: height, width: width }} center={center} zoom={zoom}>
|
<MapContainer style={{ height: height, width: width }} center={center} zoom={zoom}>
|
||||||
@ -69,7 +58,7 @@ function UtopiaMap({
|
|||||||
</MarkerClusterGroup>
|
</MarkerClusterGroup>
|
||||||
<MapEventListener setSelectMode={setSelectMode} selectMode={selectMode} setNewItemPopup={setNewItemPopup} />
|
<MapEventListener setSelectMode={setSelectMode} selectMode={selectMode} setNewItemPopup={setNewItemPopup} />
|
||||||
{newItemPopup &&
|
{newItemPopup &&
|
||||||
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup}/>
|
<NewItemPopup position={newItemPopup.position} layer={newItemPopup.layer} setNewItemPopup={setNewItemPopup} />
|
||||||
}
|
}
|
||||||
<AddButton setSelectMode={setSelectMode}></AddButton>
|
<AddButton setSelectMode={setSelectMode}></AddButton>
|
||||||
</MapContainer>
|
</MapContainer>
|
||||||
@ -85,8 +74,8 @@ function UtopiaMap({
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
</LayersProvider>
|
</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[] = [
|
export const tags : Tag[] = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useCallback, useReducer, createContext, useContext } from "react";
|
import { useCallback, useReducer, createContext, useContext } from "react";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Item, Layer } from "../../types";
|
import { Item, Layer } from "../../../types";
|
||||||
|
|
||||||
type ActionType =
|
type ActionType =
|
||||||
| { type: "ADD LAYER"; layer: Layer }
|
| { 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 { 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 { UtopiaMap, Layer, Tags, Item, Tag, API } from './Components/Map/index'
|
||||||
export { Layer } from './Components/Map/Layer';
|
|
||||||
|
|||||||
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 {
|
export class Item {
|
||||||
id: number;
|
id: number;
|
||||||
date_created?: string;
|
date_created?: string;
|
||||||
@ -32,20 +57,6 @@ export interface Tag {
|
|||||||
name: string;
|
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 {
|
export interface API {
|
||||||
getAll(): Promise<void>,
|
getAll(): Promise<void>,
|
||||||
add(item : Item): Promise<void>,
|
add(item : Item): Promise<void>,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user