basic textbased #tags

This commit is contained in:
Anton 2023-07-21 19:29:13 +02:00
parent 8bbb6bd1e2
commit bd57c87e95
6 changed files with 83 additions and 41 deletions

View File

@ -15,21 +15,37 @@ export const Layer = (props: LayerProps) => {
const tags = useTags();
console.log(tags);
// create a JS-Map with all Tags
const tagMap = new Map(tags?.map(key => [key.id, key]));
console.log(tagMap);
// returns all tags for passed item
const getTags = (item: Item) => {
console.log(item.text);
const regex = /(^|\B)#(?![0-9_]+\b)([a-zA-Z0-9_]{1,30})(\b|\r)/g;
const strings = item.text.match(regex);
console.log(strings);
const tags: Tag[] = [];
item.tags && item.tags.forEach(element => {
if (tagMap.has(element)) { tags.push(tagMap.get(element)!) }
});
strings?.map(tag => {
console.log(tag.slice(1));
if (tagMap.has(tag.slice(1))) { tags.push(tagMap.get(tag.slice(1))!) }
})
console.log(tags);
return tags;
};
const items = useItems();
const addItem = useAddItem()
@ -46,18 +62,18 @@ export const Layer = (props: LayerProps) => {
}
})
props.api?.getItems().then(result => {
props.api?.getItems().then(result => {
if (result.data) {
result.data.map(item => {
if (item.position) {
addItem(({layer: props, api: props.api, ...item}));
addItem(({ layer: props, api: props.api, ...item }));
}
});
}
})
if(props.api || props.api) {
addLayer(props);
}
if (props.api || props.api) {
addLayer(props);
}
}, [props.data, props.api])
@ -84,7 +100,7 @@ export const Layer = (props: LayerProps) => {
}
{props.children}
{props.itemFormPopup && props.itemFormPopup.layer.name == props.name &&
<ItemFormPopup position={props.itemFormPopup.position} layer={props.itemFormPopup.layer} setItemFormPopup={setItemFormPopup} item={props.itemFormPopup.item} api={props.api}/>
<ItemFormPopup position={props.itemFormPopup.position} layer={props.itemFormPopup.layer} setItemFormPopup={setItemFormPopup} item={props.itemFormPopup.item} api={props.api} />
}
</>
)

View File

