diff --git a/client/src/components/Planner/PlacesSidebar.tsx b/client/src/components/Planner/PlacesSidebar.tsx index a9d5f6f9b..8cb05b3ef 100644 --- a/client/src/components/Planner/PlacesSidebar.tsx +++ b/client/src/components/Planner/PlacesSidebar.tsx @@ -65,34 +65,27 @@ const PlacesSidebar = React.memo(function PlacesSidebar(props: PlacesSidebarProp )} - {/* Stays Dawarich recorded on these dates, waiting to be reviewed (#2279). - Above the list because that is what they become, and the panel renders - nothing at all when there is nothing pending — an integration that is - connected and quiet should be invisible rather than a permanent empty - card. */} - {/* Capped and scrolling on its own. Open, the panel is as tall as the day has stays — - ten of them on a day of driving — and with nothing holding it back it pushed the - places list, which is the flex child that scrolls, down to nothing: the rail - stopped scrolling and half the stays sat below the bottom edge with no way to - reach them. Half the rail at most, so the list it sits above is always still a - list. */} -
- days.map(day => ({ - id: day.id, - ...formatDayOption(day.day_number, day.date, locale, t), - }))} - // The place it just created belongs on the map and in the list - // now, not after a reload. - onAccepted={() => { void refreshTripAfterAccept(tripId) }} - initiallyCollapsed - /> -
- - {/* Liste */} - + {/* Liste, with the Dawarich stays riding on top of it inside the same scroller — + see the `header` prop for why they are not a band of their own. */} + + days.map(day => ({ + id: day.id, + ...formatDayOption(day.day_number, day.date, locale, t), + }))} + // The place it just created belongs on the map and in the list + // now, not after a reload. + onAccepted={() => { void refreshTripAfterAccept(tripId) }} + initiallyCollapsed + /> + + )} + /> {dayPickerPlace && } {listImportOpen && } diff --git a/client/src/components/Planner/PlacesSidebarList.tsx b/client/src/components/Planner/PlacesSidebarList.tsx index 1c0f60799..ccc1843ff 100644 --- a/client/src/components/Planner/PlacesSidebarList.tsx +++ b/client/src/components/Planner/PlacesSidebarList.tsx @@ -1,10 +1,21 @@ -import { Fragment } from 'react' +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(S: SidebarState) { +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, @@ -14,6 +25,7 @@ export function PlacesList(S: SidebarState) { const contribFor = usePluginViewContributions('places', tripId) return (
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