Merge pull request #793 from mauriceboe/fix/atlas-bucket-list-ui-overflow

fix(atlas): constrain bucket list width to prevent panel overflow
This commit is contained in:
Julien G.
2026-04-21 20:28:58 +02:00
committed by GitHub
2 changed files with 18 additions and 7 deletions
+11 -2
View File
@@ -1240,6 +1240,15 @@ interface SidebarContentProps {
function SidebarContent({ data, stats, countries, selectedCountry, countryDetail, resolveName, onTripClick, onUnmarkCountry, bucketList, bucketTab, setBucketTab, showBucketAdd, setShowBucketAdd, bucketForm, setBucketForm, onAddBucket, onDeleteBucket, onSearchBucket, onSelectBucketPoi, bucketSearchResults, setBucketSearchResults, bucketPoiMonth, setBucketPoiMonth, bucketPoiYear, setBucketPoiYear, bucketSearching, bucketSearch, setBucketSearch, t, dark }: SidebarContentProps): React.ReactElement { function SidebarContent({ data, stats, countries, selectedCountry, countryDetail, resolveName, onTripClick, onUnmarkCountry, bucketList, bucketTab, setBucketTab, showBucketAdd, setShowBucketAdd, bucketForm, setBucketForm, onAddBucket, onDeleteBucket, onSearchBucket, onSelectBucketPoi, bucketSearchResults, setBucketSearchResults, bucketPoiMonth, setBucketPoiMonth, bucketPoiYear, setBucketPoiYear, bucketSearching, bucketSearch, setBucketSearch, t, dark }: SidebarContentProps): React.ReactElement {
const { language } = useTranslation() const { language } = useTranslation()
const statsContentRef = useRef<HTMLDivElement>(null)
const [statsWidth, setStatsWidth] = useState<number | undefined>(undefined)
useEffect(() => {
const el = statsContentRef.current
if (!el || typeof ResizeObserver === 'undefined') return
const ro = new ResizeObserver(() => setStatsWidth(el.offsetWidth))
ro.observe(el)
return () => ro.disconnect()
}, [])
const bg = (o) => dark ? `rgba(255,255,255,${o})` : `rgba(0,0,0,${o})` const bg = (o) => dark ? `rgba(255,255,255,${o})` : `rgba(0,0,0,${o})`
const tp = dark ? '#f1f5f9' : '#0f172a' const tp = dark ? '#f1f5f9' : '#0f172a'
const tm = dark ? '#94a3b8' : '#64748b' const tm = dark ? '#94a3b8' : '#64748b'
@@ -1290,7 +1299,7 @@ function SidebarContent({ data, stats, countries, selectedCountry, countryDetail
// Bucket list content // Bucket list content
const bucketContent = ( const bucketContent = (
<> <>
<div className="flex items-stretch" style={{ overflowX: 'auto', padding: '0 8px' }}> <div className="flex items-stretch" style={{ overflowX: 'auto', padding: '0 8px', maxWidth: statsWidth, width: '100%' }}>
{bucketList.map(item => ( {bucketList.map(item => (
<div key={item.id} className="group flex flex-col items-center justify-center shrink-0" style={{ padding: '8px 14px', position: 'relative', minWidth: 80 }}> <div key={item.id} className="group flex flex-col items-center justify-center shrink-0" style={{ padding: '8px 14px', position: 'relative', minWidth: 80 }}>
{(() => { {(() => {
@@ -1400,7 +1409,7 @@ function SidebarContent({ data, stats, countries, selectedCountry, countryDetail
{/* Both tabs always rendered so the wider one sets the panel width */} {/* Both tabs always rendered so the wider one sets the panel width */}
<div style={{ display: 'grid' }}> <div style={{ display: 'grid' }}>
<div style={bucketTab === 'bucket' ? { visibility: 'hidden' as const, gridArea: '1/1' } : { gridArea: '1/1' }}> <div style={bucketTab === 'bucket' ? { visibility: 'hidden' as const, gridArea: '1/1' } : { gridArea: '1/1' }}>
<div className="flex items-stretch justify-center"> <div ref={statsContentRef} className="flex items-stretch justify-center">
{/* ═══ SECTION 1: Numbers ═══ */} {/* ═══ SECTION 1: Numbers ═══ */}
{/* Countries hero */} {/* Countries hero */}
+7 -5
View File
@@ -64,11 +64,13 @@ class _MockIntersectionObserver {
globalThis.IntersectionObserver = _MockIntersectionObserver as unknown as typeof IntersectionObserver; globalThis.IntersectionObserver = _MockIntersectionObserver as unknown as typeof IntersectionObserver;
// ResizeObserver — used by resizable panels // ResizeObserver — used by resizable panels
globalThis.ResizeObserver = vi.fn().mockImplementation(() => ({ class _MockResizeObserver {
observe: vi.fn(), observe = vi.fn()
unobserve: vi.fn(), unobserve = vi.fn()
disconnect: vi.fn(), disconnect = vi.fn()
})) as unknown as typeof ResizeObserver; constructor(_callback: ResizeObserverCallback) {}
}
globalThis.ResizeObserver = _MockResizeObserver as unknown as typeof ResizeObserver;
// URL.createObjectURL / revokeObjectURL — Node 22 URL.createObjectURL requires // URL.createObjectURL / revokeObjectURL — Node 22 URL.createObjectURL requires
// a native node:buffer Blob; passing a jsdom Blob throws ERR_INVALID_ARG_TYPE. // a native node:buffer Blob; passing a jsdom Blob throws ERR_INVALID_ARG_TYPE.