@ -6,10 +6,7 @@ import { useLayers } from '../hooks/useLayers'
export default function AddButton({setSelectMode} : {setSelectMode: React.Dispatch<React.SetStateAction<any>>}) {
const layers = useLayers();
console.log(layers);
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" >
<button tabIndex={0} className="tw-z-500 tw-border-0 tw-m-0 tw-mt-2 tw-p-0 tw-w-14 tw-h-14 tw-cursor-pointer tw-bg-white tw-rounded-full hover:tw-bg-gray-100 tw-mouse tw-drop-shadow-md tw-transition tw-ease-in tw-duration-200 focus:tw-outline-none">

View File

@ -5,6 +5,8 @@ import { Item, Tag } from '../../../types'
import { replaceURLs } from '../../../Utils/ReplaceURLs'
import { useRemoveItem } from '../hooks/useItems'
import { ItemFormPopupProps } from './ItemFormPopup'
import { heighlightTags } from '../../../Utils/HeighlightTags'
import { useTags } from '../hooks/useTags'
export interface ItemViewPopupProps {
item: Item,
@ -13,12 +15,17 @@ export interface ItemViewPopupProps {
}
const ItemViewPopup = (props: ItemViewPopupProps) => {
const item: Item = props.item;
const tags: Tag[] = props.tags;
const removeItem = useRemoveItem();
const map = useMap();
const all_tags = useTags();
const removeItemFromMap = (event: React.MouseEvent<HTMLElement>) => {
props.item.api?.deleteItem!(props.item.id)
.then( () => removeItem(item))
@ -44,15 +51,15 @@ const ItemViewPopup = (props: ItemViewPopupProps) => {
</div>
<div className='tw-col-span-1'>
{item.api &&
<div className="tw-dropdown tw-dropdown-bottom">
<label tabIndex={0} className="tw-btn tw-m-1 tw-bg-white hover:tw-bg-white tw-text-gray-500 hover:tw-text-gray-700 tw-leading-3 tw-border-none">
<div className="tw-dropdown tw-dropdown-right">
<label tabIndex={0} className="tw-btn tw-m-1 tw-bg-white hover:tw-bg-white tw-text-gray-500 hover:tw-text-gray-700 tw-leading-3 tw-border-none tw-min-h-0 tw-h-4">
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
</label>
<ul tabIndex={0} className="tw-dropdown-content tw-menu tw-p-2 tw-shadow tw-bg-base-100 tw-rounded-box">
{item.api.updateItem && <li>
<a className='tw-bg-white hover:tw-bg-white tw-text-gray-500 hover:tw-text-gray-700' onClick={openEditPopup}>
<a className='tw-bg-white hover:tw-bg-slate-200 !tw-text-blue-800 hover:tw-text-gray-700' onClick={openEditPopup}>
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
<path d="M13.586 3.586a2 2 0 112.828 2.828l-.793.793-2.828-2.828.793-.793zM11.379 5.793L3 14.172V17h2.828l8.38-8.379-2.83-2.828z" />
</svg>
@ -60,7 +67,7 @@ const ItemViewPopup = (props: ItemViewPopupProps) => {
</li>}
{item.api.deleteItem && <li>
<a className='tw-bg-white hover:tw-bg-white tw-text-gray-500 hover:tw-text-gray-700' onClick={removeItemFromMap}>
<a className='tw-bg-white hover:tw-bg-slate-200 !tw-text-red-800 hover:tw-text-red-950' onClick={removeItemFromMap}>
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-5 tw-w-5" viewBox="0 0 20 20" fill="currentColor">
<path fillRule="evenodd" d="M9 2a1 1 0 00-.894.553L7.382 4H4a1 1 0 000 2v10a2 2 0 002 2h8a2 2 0 002-2V6a1 1 0 100-2h-3.382l-.724-1.447A1 1 0 0011 2H9zM7 8a1 1 0 012 0v6a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v6a1 1 0 102 0V8a1 1 0 00-1-1z" clipRule="evenodd" />
</svg>
@ -91,12 +98,12 @@ const ItemViewPopup = (props: ItemViewPopupProps) => {
</div>
}
<p style={{ whiteSpace: "pre-wrap" }} dangerouslySetInnerHTML={{ __html: replaceURLs(item.text) }} />
<p style={{ whiteSpace: "pre-wrap" }} dangerouslySetInnerHTML={{ __html: replaceURLs(heighlightTags(item.text, all_tags)) }} />
<p>
{item.tags &&
tags.map((tag: Tag) => (
<span className="" style={{ fontWeight: "bold", display: "inline-block", color: "#fff", padding: ".3rem", borderRadius: ".5rem", backgroundColor: tag.color, margin: '.2rem', fontSize: "100%" }} key={tag.id}>#{tag.name}</span>
<span className="" style={{ fontWeight: "bold", display: "inline-block", color: "#fff", padding: ".3rem", borderRadius: ".5rem", backgroundColor: tag.color, margin: '.2rem', fontSize: "100%" }} key={tag.id}>#{tag.id}</span>
))
}
</p>

View File

@ -3,34 +3,39 @@ import * as React from "react";
import { Tag } from "../../../types";
type ActionType =
| { type: "ADD"; tag: Tag }
| { type: "REMOVE"; id: number };
| { type: "ADD"; tag: Tag }
| { type: "REMOVE"; id: string };
type UseTagManagerResult = ReturnType<typeof useTagsManager>;
const TagContext = createContext<UseTagManagerResult>({
tags: [],
addTag: () => {},
removeTag: () => {}
tags: [],
addTag: () => { },
removeTag: () => { }
});
function useTagsManager (initialTags: Tag[]): {
function useTagsManager(initialTags: Tag[]): {
tags: Tag[];
addTag: (tag: Tag) => void;
removeTag: (id: number) => void;
removeTag: (id: string) => 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();
}
case "ADD":
const exist = state.find((tag) =>
tag.id === action.tag.id ? true : false
);
if (!exist) return [
...state,
action.tag,
];
else return state;
case "REMOVE":
return state.filter(({ id }) => id !== action.id);
default:
throw new Error();
}
}, initialTags);
const addTag = useCallback((tag: Tag) => {
@ -40,7 +45,7 @@ function useTagsManager (initialTags: Tag[]): {
});
}, []);
const removeTag = useCallback((id: number) => {
const removeTag = useCallback((id: string) => {
dispatch({
type: "REMOVE",
id,
@ -50,7 +55,7 @@ function useTagsManager (initialTags: Tag[]): {
}
export const TagsProvider: React.FunctionComponent<{
initialTags: Tag[], children?: React.ReactNode
initialTags: Tag[], children?: React.ReactNode
}> = ({ initialTags, children }) => (
<TagContext.Provider value={useTagsManager(initialTags)}>
{children}

View File

@ -0,0 +1,18 @@
import { Tag } from "../types";
export function heighlightTags(message: string, tags: Tag[]): string {
if (!message) return "";
const hashTagRegex = /(^|\B)#(?![0-9_]+\b)([a-zA-Z0-9_]{1,30})(\b|\r)/g;
message = message.replace(hashTagRegex, function (string) {
console.log(string);
const tag = tags.find(t => t.id == string.slice(1))
return `<span style="background-color: ${tag ? tag.color : '#aaa' };padding: 0px 5px;border-radius: 7px;cursor: pointer;color:#fff">` + string + '</span>'
});
return message;
}

View File

@ -59,8 +59,7 @@ export class Geometry {
export interface Tag {
color: string;
id: string | number;
name: string;
id: string;
}
export interface ItemsApi<T> {