feat(tours): bike tours in the planner, CyclOSM, and the planned cards' last points (BIK-01 to BIK-06, RTE-01, IO-01, LIB-02)

The tour type is a dropdown; a bike tour picks its profile, routes for it,
says when a point lies off every way, and shows what it runs on: surfaces,
kinds of way and, for a mountain bike, the trail grades, each pointed at on
the map. A type's own map (OpenHikingMap for a hike, CyclOSM for a bike tour)
is offered while a tour of that type is open, with an admin switch each.

From the planned cards: a hike avoids steep climbs, steps or ferries, nothing
else; a saved tour can be shared where the platform takes GPX files; and the
tours rail adds a tour from one menu: plan new, import GPX, or take one over
from another trip.
This commit is contained in:
Maurice
2026-10-19 21:33:49 +02:00
parent adcaca3c5f
commit 73237ffedb
85 changed files with 3728 additions and 647 deletions
@@ -5,7 +5,7 @@ import type { FerrataMapLayer } from '../Ferratas/useFerrataMapLayer';
import type { PaddleMapLayer } from '../Tours/paddle/paddleMapLayer';
import { isPaddleHit, type PaddleGlMap, usePaddleLayerGL } from '../Tours/paddle/usePaddleLayerGL';
import { OWN_LAYER_PREFIXES, tourRasterSourceId } from './glRasterLayers';
import type { TileHealth } from './tourRasterBases';
import type { BaseMapHealth, TileHealth } from './tourRasterBases';
/**
* A transparent raster layer laid over the basemap and under the route, such
@@ -135,17 +135,17 @@ export function useSourceTileHealthGL(
/**
* The tour planner's layers on a GL map: the via ferratas, the raster overlays its type offers,
* the paddle obstacles, and whether OpenHikingMap answers while it is the base map.
* the paddle obstacles, and whether the map on terms (OpenHikingMap, CyclOSM) answers while it is the base map.
*/
export function useTourMapLayersGL(
map: RasterOverlayGlMap | null,
ferrataLayer: FerrataMapLayer | undefined,
layers: { overlays?: readonly MapRasterOverlay[]; paddle?: PaddleMapLayer; hikingMap?: TileHealth } | undefined
layers: { overlays?: readonly MapRasterOverlay[]; paddle?: PaddleMapLayer; baseHealth?: BaseMapHealth } | undefined
) {
useFerrataMapLayerGL(map, ferrataLayer);
useRasterOverlaysGL(map, layers?.overlays);
usePaddleLayerGL(map as unknown as PaddleGlMap | null, layers?.paddle);
useSourceTileHealthGL(map, tourRasterSourceId('hiking'), layers?.hikingMap);
useSourceTileHealthGL(map, tourRasterSourceId(layers?.baseHealth?.base ?? 'hiking'), layers?.baseHealth);
}
/**