optimized layout

This commit is contained in:
Anton Tranelis 2025-10-10 12:30:42 +02:00
parent eb87b9344a
commit 3a690aaffa
6 changed files with 74 additions and 9 deletions

View File

@ -120,7 +120,7 @@ function MapContainer({ layers, map }: { layers: LayerProps[]; map: any }) {
parameterField={
layer.itemType.custom_profile_url ? 'extended.external_profile_id' : 'id'
}
text={layer.itemType.botton_label ?? 'Profile'}
text={layer.itemType.button_label ?? 'Profile'}
target={layer.itemType.custom_profile_url ? '_blank' : '_self'}
/>
)}

View File

@ -1,3 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import { MapPinIcon } from '@heroicons/react/24/solid'
import { useGeoDistance } from '#components/Map/hooks/useGeoDistance'
@ -24,6 +25,9 @@ export function ItemTitle({
}: ItemTitleProps) {
const { distance } = useGeoDistance(item.position ?? undefined)
const { formatDistance } = useFormatDistance()
const titleRef = useRef<HTMLDivElement>(null)
const containerRef = useRef<HTMLDivElement>(null)
const [fontSize, setFontSize] = useState<string>('tw:text-xl')
const { address } = useReverseGeocode(
item.position?.coordinates as [number, number] | undefined,
@ -34,10 +38,71 @@ export function ItemTitle({
const title = item.name ?? item.layer?.item_default_name
const subtitle = item.subname
useEffect(() => {
if (!containerRef.current || !title) {
return
}
const calculateFontSize = () => {
const container = containerRef.current
if (!container) return
const containerWidth = container.offsetWidth
// Create temporary element to measure text width
const measureElement = document.createElement('span')
measureElement.style.position = 'absolute'
measureElement.style.visibility = 'hidden'
measureElement.style.whiteSpace = 'nowrap'
measureElement.style.fontWeight = '700' // font-bold
measureElement.textContent = title
document.body.appendChild(measureElement)
// Measure at different font sizes - include larger sizes only if big is true
const fontSizes = big
? [
{ class: 'tw:text-2xl', pixels: 24 },
{ class: 'tw:text-xl', pixels: 20 },
{ class: 'tw:text-lg', pixels: 18 }
]
: [
{ class: 'tw:text-xl', pixels: 20 },
{ class: 'tw:text-lg', pixels: 18 }
]
let selectedSize = 'tw:text-lg'
for (const size of fontSizes) {
measureElement.style.fontSize = `${size.pixels}px`
const textWidth = measureElement.offsetWidth
if (textWidth <= containerWidth) {
selectedSize = size.class
break
}
}
document.body.removeChild(measureElement)
setFontSize(selectedSize)
}
// Initial calculation
calculateFontSize()
// Watch for container size changes
const resizeObserver = new ResizeObserver(calculateFontSize)
resizeObserver.observe(containerRef.current)
return () => {
resizeObserver.disconnect()
}
}, [title, big])
return (
<div className={`${hasAvatar ? 'tw:ml-3' : ''} tw:overflow-hidden tw:flex-1 tw:min-w-0 `}>
<div ref={containerRef} className={`${hasAvatar ? 'tw:ml-3' : ''} tw:overflow-hidden tw:flex-1 tw:min-w-0 `}>
<div
className={`${big ? 'tw:xl:text-3xl tw:text-2xl' : 'tw:text-xl'} tw:font-bold`}
ref={titleRef}
className={`${fontSize} tw:font-bold`}
title={title}
data-cy='profile-title'
>

View File

@ -8,8 +8,8 @@ import type { Item } from '#types/Item'
*/
export const StartEndView = ({ item }: { item?: Item }) => {
return (
<div className='tw:flex tw:flex-row tw:mb-4 tw:mt-4'>
<div className='tw:basis-2/5 tw:flex tw:flex-row'>
<div className='tw:flex tw:flex-row tw:mb-4 tw:mt-4 tw:bg-base-300 tw:px-4 tw:py-3 tw:rounded-selector tw:w-full'>
<div className='tw:basis-2/5 tw:flex tw:flex-row tw:font-bold'>
<CalendarIcon className='tw:h-4 tw:w-4 tw:mr-2' />
<time
className='tw:align-middle'
@ -21,7 +21,7 @@ export const StartEndView = ({ item }: { item?: Item }) => {
<div className='tw:basis-1/5 tw:place-content-center'>
<span>-</span>
</div>
<div className='tw:basis-2/5 tw:flex tw:flex-row'>
<div className='tw:basis-2/5 tw:flex tw:flex-row tw:font-bold'>
<CalendarIcon className='tw:h-4 tw:w-4 tw:mr-2' />
<time
className='tw:align-middle'

View File

@ -174,7 +174,7 @@ export function ProfileView({ attestationApi }: { attestationApi?: ItemsApi<any>
<MapOverlayPage
key={item.id}
data-cy='profile-view'
className={`tw:p-0! tw:overflow-scroll tw:m-4! tw:md:w-[calc(50%-32px)] tw:w-[calc(100%-32px)] tw:min-w-80 tw:max-w-3xl tw:left-0! tw:sm:left-auto! tw:top-0 tw:bottom-0 tw:transition-opacity tw:duration-500 ${!selectPosition ? 'tw:opacity-100 tw:pointer-events-auto' : 'tw:opacity-0 tw:pointer-events-none'} tw:max-h-[1000px]`}
className={`tw:@container tw:p-0! tw:overflow-scroll tw:m-4! tw:md:w-[calc(50%-32px)] tw:w-[calc(100%-32px)] tw:min-w-80 tw:max-w-3xl tw:left-0! tw:sm:left-auto! tw:top-0 tw:bottom-0 tw:transition-opacity tw:duration-500 ${!selectPosition ? 'tw:opacity-100 tw:pointer-events-auto' : 'tw:opacity-0 tw:pointer-events-none'} tw:max-h-[1000px]`}
>
<>
<div className={'tw:px-6 tw:pt-6'} data-cy='profile-header'>

View File

@ -4,7 +4,7 @@ import type { Item } from '#types/Item'
export const ProfileStartEndView = ({ item }: { item: Item }) => {
return (
<div className='tw:mt-2 tw:px-6 tw:max-w-xs'>
<div className='tw:mt-2 tw:px-6'>
<StartEndView item={item}></StartEndView>
</div>
)

View File

@ -18,7 +18,7 @@ export interface ItemType {
questlog: boolean
custom_profile_url?: string
small_form_edit?: boolean
botton_label?: string
button_label?: string
text_input_label?: string
show_header_view_in_form?: boolean
cta_button_label?: string