Merge branch 'main' of github.com:utopia-os/utopia-ui

This commit is contained in:
Anton Tranelis 2025-06-11 11:49:03 +02:00
commit 612f693c22
10 changed files with 62 additions and 44 deletions

View File

@ -9,6 +9,7 @@ export interface StartEndInputProps {
labelStyle?: string
updateStartValue?: (value: string) => void
updateEndValue?: (value: string) => void
containerStyle?: string
}
/**
@ -20,9 +21,10 @@ export const PopupStartEndInput = ({
labelStyle,
updateStartValue,
updateEndValue,
containerStyle,
}: StartEndInputProps) => {
return (
<div className='tw:grid tw:grid-cols-2 tw:gap-2'>
<div className={`tw:grid tw:grid-cols-2 tw:gap-2 ${containerStyle ?? ''}`}>
<TextInput
type='date'
placeholder='start'

View File

@ -67,6 +67,7 @@ describe('GalleryForm', () => {
id: '1',
width: 800,
height: 600,
type: 'image/jpeg',
},
},
{
@ -74,6 +75,7 @@ describe('GalleryForm', () => {
id: '2',
width: 1024,
height: 768,
type: 'image/jpeg',
},
},
]

View File

@ -42,6 +42,7 @@ export const GalleryForm = ({ state, setState }: Props) => {
height,
asset: await appState.assetsApi.upload(compressedFile, file.name),
name: file.name,
type: file.type,
}
})
@ -56,6 +57,7 @@ export const GalleryForm = ({ state, setState }: Props) => {
id: upload.asset.id,
width: upload.width,
height: upload.height,
type: upload.type,
},
},
],
@ -68,6 +70,7 @@ export const GalleryForm = ({ state, setState }: Props) => {
onDrop: upload,
accept: {
'image/jpeg': [],
'image/png': [],
},
})

View File

@ -6,15 +6,28 @@ import { useAppState } from '#components/AppShell/hooks/useAppState'
import type { Item } from '#types/Item'
const extensionMap = new Map([
['image/jpeg', '.jpg'],
['image/png', '.png'],
])
const getExtension = (type: string) => {
const extension = extensionMap.get(type)
if (extension) return extension
throw new Error(`Unsupported file type: ${type}`)
}
export const GalleryView = ({ item }: { item: Item }) => {
const [index, setIndex] = useState(-1)
const appState = useAppState()
const images =
item.gallery?.map((i, j) => ({
src: appState.assetsApi.url + `${i.directus_files_id.id}.jpg`,
width: i.directus_files_id.width,
height: i.directus_files_id.height,
index: j,
item.gallery?.map(({ directus_files_id: { id, type, width, height } }, index) => ({
src: `${appState.assetsApi.url}${id}${getExtension(type)}`,
width,
height,
index,
})) ?? []
if (images.length > 0)

View File

@ -21,18 +21,16 @@ export function PlusButton({
return (
<>
{hasUserPermission(collection, 'create', undefined, layer) && (
<div className='tw:dropdown tw:dropdown-top tw:dropdown-end tw:dropdown-hover tw:z-3000 tw:absolute tw:right-4 tw:bottom-4'>
<button
tabIndex={0}
className='tw:z-500 tw:btn tw:btn-circle tw:shadow'
onClick={() => {
triggerAction()
}}
style={{ backgroundColor: color, color: '#fff' }}
>
<PlusIcon className='tw:w-5 tw:h-5 tw:stroke-[2.5]' />
</button>
</div>
<button
tabIndex={0}
className='tw:btn tw:btn-circle tw:shadow tw:z-3000 tw:absolute tw:right-4 tw:bottom-4'
onClick={() => {
triggerAction()
}}
style={{ backgroundColor: color, color: '#fff' }}
>
<PlusIcon className='tw:w-5 tw:h-5 tw:stroke-[2.5]' />
</button>
)}
</>
)

View File

@ -69,7 +69,7 @@ exports[`GalleryForm > with previous images > renders 1`] = `
tabindex="0"
>
<input
accept="image/jpeg"
accept="image/jpeg,image/png"
data-testid="gallery-upload-input"
multiple=""
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
@ -149,7 +149,7 @@ exports[`GalleryForm > with uploading images > renders 1`] = `
tabindex="0"
>
<input
accept="image/jpeg"
accept="image/jpeg,image/png"
data-testid="gallery-upload-input"
multiple=""
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"
@ -193,7 +193,7 @@ exports[`GalleryForm > without previous images > renders 1`] = `
tabindex="0"
>
<input
accept="image/jpeg"
accept="image/jpeg,image/png"
data-testid="gallery-upload-input"
multiple=""
style="border: 0px; clip: rect(0, 0, 0, 0); clip-path: inset(50%); height: 1px; margin: 0px -1px -1px 0px; overflow: hidden; padding: 0px; position: absolute; width: 1px; white-space: nowrap;"

View File

@ -8,7 +8,7 @@ import { useEffect, useRef, useState } from 'react'
import { toast } from 'react-toastify'
import { useAuth } from '#components/Auth/useAuth'
import { TextInput, TextAreaInput } from '#components/Input'
import { TextInput } from '#components/Input'
import { useFilterTags } from '#components/Map/hooks/useFilter'
import { useAddItem, useItems, useRemoveItem } from '#components/Map/hooks/useItems'
import { useLayers } from '#components/Map/hooks/useLayers'
@ -33,15 +33,13 @@ export const OverlayItemsIndexPage = ({
url,
layerName,
parameterField,
plusButton = true,
}: {
layerName: string
url: string
parameterField?: string
plusButton?: boolean
}) => {
const [loading, setLoading] = useState<boolean>(false)
const [addItemPopupType, setAddItemPopupType] = useState<string>('')
const [addItemPopupOpen, setAddItemPopupOpen] = useState<boolean>(false)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const parameterFieldDummy = parameterField
@ -52,12 +50,10 @@ export const OverlayItemsIndexPage = ({
}
useEffect(() => {
scroll()
}, [addItemPopupType])
useEffect(() => {
setAddItemPopupType('')
}, [layerName])
if (addItemPopupOpen) {
scroll()
}
}, [addItemPopupOpen])
const tags = useTags()
const addTag = useAddTag()
@ -106,7 +102,7 @@ export const OverlayItemsIndexPage = ({
}
addItem({ ...formItem, user_created: user ?? undefined, id: uuid, layer, public_edit: !user })
setLoading(false)
setAddItemPopupType('')
setAddItemPopupOpen(false)
}
const deleteItem = async (item: Item) => {
@ -174,15 +170,18 @@ export const OverlayItemsIndexPage = ({
/>
</div>
))}
{addItemPopupType === 'place' && (
{addItemPopupOpen && (
<form ref={tabRef} autoComplete='off' onSubmit={(e) => submitNewItem(e)}>
<div className='tw:cursor-pointer tw:break-inside-avoid card tw:border-[1px] tw:border-base-300 card-body tw:shadow-xl tw:bg-base-100 tw:text-base-content tw:p-6 tw:mb-10'>
<label
className='btn btn-sm tw:rounded-2xl btn-circle btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
onClick={() => setAddItemPopupType('')}
className='tw:btn tw:btn-sm tw:rounded-2xl tw:btn-circle tw:btn-ghost tw:hover:bg-transparent tw:absolute tw:right-0 tw:top-0 tw:text-gray-600'
onClick={() => setAddItemPopupOpen(false)}
>
<p className='tw:text-center'></p>
</label>
<div className='tw:flex tw:justify-center tw:mb-4'>
<b className='tw:text-xl tw:text-center tw:font-bold'>{layer?.menuText}</b>
</div>
<TextInput
type='text'
placeholder='Name'
@ -190,13 +189,9 @@ export const OverlayItemsIndexPage = ({
defaultValue={''}
inputStyle=''
/>
{layer?.itemType.show_start_end_input && <PopupStartEndInput />}
<TextAreaInput
placeholder='Text'
dataField='text'
defaultValue={''}
inputStyle='tw:h-40 tw:mt-5'
/>
{layer?.itemType.show_start_end_input && (
<PopupStartEndInput containerStyle='tw:mt-3' showLabels={false} />
)}
<div className='tw:flex tw:justify-center'>
<button
className={
@ -217,11 +212,11 @@ export const OverlayItemsIndexPage = ({
</div>
</MapOverlayPage>
{plusButton && (
{!layer?.userProfileLayer && (
<PlusButton
layer={layer}
triggerAction={() => {
setAddItemPopupType('place')
setAddItemPopupOpen(true)
scroll()
}}
color={'#777'}

View File

@ -0,0 +1,3 @@
.yarl__portal_open {
z-index: 10050;
}

View File

@ -15,3 +15,4 @@ import '#assets/css/leaflet.css'
import '#assets/css/color-picker.css'
import '#assets/css/markdown.css'
import '#assets/css/tiptap.css'
import '#assets/css/gallery.css'

1
src/types/Item.d.ts vendored
View File

@ -12,6 +12,7 @@ interface GalleryItem {
id: string
width: number
height: number
type: string
}
}