Modularization of Item Popups

This commit is contained in:
Anton 2023-08-20 13:11:57 +02:00
parent 77f7e36a5d
commit 4fe4aa6b74
10 changed files with 491 additions and 452 deletions

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 68 KiB

View File

@ -31,16 +31,18 @@ const DialogModal = ({
useEffect(() => {
if (isOpened) {
ref.current?.showModal();
ref.current?.classList.remove("tw-hidden");
document.body.classList.add("modal-open"); // prevent bg scroll
} else {
ref.current?.close();
ref.current?.classList.add("tw-hidden");
document.body.classList.remove("modal-open");
}
}, [isOpened]);
return (
<dialog id="signup_modal" className='tw-card tw-shadow-xl tw-absolute tw-right-0 tw-top-0 tw-bottom-0 tw-left-0 tw-m-auto tw-transition-opacity tw-duration-300'
<dialog className='tw-card tw-shadow-xl tw-absolute tw-right-0 tw-top-0 tw-bottom-0 tw-left-0 tw-m-auto tw-transition-opacity tw-duration-300'
ref={ref}
onCancel={onClose}

View File

@ -3,9 +3,10 @@ import * as React from "react"
type TextAreaProps = {
labelTitle: string;
labelTitle?: string;
labelStyle?: string;
containerStyle?: string;
inputStyle?: string;
defaultValue: string;
placeholder?: string;
updateFormValue: (value: string ) => void;
@ -13,7 +14,7 @@ type TextAreaProps = {
function TextAreaInput({labelTitle, labelStyle, containerStyle, defaultValue, placeholder, updateFormValue} : TextAreaProps){
function TextAreaInput({labelTitle, labelStyle, containerStyle, inputStyle, defaultValue, placeholder, updateFormValue} : TextAreaProps){
const [value, setValue] = useState<string>(defaultValue)
@ -28,11 +29,11 @@ function TextAreaInput({labelTitle, labelStyle, containerStyle, defaultValue, pl
}
return(
<div className={`tw-form-control tw-w-full ${containerStyle}`}>
<label className="tw-label">
<div className={`tw-form-control tw-w-full ${containerStyle? containerStyle : ""}`}>
{labelTitle ? <label className="tw-label">
<span className={"tw-label-text tw-text-base-content " + labelStyle}>{labelTitle}</span>
</label>
<textarea value={value} className="tw-textarea tw-textarea-bordered tw-w-full tw-min-h-64" placeholder={placeholder || ""} onChange={(e) => updateInputValue(e.target.value)}></textarea>
</label> : ""}
<textarea value={value} className={`tw-textarea tw-textarea-bordered tw-w-full tw-leading-5 ${inputStyle? inputStyle : ""}`} placeholder={placeholder || ""} onChange={(e) => updateInputValue(e.target.value)}></textarea>
</div>
)
}

View File

@ -86,7 +86,7 @@ export const Layer = (props: LayerProps) => {
}
return (
<Marker icon={MarkerIconFactory(props.markerShape, color1, color2, props.markerIcon)} key={place.id} position={[place.position.coordinates[1], place.position.coordinates[0]]}>
<ItemViewPopup item={place} tags={tags} setItemFormPopup={props.setItemFormPopup} />
<ItemViewPopup item={place} setItemFormPopup={props.setItemFormPopup} />
</Marker>
);
})

View File

@ -4,6 +4,8 @@ import { Popup as LeafletPopup, useMap } from 'react-leaflet'
import { useEffect, useState } from 'react'
import { useAddItem, useUpdateItem } from '../hooks/useItems'
import { Geometry, LayerProps, Item, ItemsApi} from '../../../types'
import TextAreaInput from '../../Input/TextAreaInput'
import InputText from '../../Input/InputText'
export interface ItemFormPopupProps {
position: LatLng,
@ -68,8 +70,8 @@ export default function ItemFormPopup(props: ItemFormPopupProps) {
position={props.position}>
<form onSubmit={handleSubmit}>
<div className='tw-flex tw-justify-center'><b className="tw-text-xl tw-font-bold">New {props.layer.name}</b></div>
<input type="text" placeholder="Name" className="tw-input tw-input-bordered tw-w-full tw-max-w-xs tw-mt-5" value={name} onChange={e => setName(e.target.value)} />
<textarea className="tw-textarea tw-textarea-bordered tw-w-full tw-mt-5 tw-leading-5 tw-h-40" placeholder="Text" value={text} onChange={e => setText(e.target.value)}></textarea>
<InputText type="text" placeholder="Name" defaultValue={name} updateFormValue={e => setName(e)} />
<TextAreaInput placeholder="Text" defaultValue={text} updateFormValue={e => setText(e)} inputStyle='tw-h-40 tw-mt-5'/>
<div className='tw-flex tw-justify-center'><button className={spinner ? 'tw-btn tw-loading tw-mt-5 tw-place-self-center' : 'tw-btn tw-mt-5 tw-place-self-center'}>Save</button></div>
</form>
</LeafletPopup>

View File

@ -1,118 +1,33 @@
import { LatLng } from 'leaflet'
import * as React from 'react'
import { Popup as LeafletPopup, useMap } from 'react-leaflet'
import { Item, Tag } from '../../../types'
import { replaceURLs } from '../../../Utils/ReplaceURLs'
import { useRemoveItem } from '../hooks/useItems'
import { Item} from '../../../types'
import { ItemFormPopupProps } from './ItemFormPopup'
import { heighlightTags } from '../../../Utils/HeighlightTags'
import { useTags } from '../hooks/useTags'
import {HeaderView} from './HeaderView'
import StartEndView from './StartEndView'
import { TextView } from './TextView'
export interface ItemViewPopupProps {
item: Item,
tags: Tag[],
setItemFormPopup?: React.Dispatch<React.SetStateAction<ItemFormPopupProps | null>>
}
const ItemViewPopup = (props: ItemViewPopupProps) => {
export 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))
.then(()=> map.closePopup())
.catch(err => console.log(err));
event.stopPropagation();
}
const openEditPopup = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation();
map.closePopup();
if (props.setItemFormPopup)
props.setItemFormPopup({ position: new LatLng(item.position.coordinates[1], item.position.coordinates[0]), layer: item.layer, item: item, setItemFormPopup: props.setItemFormPopup })
}
return (
<LeafletPopup maxHeight={377} minWidth={275} maxWidth={275} autoPanPadding={[20, 5]}>
<div>
<div className='tw-grid tw-grid-cols-6'>
<div className='tw-col-span-5'>
<b className="tw-text-xl tw-font-bold">{item.name}</b>
</div>
<div className='tw-col-span-1'>
{item.api &&
<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-gray-300 !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>
</a>
</li>}
{item.api.deleteItem && <li>
<a className='tw-bg-white hover:tw-bg-gray-300 !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>
</a>
</li>}
</ul>
</div>}
</div>
</div>
<HeaderView item={props.item} setItemFormPopup={props.setItemFormPopup}/>
<div className='tw-overflow-y-auto tw-max-h-72'>
{item.start && item.end &&
<div className="tw-flex tw-flex-row">
<div className="basis-2/5">
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-6 tw-w-6 tw-mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className='tw-align-middle'>{new Date(item.start).toISOString().substring(0, 10) || ""}</span>
</div>
<div className="tw-basis-1/5 tw-place-content-center">
<span>-</span>
</div>
<div className="tw-basis-2/5">
<svg xmlns="http://www.w3.org/2000/svg" className="tw-h-6 tw-w-6 tw-mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path strokeLinecap="round" strokeLinejoin="round" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
</svg>
<span className='tw-align-middle tw-leading-6'>{new Date(item.end).toISOString().substring(0, 10) || ""}</span>
</div>
</div>
<StartEndView item={props.item} />
}
<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.id}</span>
))
}
</p>
<TextView item={props.item}/>
</div>
</div>
</LeafletPopup>
)
}
export { ItemViewPopup };

