feat(tours): via ferratas on the tour as fixed legs of their own line, crossing warnings, violet ferrata look, tour list and editor polish

This commit is contained in:
Maurice
2026-10-14 19:10:57 +02:00
parent 77c4785a9d
commit 84d637f5fe
97 changed files with 1891 additions and 283 deletions
@@ -154,4 +154,14 @@ describe('ElevationProfile', () => {
expect(prepared).toHaveBeenCalledTimes(2)
unmount()
})
it('bands the stretches it is given behind the line, placed by distance along the route', () => {
const { container } = render(
<ElevationProfile samples={samples} color="currentColor" gradientId="banded" ariaLabel="Elevation profile" bands={[{ fromM: 150, toM: 300 }]} />,
)
const band = container.querySelector('[data-profile-band]')
expect(band).toHaveAttribute('x', '220')
expect(band).toHaveAttribute('width', '220')
expect(band).toHaveAttribute('fill', 'var(--map-ferrata)')
})
})
@@ -11,10 +11,12 @@ interface ElevationProfileProps {
focus?: RouteProfileFocus | null
onFocusChange?: (focus: RouteProfileFocus | null) => void
formatFocus?: (focus: RouteProfileFocus) => string
/** Stretches to mark behind the line, in metres along the route (the via ferratas a tour climbs). */
bands?: ReadonlyArray<{ fromM: number; toM: number }>
}
/** A route profile whose horizontal axis represents travelled distance. */
export default function ElevationProfile({ samples, color, height = 100, gradientId, ariaLabel, focus = null, onFocusChange, formatFocus }: ElevationProfileProps) {
export default function ElevationProfile({ samples, color, height = 100, gradientId, ariaLabel, focus = null, onFocusChange, formatFocus, bands }: ElevationProfileProps) {
const [keyboardAnnouncement, setKeyboardAnnouncement] = useState('')
const pointerFrameRef = useRef<number | null>(null)
const pendingPointerDistanceRef = useRef<number | null>(null)
@@ -117,6 +119,11 @@ export default function ElevationProfile({ samples, color, height = 100, gradien
<stop offset="100%" stopColor={color} stopOpacity="0.02" />
</linearGradient>
</defs>
{bands?.map(band => (
<rect key={`${band.fromM}-${band.toM}`} data-profile-band="true" x={(band.fromM / chart.maxDistance) * width} y={0}
width={Math.max(1, ((band.toM - band.fromM) / chart.maxDistance) * width)} height={height}
fill="var(--map-ferrata)" fillOpacity={0.16} />
))}
<path d={chart.areaPath} fill={`url(#${gradientId})`} />
<path d={chart.linePath} fill="none" stroke={color} strokeWidth={2} strokeLinejoin="round" strokeLinecap="round" vectorEffect="non-scaling-stroke" />
{focusX != null && (