mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2025-12-13 07:46:10 +00:00
basic textbased #tags
This commit is contained in:
parent
8bbb6bd1e2
commit
bd57c87e95
@ -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} />
|
||||
}
|
||||
</>
|
||||
)
|
||||
|
||||
@ -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">
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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}
|
||||
|
||||
18
src/Utils/HeighlightTags.ts
Normal file
18
src/Utils/HeighlightTags.ts
Normal 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;
|
||||
}
|
||||
@ -59,8 +59,7 @@ export class Geometry {
|
||||
|
||||
export interface Tag {
|
||||
color: string;
|
||||
id: string | number;
|
||||
name: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface ItemsApi<T> {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user