mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-04-06 01:25:33 +00:00
Compare commits
12 Commits
59a4501f25
...
69c735bae3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69c735bae3 | ||
| b6cb5db804 | |||
|
|
b0e952c4df | ||
| 6004ca095a | |||
|
|
c3edabdbb9 | ||
| c704308010 | |||
| 9c0a11ceee | |||
|
|
4b444b65c2 | ||
|
|
cc2f4badbb | ||
|
|
6287bb78e8 | ||
|
|
0c60f9fc7f | ||
|
|
be3fca7925 |
2434
examples/2-static-layers/package-lock.json
generated
2434
examples/2-static-layers/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,8 +11,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"utopia-ui": "^3.0.35"
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.17.0",
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||
@ -8,8 +7,7 @@
|
||||
/* eslint-disable @typescript-eslint/prefer-optional-chain */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import { Children, isValidElement, useEffect, useState } from 'react'
|
||||
import { Marker, Tooltip, useMap, useMapEvents } from 'react-leaflet'
|
||||
import { useLocation } from 'react-router-dom'
|
||||
import { Marker, Tooltip } from 'react-leaflet'
|
||||
|
||||
import { encodeTag } from '#utils/FormatTags'
|
||||
import { getValue } from '#utils/GetValue'
|
||||
@ -79,8 +77,6 @@ export const Layer = ({
|
||||
const addPopup = useAddPopup()
|
||||
const leafletRefs = useLeafletRefs()
|
||||
|
||||
const location = useLocation()
|
||||
|
||||
const allTagsLoaded = useAllTagsLoaded()
|
||||
const allItemsLoaded = useAllItemsLoaded()
|
||||
|
||||
@ -92,8 +88,6 @@ export const Layer = ({
|
||||
const [newTagsToAdd, setNewTagsToAdd] = useState<Tag[]>([])
|
||||
const [tagsReady, setTagsReady] = useState<boolean>(false)
|
||||
|
||||
const map = useMap()
|
||||
|
||||
const isLayerVisible = useIsLayerVisible()
|
||||
|
||||
const isGroupTypeVisible = useIsGroupTypeVisible()
|
||||
@ -170,64 +164,6 @@ export const Layer = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data, api])
|
||||
|
||||
useMapEvents({
|
||||
popupopen: (e) => {
|
||||
const item = Object.entries(leafletRefs).find((r) => r[1].popup === e.popup)?.[1].item
|
||||
if (item?.layer?.name === name && window.location.pathname.split('/')[1] !== item.id) {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (!location.pathname.includes('/item/')) {
|
||||
window.history.pushState(
|
||||
{},
|
||||
'',
|
||||
`/${item.id}` + `${params.toString() !== '' ? `?${params}` : ''}`,
|
||||
)
|
||||
}
|
||||
let title = ''
|
||||
if (item.name) title = item.name
|
||||
else if (item.layer.itemNameField) title = getValue(item, item.layer.itemNameField)
|
||||
document.title = `${document.title.split('-')[0]} - ${title}`
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const openPopup = () => {
|
||||
if (
|
||||
window.location.pathname.split('/').length <= 1 ||
|
||||
window.location.pathname.split('/')[1] === ''
|
||||
) {
|
||||
map.closePopup()
|
||||
} else {
|
||||
if (window.location.pathname.split('/')[1]) {
|
||||
const id = window.location.pathname.split('/')[1]
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
const ref = leafletRefs[id]
|
||||
if (ref?.marker && ref.item.layer?.name === name) {
|
||||
ref.marker &&
|
||||
clusterRef.hasLayer(ref.marker) &&
|
||||
clusterRef?.zoomToShowLayer(ref.marker, () => {
|
||||
ref.marker.openPopup()
|
||||
})
|
||||
let title = ''
|
||||
if (ref.item.name) title = ref.item.name
|
||||
else if (ref.item.layer.itemNameField)
|
||||
title = getValue(ref.item.name, ref.item.layer.itemNameField)
|
||||
document.title = `${document.title.split('-')[0]} - ${title}`
|
||||
document
|
||||
.querySelector('meta[property="og:title"]')
|
||||
?.setAttribute('content', ref.item.name)
|
||||
document
|
||||
.querySelector('meta[property="og:description"]')
|
||||
?.setAttribute('content', ref.item.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
openPopup()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [leafletRefs, location])
|
||||
|
||||
useEffect(() => {
|
||||
if (tagsReady) {
|
||||
const processedTags = {}
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
import { LatLng } from 'leaflet'
|
||||
import { MapContainer } from 'react-leaflet'
|
||||
|
||||
import { ContextWrapper } from '#components/AppShell/ContextWrapper'
|
||||
|
||||
import { UtopiaMapInner } from './UtopiaMapInner'
|
||||
@ -7,10 +10,37 @@ import type { UtopiaMapProps } from '#types/UtopiaMapProps'
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import 'react-toastify/dist/ReactToastify.css'
|
||||
|
||||
function UtopiaMap(props: UtopiaMapProps) {
|
||||
function UtopiaMap({
|
||||
height = '500px',
|
||||
width = '100%',
|
||||
center = [50.6, 9.5],
|
||||
zoom = 10,
|
||||
children,
|
||||
geo,
|
||||
showFilterControl = false,
|
||||
showGratitudeControl = false,
|
||||
showLayerControl = true,
|
||||
infoText,
|
||||
}: UtopiaMapProps) {
|
||||
return (
|
||||
<ContextWrapper>
|
||||
<UtopiaMapInner {...props} />
|
||||
<MapContainer
|
||||
style={{ height, width }}
|
||||
center={new LatLng(center[0], center[1])}
|
||||
zoom={zoom}
|
||||
zoomControl={false}
|
||||
maxZoom={19}
|
||||
>
|
||||
<UtopiaMapInner
|
||||
geo={geo}
|
||||
showFilterControl={showFilterControl}
|
||||
showGratitudeControl={showGratitudeControl}
|
||||
showLayerControl={showLayerControl}
|
||||
infoText={infoText}
|
||||
>
|
||||
{children}
|
||||
</UtopiaMapInner>
|
||||
</MapContainer>
|
||||
</ContextWrapper>
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,29 +6,24 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||
import { LatLng } from 'leaflet'
|
||||
import {
|
||||
Children,
|
||||
cloneElement,
|
||||
createRef,
|
||||
isValidElement,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { TileLayer, MapContainer, useMapEvents, GeoJSON } from 'react-leaflet'
|
||||
import { Children, cloneElement, isValidElement, useEffect, useRef, useState } from 'react'
|
||||
import { TileLayer, useMapEvents, GeoJSON, useMap } from 'react-leaflet'
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import 'leaflet/dist/leaflet.css'
|
||||
import MarkerClusterGroup from 'react-leaflet-cluster'
|
||||
import { Outlet } from 'react-router-dom'
|
||||
import { Outlet, useLocation } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
// eslint-disable-next-line import/no-unassigned-import
|
||||
import './UtopiaMap.css'
|
||||
|
||||
import { containsUUID } from '#utils/ContainsUUID'
|
||||
import { getValue } from '#utils/GetValue'
|
||||
|
||||
import { useClusterRef, useSetClusterRef } from './hooks/useClusterRef'
|
||||
import { useAddVisibleLayer } from './hooks/useFilter'
|
||||
import { useLayers } from './hooks/useLayers'
|
||||
import { useLeafletRefs } from './hooks/useLeafletRefs'
|
||||
import {
|
||||
useSelectPosition,
|
||||
useSetMapClicked,
|
||||
@ -48,13 +43,7 @@ import type { ItemFormPopupProps } from '#types/ItemFormPopupProps'
|
||||
import type { UtopiaMapProps } from '#types/UtopiaMapProps'
|
||||
import type { Feature, Geometry as GeoJSONGeometry } from 'geojson'
|
||||
|
||||
const mapDivRef = createRef()
|
||||
|
||||
export function UtopiaMapInner({
|
||||
height = '500px',
|
||||
width = '100%',
|
||||
center = [50.6, 9.5],
|
||||
zoom = 10,
|
||||
children,
|
||||
geo,
|
||||
showFilterControl = false,
|
||||
@ -62,7 +51,6 @@ export function UtopiaMapInner({
|
||||
showLayerControl = true,
|
||||
infoText,
|
||||
}: UtopiaMapProps) {
|
||||
// Hooks that rely on contexts, called after ContextWrapper is provided
|
||||
const selectNewItemPosition = useSelectPosition()
|
||||
const setSelectNewItemPosition = useSetSelectPosition()
|
||||
const setClusterRef = useSetClusterRef()
|
||||
@ -72,6 +60,10 @@ export function UtopiaMapInner({
|
||||
|
||||
const layers = useLayers()
|
||||
const addVisibleLayer = useAddVisibleLayer()
|
||||
const leafletRefs = useLeafletRefs()
|
||||
|
||||
const location = useLocation()
|
||||
const map = useMap()
|
||||
|
||||
useEffect(() => {
|
||||
layers.forEach((layer) => addVisibleLayer(layer))
|
||||
@ -105,9 +97,64 @@ export function UtopiaMapInner({
|
||||
return null
|
||||
}
|
||||
|
||||
useMapEvents({
|
||||
popupopen: (e) => {
|
||||
const item = Object.entries(leafletRefs).find((r) => r[1].popup === e.popup)?.[1].item
|
||||
if (window.location.pathname.split('/')[1] !== item?.id) {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (!location.pathname.includes('/item/')) {
|
||||
window.history.pushState(
|
||||
{},
|
||||
'',
|
||||
`/${item?.id}` + `${params.toString() !== '' ? `?${params}` : ''}`,
|
||||
)
|
||||
}
|
||||
let title = ''
|
||||
if (item?.name) title = item.name
|
||||
else if (item?.layer?.itemNameField) title = getValue(item, item.layer.itemNameField)
|
||||
document.title = `${document.title.split('-')[0]} - ${title}`
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const openPopup = () => {
|
||||
if (!containsUUID(window.location.pathname)) {
|
||||
map.closePopup()
|
||||
} else {
|
||||
if (window.location.pathname.split('/')[1]) {
|
||||
const id = window.location.pathname.split('/')[1]
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
const ref = leafletRefs[id]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (ref) {
|
||||
clusterRef.hasLayer(ref.marker) &&
|
||||
clusterRef?.zoomToShowLayer(ref.marker, () => {
|
||||
ref.marker.openPopup()
|
||||
})
|
||||
let title = ''
|
||||
if (ref.item.name) title = ref.item.name
|
||||
else if (ref.item.layer?.itemNameField)
|
||||
title = getValue(ref.item.name, ref.item.layer.itemNameField)
|
||||
document.title = `${document.title.split('-')[0]} - ${title}`
|
||||
document
|
||||
.querySelector('meta[property="og:title"]')
|
||||
?.setAttribute('content', ref.item.name)
|
||||
document
|
||||
.querySelector('meta[property="og:description"]')
|
||||
?.setAttribute('content', ref.item.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
openPopup()
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [leafletRefs, location])
|
||||
|
||||
const resetMetaTags = () => {
|
||||
const params = new URLSearchParams(window.location.search)
|
||||
if (!window.location.pathname.includes('/item/')) {
|
||||
if (!containsUUID(window.location.pathname)) {
|
||||
window.history.pushState({}, '', '/' + `${params.toString() !== '' ? `?${params}` : ''}`)
|
||||
}
|
||||
document.title = document.title.split('-')[0]
|
||||
@ -130,62 +177,53 @@ export function UtopiaMapInner({
|
||||
<div
|
||||
className={`tw-h-full ${selectNewItemPosition != null ? 'crosshair-cursor-enabled' : undefined}`}
|
||||
>
|
||||
<MapContainer
|
||||
ref={mapDivRef}
|
||||
style={{ height, width }}
|
||||
center={new LatLng(center[0], center[1])}
|
||||
zoom={zoom}
|
||||
zoomControl={false}
|
||||
<Outlet />
|
||||
<Control position='topLeft' zIndex='1000' absolute>
|
||||
<SearchControl />
|
||||
<TagsControl />
|
||||
</Control>
|
||||
<Control position='bottomLeft' zIndex='999' absolute>
|
||||
{showFilterControl && <FilterControl />}
|
||||
{showLayerControl && <LayerControl />}
|
||||
{showGratitudeControl && <GratitudeControl />}
|
||||
</Control>
|
||||
<TileLayer
|
||||
maxZoom={19}
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url='https://tile.osmand.net/hd/{z}/{x}/{y}.png'
|
||||
/>
|
||||
<MarkerClusterGroup
|
||||
ref={(r) => setClusterRef(r)}
|
||||
showCoverageOnHover
|
||||
chunkedLoading
|
||||
maxClusterRadius={50}
|
||||
removeOutsideVisibleBounds={false}
|
||||
>
|
||||
<Outlet />
|
||||
<Control position='topLeft' zIndex='1000' absolute>
|
||||
<SearchControl />
|
||||
<TagsControl />
|
||||
</Control>
|
||||
<Control position='bottomLeft' zIndex='999' absolute>
|
||||
{showFilterControl && <FilterControl />}
|
||||
{showLayerControl && <LayerControl />}
|
||||
{showGratitudeControl && <GratitudeControl />}
|
||||
</Control>
|
||||
<TileLayer
|
||||
maxZoom={19}
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||||
url='https://tile.osmand.net/hd/{z}/{x}/{y}.png'
|
||||
/>
|
||||
<MarkerClusterGroup
|
||||
ref={(r) => setClusterRef(r)}
|
||||
showCoverageOnHover
|
||||
chunkedLoading
|
||||
maxClusterRadius={50}
|
||||
removeOutsideVisibleBounds={false}
|
||||
>
|
||||
{Children.toArray(children).map((child) =>
|
||||
isValidElement<{
|
||||
setItemFormPopup: React.Dispatch<React.SetStateAction<ItemFormPopupProps>>
|
||||
itemFormPopup: ItemFormPopupProps | null
|
||||
clusterRef: React.MutableRefObject<undefined>
|
||||
}>(child)
|
||||
? cloneElement(child, { setItemFormPopup, itemFormPopup, clusterRef })
|
||||
: child,
|
||||
)}
|
||||
</MarkerClusterGroup>
|
||||
{geo && (
|
||||
<GeoJSON
|
||||
data={geo}
|
||||
onEachFeature={onEachFeature}
|
||||
eventHandlers={{
|
||||
click: (e) => {
|
||||
if (selectNewItemPosition) {
|
||||
e.layer.closePopup()
|
||||
setMapClicked({ position: e.latlng, setItemFormPopup })
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
{Children.toArray(children).map((child) =>
|
||||
isValidElement<{
|
||||
setItemFormPopup: React.Dispatch<React.SetStateAction<ItemFormPopupProps>>
|
||||
itemFormPopup: ItemFormPopupProps | null
|
||||
clusterRef: React.MutableRefObject<undefined>
|
||||
}>(child)
|
||||
? cloneElement(child, { setItemFormPopup, itemFormPopup, clusterRef })
|
||||
: child,
|
||||
)}
|
||||
<MapEventListener />
|
||||
</MapContainer>
|
||||
</MarkerClusterGroup>
|
||||
{geo && (
|
||||
<GeoJSON
|
||||
data={geo}
|
||||
onEachFeature={onEachFeature}
|
||||
eventHandlers={{
|
||||
click: (e) => {
|
||||
if (selectNewItemPosition) {
|
||||
e.layer.closePopup()
|
||||
setMapClicked({ position: e.latlng, setItemFormPopup })
|
||||
}
|
||||
},
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<MapEventListener />
|
||||
<AddButton triggerAction={setSelectNewItemPosition} />
|
||||
{selectNewItemPosition != null && (
|
||||
<SelectPosition setSelectNewItemPosition={setSelectNewItemPosition} />
|
||||
|
||||
@ -1,11 +1,3 @@
|
||||
/* eslint-disable @typescript-eslint/no-misused-promises */
|
||||
/* eslint-disable @typescript-eslint/prefer-optional-chain */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/require-await */
|
||||
/* eslint-disable @typescript-eslint/no-floating-promises */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
/* eslint-disable @typescript-eslint/restrict-plus-operands */
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||
import { useRef, useState, useEffect } from 'react'
|
||||
import { useNavigate } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
@ -19,7 +11,7 @@ import { MapOverlayPage } from './MapOverlayPage'
|
||||
import type { Item } from '#types/Item'
|
||||
import type { ItemsApi } from '#types/ItemsApi'
|
||||
|
||||
export const AttestationForm = ({ api }: { api?: ItemsApi<any> }) => {
|
||||
export const AttestationForm = ({ api }: { api?: ItemsApi<unknown> }) => {
|
||||
const items = useItems()
|
||||
const appState = useAppState()
|
||||
const [users, setUsers] = useState<Item[]>()
|
||||
@ -46,10 +38,12 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<any> }) => {
|
||||
setInputValue(event.target.value)
|
||||
}
|
||||
|
||||
const sendAttestation = async () => {
|
||||
const sendAttestation = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const to: any[] = []
|
||||
users?.map((u) => to.push({ directus_users_id: u.user_created?.id }))
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
api?.createItem &&
|
||||
toast
|
||||
.promise(
|
||||
@ -65,6 +59,7 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<any> }) => {
|
||||
success: 'Attestation created',
|
||||
error: {
|
||||
render({ data }) {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
||||
return `${data}`
|
||||
},
|
||||
},
|
||||
@ -73,8 +68,10 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<any> }) => {
|
||||
.then(() =>
|
||||
navigate(
|
||||
'/item/' +
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
||||
items.find(
|
||||
(i) =>
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
i.user_created?.id === to[0].directus_users_id &&
|
||||
i.layer?.itemType.name === 'player',
|
||||
)?.id +
|
||||
@ -92,29 +89,28 @@ export const AttestationForm = ({ api }: { api?: ItemsApi<any> }) => {
|
||||
<div className='tw-text-center tw-text-xl tw-font-bold'>Gratitude</div>
|
||||
<div className='tw-text-center tw-text-base tw-text-gray-400'>to</div>
|
||||
<div className='tw-flex tw-flex-row tw-justify-center tw-items-center tw-flex-wrap'>
|
||||
{users &&
|
||||
users.map(
|
||||
(u, k) => (
|
||||
<div key={k} className='tw-flex tw-items-center tw-space-x-3 tw-mx-2 tw-my-1'>
|
||||
{u.image ? (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-mask tw-mask-circle tw-w-8 tw-h-8'>
|
||||
<img
|
||||
src={appState.assetsApi.url + u.image + '?width=40&heigth=40'}
|
||||
alt='Avatar'
|
||||
/>
|
||||
</div>
|
||||
{users?.map(
|
||||
(u, k) => (
|
||||
<div key={k} className='tw-flex tw-items-center tw-space-x-3 tw-mx-2 tw-my-1'>
|
||||
{u.image ? (
|
||||
<div className='tw-avatar'>
|
||||
<div className='tw-mask tw-mask-circle tw-w-8 tw-h-8'>
|
||||
<img
|
||||
src={appState.assetsApi.url + u.image + '?width=40&heigth=40'}
|
||||
alt='Avatar'
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-w-8 tw-h-8'></div>
|
||||
)}
|
||||
<div>
|
||||
<div className='tw-font-bold'>{u.name}</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw-mask tw-mask-circle tw-text-xl md:tw-text-2xl tw-bg-slate-200 tw-rounded-full tw-w-8 tw-h-8'></div>
|
||||
)}
|
||||
<div>
|
||||
<div className='tw-font-bold'>{u.name}</div>
|
||||
</div>
|
||||
),
|
||||
', ',
|
||||
)}
|
||||
</div>
|
||||
),
|
||||
', ',
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='tw-w-full'>
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
||||
/* eslint-disable @typescript-eslint/restrict-template-expressions */
|
||||
import { useState } from 'react'
|
||||
|
||||
interface Props {
|
||||
selectedEmoji: string
|
||||
selectedColor: string
|
||||
selectedShape: string
|
||||
setSelectedEmoji: (emoji: string) => void
|
||||
setSelectedColor: (color: string) => void
|
||||
setSelectedShape: (shape: string) => void
|
||||
}
|
||||
|
||||
export const EmojiPicker = ({
|
||||
// eslint-disable-next-line react/prop-types
|
||||
selectedEmoji,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
selectedColor,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
selectedShape,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
setSelectedEmoji,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
setSelectedColor,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
setSelectedShape,
|
||||
}) => {
|
||||
}: Props) => {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
const emojis = [
|
||||
@ -77,17 +79,17 @@ export const EmojiPicker = ({
|
||||
setIsOpen(!isOpen)
|
||||
}
|
||||
|
||||
const selectEmoji = (emoji) => {
|
||||
const selectEmoji = (emoji: string) => {
|
||||
setSelectedEmoji(emoji)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
const selectShape = (shape) => {
|
||||
const selectShape = (shape: string) => {
|
||||
setSelectedShape(shape)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
const selectColor = (color) => {
|
||||
const selectColor = (color: string) => {
|
||||
setSelectedColor(color)
|
||||
setIsOpen(false)
|
||||
}
|
||||
|
||||
4
src/Utils/ContainsUUID.ts
Normal file
4
src/Utils/ContainsUUID.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export function containsUUID(str: string): boolean {
|
||||
const uuidRegex = /[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i
|
||||
return uuidRegex.test(str)
|
||||
}
|
||||
@ -19,7 +19,6 @@ export {
|
||||
export { AppShell, Content, SideBar, Sitemap } from './Components/AppShell'
|
||||
export {
|
||||
AuthProvider,
|
||||
useAuth,
|
||||
LoginPage,
|
||||
SignupPage,
|
||||
RequestPasswordPage,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user