feat(tours): tidy the tour editor and tour list, set points only on purpose, name waypoints on the map

This commit is contained in:
Maurice
2026-10-14 17:13:24 +02:00
parent 160bc89e78
commit e3983ef857
72 changed files with 2607 additions and 869 deletions
@@ -80,9 +80,7 @@ describe('CustomSelect consumer contracts', () => {
planner={planner({ saveOutcome: tour, editingPlaceId: 42 })}
tours={[tour]} days={days} loading={false} onAssignToDay={onAssignToDay} onViewGpxTour={vi.fn()}
/></TranslationProvider>)
const saveBanner = screen.getByText('Tour saved').closest('[role="status"]') as HTMLElement
expect(within(saveBanner).getByRole('button', { name: 'Plan another' })).toBeInTheDocument()
expect(within(saveBanner).queryByRole('button', { name: 'Assign to a day' })).not.toBeInTheDocument()
expect(screen.queryByRole('button', { name: 'Assign to a day' })).not.toBeInTheDocument()
await user.click(screen.getByRole('button', { name: 'Add to day: Ridge walk' }))
const dayOption = screen.getByRole('button', { name: /Summit day/ })
expect(dayOption).toHaveTextContent(/Day 1/)
@@ -60,7 +60,7 @@ describe('ElevationProfile', () => {
expect(onFocus).toHaveBeenLastCalledWith({ distanceMeters: 150, elevationMeters: 187.5, lat: 48.015, lng: 11.015, sampleIndex: 1 })
expect(profile.querySelector('[data-profile-focus-line]')).toBeInTheDocument()
expect(profile.querySelector('[data-profile-focus-point]')).toBeInTheDocument()
expect(profile.parentElement?.querySelector('[data-profile-focus-point]')).toBeInTheDocument()
const readout = profile.parentElement?.querySelector('[data-profile-focus-readout]')
expect(readout?.textContent).toBe('150 m · 187.5 m')
expect(readout).toHaveClass('rounded-lg', 'border-edge-faint', 'bg-surface-card', 'text-content', 'shadow-elevated')
@@ -68,7 +68,7 @@ describe('ElevationProfile', () => {
expect(readout).toHaveStyle({ maxWidth: 'min(164px, calc(100% - 8px))' })
expect(profile).toHaveStyle({ fontFamily: 'var(--font-system)' })
expect(profile.querySelector('[data-profile-focus-line]')).toHaveAttribute('stroke', 'var(--text-muted)')
expect(profile.querySelector('[data-profile-focus-point]')).toHaveAttribute('stroke', 'var(--bg-card)')
expect(profile.parentElement?.querySelector('[data-profile-focus-point]')).toHaveAttribute('stroke', 'var(--bg-card)')
expect(profile.parentElement?.querySelector('[aria-live="polite"]')?.textContent).toBe('')
fireEvent.pointerMove(profile, { clientX: -50, pointerType: 'mouse' })
act(() => frames.shift()?.(32))
@@ -122,10 +122,15 @@ export default function ElevationProfile({ samples, color, height = 100, gradien
{focusX != null && (
<g pointerEvents="none" aria-hidden="true">
<line data-profile-focus-line="true" x1={focusX} x2={focusX} y1={4} y2={height - 4} stroke="var(--text-muted)" strokeOpacity="0.85" strokeWidth={1} strokeDasharray="3 3" vectorEffect="non-scaling-stroke" />
{focusY != null && <circle data-profile-focus-point="true" cx={focusX} cy={focusY} r={4} fill={color} stroke="var(--bg-card)" strokeWidth={2} vectorEffect="non-scaling-stroke" />}
</g>
)}
</svg>
{/* The point in an unscaled layer of its own: the chart above stretches to the width, which would squash a circle drawn in it into an ellipse. */}
{focusX != null && focusY != null && (
<svg width="100%" height={height} aria-hidden="true" className="pointer-events-none absolute inset-x-0 top-0 overflow-visible">
<circle data-profile-focus-point="true" cx={`${(focusX / width) * 100}%`} cy={focusY} r={4} fill={color} stroke="var(--bg-card)" strokeWidth={2} />
</svg>
)}
{interactive && focusX != null && (
<div
data-profile-focus-readout="true"