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