mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-24 07:53:09 +00:00
2879433bd3
Capping it was the wrong half of the fix: the stays were reachable but the panel was cut off at half the rail, which is not what opening something means. It sits inside the places list's own scroller now, above the rows, so it simply grows to whatever the day's stays need — 3350px for forty of them — and the rail scrolls past it to the places. No second scrollbar, no fold. As a band of its own it could never do that: the list is the flex child that scrolls, so anything unbounded above it squeezed the list to nothing and took the rail's scrolling with it.
89 lines
3.8 KiB
TypeScript
89 lines
3.8 KiB
TypeScript
import { Fragment, type ReactNode } from 'react'
|
|
import EmptyState from '../shared/EmptyState'
|
|
import { MemoPlaceRow } from './PlacesSidebarRow'
|
|
import type { SidebarState } from './usePlacesSidebar'
|
|
import { usePluginViewContributions, PluginCardFooter } from '../Plugins/PluginContributions'
|
|
|
|
export function PlacesList({ header, ...S }: SidebarState & {
|
|
/**
|
|
* A block that sits above the places and scrolls WITH them.
|
|
*
|
|
* The Dawarich panel lives here rather than in a band of its own above the list. As its
|
|
* own band it could not grow: the list is the flex child that scrolls, so a panel with
|
|
* ten stays in it squeezed the list to nothing and took the rail's scrolling with it,
|
|
* and capping the panel left half its stays below a fold with no way to reach them.
|
|
* Inside the scroller it simply opens to its full height and the rail scrolls past it.
|
|
*/
|
|
header?: ReactNode
|
|
}) {
|
|
const {
|
|
filtered, scrollContainerRef, onScrollTopChange, filter, t, canEditPlaces, onAddPlace,
|
|
categories, selectedPlaceId, plannedIds, inDaySet, selectedIds, selectMode, selectedDayId,
|
|
isMobile, onPlaceClick, openContextMenu, onAssignToDay, toggleSelected, setDayPickerPlace, registerPlaceRow, tripId,
|
|
} = S
|
|
// Plugin-contributed columns/actions for the places view, keyed by place id (#plugins).
|
|
const contribFor = usePluginViewContributions('places', tripId)
|
|
return (
|
|
<div className="trek-stagger" style={{ flex: 1, overflowY: 'auto', minHeight: 0 }} ref={scrollContainerRef} onScroll={(e) => onScrollTopChange?.((e.currentTarget as HTMLElement).scrollTop)}>
|
|
{header}
|
|
{filtered.length === 0 ? (
|
|
/* The mascot and one line, the shape every other empty state in TREK has.
|
|
The add link stays as the state's action: an empty list of places is
|
|
one of the few that has an obvious next step. */
|
|
<EmptyState
|
|
scene="search"
|
|
mood="sad"
|
|
size={92}
|
|
fill
|
|
surface="var(--bg-secondary)"
|
|
title={filter === 'unplanned' ? t('places.allPlanned') : t('places.noneFound')}
|
|
action={canEditPlaces ? (
|
|
<button
|
|
type="button"
|
|
onClick={onAddPlace}
|
|
className="text-caption text-content underline underline-offset-2 hover:text-accent"
|
|
>
|
|
{t('places.addPlace')}
|
|
</button>
|
|
) : undefined}
|
|
/>
|
|
) : (
|
|
filtered.map(place => {
|
|
const cat = categories.find(c => c.id === place.category_id)
|
|
const isSelected = place.id === selectedPlaceId
|
|
const isPlanned = plannedIds.has(place.id)
|
|
const inDay = inDaySet.has(place.id)
|
|
const isChecked = selectedIds.has(place.id)
|
|
const contributions = contribFor(place.id)
|
|
return (
|
|
<Fragment key={place.id}>
|
|
<MemoPlaceRow
|
|
place={place}
|
|
category={cat}
|
|
isSelected={isSelected}
|
|
isPlanned={isPlanned}
|
|
inDay={inDay}
|
|
isChecked={isChecked}
|
|
selectMode={selectMode}
|
|
selectedDayId={selectedDayId}
|
|
canEditPlaces={canEditPlaces}
|
|
isMobile={isMobile}
|
|
t={t}
|
|
onPlaceClick={onPlaceClick}
|
|
onContextMenu={openContextMenu}
|
|
onAssignToDay={onAssignToDay}
|
|
toggleSelected={toggleSelected}
|
|
setDayPickerPlace={setDayPickerPlace}
|
|
registerPlaceRow={registerPlaceRow}
|
|
/>
|
|
{contributions.length > 0 && (
|
|
<div style={{ padding: '0 14px 8px 16px' }}><PluginCardFooter items={contributions} tripId={tripId} /></div>
|
|
)}
|
|
</Fragment>
|
|
)
|
|
})
|
|
)}
|
|
</div>
|
|
)
|
|
}
|