View File

@ -1,7 +1,7 @@
import { TileLayer, MapContainer, useMapEvents } from "react-leaflet";
import "leaflet/dist/leaflet.css";
import * as React from "react";
import { Item, Tag, ItemsApi, LayerProps, UtopiaMapProps } from "../../types"
import { Tag, ItemsApi, LayerProps, UtopiaMapProps } from "../../types"
import "./UtopiaMap.css"
import { LatLng } from "leaflet";
import MarkerClusterGroup from 'react-leaflet-cluster'
@ -87,4 +87,4 @@ function UtopiaMap({
);
}
export { UtopiaMap, Item, Tag, ItemsApi };
export { UtopiaMap };

View File

@ -1,3 +1,3 @@
export { UtopiaMap, Item, Tag, ItemsApi } from './UtopiaMap'
export { UtopiaMap } from './UtopiaMap'
export { Layer } from './Layer';
export { Tags } from "./Tags";

View File

@ -55,10 +55,6 @@ export function Settings({useAuth}) {
}
const updateFormValue = (val: string) => {
console.log(val)
}
return (
<main className="tw-flex-1 tw-overflow-y-auto tw-overflow-x-hidden tw-pt-8 tw-px-6 tw-bg-base-200 tw-min-w-80 tw-flex tw-justify-center" >
<div className='tw-w-full xl:tw-max-w-6xl'>
@ -66,17 +62,17 @@ export function Settings({useAuth}) {
<div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-2 tw-gap-6">
<InputText labelTitle="Name" defaultValue={user?.first_name ? user.first_name : ""} updateFormValue={(v) => setName(v)} />
<InputText placeholder="Name" defaultValue={user?.first_name ? user.first_name : ""} updateFormValue={(v) => setName(v)} />
</div>
<div className="tw-grid tw-grid-cols-1 tw-md:grid-cols-1 tw-gap-6 tw-pt-6 tw-pb-6">
<TextAreaInput labelTitle="About" defaultValue={user?.description ? user.description : ""} updateFormValue={(v) => setText(v)} />
<TextAreaInput placeholder="About me, Contact, #Tags, ..." defaultValue={user?.description ? user.description : ""} updateFormValue={(v) => setText(v)} inputStyle='tw-h-64'/>
</div>
<div className="tw-divider" ></div>
<div className="tw-grid tw-grid-cols-1 md:tw-grid-cols-2 tw-gap-6">
<InputText type='email' labelTitle="E-Mail" defaultValue={user?.email ? user.email : ""} updateFormValue={(v) => setEmail(v)} />
<InputText type='password' labelTitle="Password" defaultValue={user?.password ? user.password : ""} updateFormValue={(v) => {
<InputText type='email' placeholder="E-Mail" defaultValue={user?.email ? user.email : ""} updateFormValue={(v) => setEmail(v)} />
<InputText type='password' placeholder="new Password" defaultValue={user?.password ? user.password : ""} updateFormValue={(v) => {
setPassword(v);
setPasswordChanged(true);
}} />

View File

@ -1,4 +1,4 @@
export { UtopiaMap, Layer, Tags, Item, Tag } from './Components/Map/index';
export { UtopiaMap, Layer, Tags } from './Components/Map/index';
export {AppShell, Content, SideBar} from "./Components/AppShell"
export {AuthProvider, useAuth, LoginPage, SignupPage} from "./Components/Auth"
export {Settings} from './Components/Profile'