aboutsummaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/frontend/ride-detail-map.ts27
-rw-r--r--web/frontend/types.d.ts1
-rw-r--r--web/static/style.css10
-rw-r--r--web/views.go2
4 files changed, 32 insertions, 8 deletions
diff --git a/web/frontend/ride-detail-map.ts b/web/frontend/ride-detail-map.ts
index a9b9c06..508829c 100644
--- a/web/frontend/ride-detail-map.ts
+++ b/web/frontend/ride-detail-map.ts
@@ -41,16 +41,27 @@ export class RideDetailMap {
.addTo(this.map);
const bounds = routeLayer.getBounds();
if (bounds.isValid()) this.map.fitBounds(bounds, { padding: [24, 24], maxZoom: 15 });
- const passIcon = leaflet.divIcon({
- className: "ride-map-pass-icon",
- html: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 19 10.5 6l3.25 5.5L16 8l5 11H3Z" fill="currentColor"/></svg>',
- iconSize: [28, 28],
- iconAnchor: [14, 14],
- });
+ const passIconCache = new Map<string, DivIcon>();
+ const getPassIcon = (category: string): DivIcon => {
+ const cat = (category || "unknown").toLowerCase();
+ const valid = ["road", "track", "path", "hiking", "unknown"].includes(cat) ? cat : "unknown";
+ const cached = passIconCache.get(valid);
+ if (cached) return cached;
+ const icon = leaflet.divIcon({
+ className: `ride-map-pass-icon ride-map-pass-icon-${valid}`,
+ html: '<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M3 19 10.5 6l3.25 5.5L16 8l5 11H3Z" fill="currentColor"/></svg>',
+ iconSize: [28, 28],
+ iconAnchor: [14, 14],
+ });
+ passIconCache.set(valid, icon);
+ return icon;
+ };
for (const pass of passes) {
- const marker = leaflet.marker([pass.latitude, pass.longitude], { icon: passIcon, alt: pass.name || "Mountain pass" }).addTo(this.map);
+ const icon = getPassIcon(pass.category);
+ const marker = leaflet.marker([pass.latitude, pass.longitude], { icon, alt: pass.name || "Mountain pass" }).addTo(this.map);
const tooltip = document.createElement("span");
- tooltip.textContent = `${pass.name || "Mountain pass"} | ${Math.round(pass.elevationM)} m`;
+ const catLabel = pass.category ? ` ยท ${pass.category}` : "";
+ tooltip.textContent = `${pass.name || "Mountain pass"} | ${Math.round(pass.elevationM)} m${catLabel}`;
marker.bindTooltip(tooltip);
}
this.climbLayers = climbs.map((climb) => this.createClimbLayer(climb));
diff --git a/web/frontend/types.d.ts b/web/frontend/types.d.ts
index d4c4bdf..790abe6 100644
--- a/web/frontend/types.d.ts
+++ b/web/frontend/types.d.ts
@@ -62,6 +62,7 @@ export interface RideMapPass {
elevationM: number;
latitude: number;
longitude: number;
+ category: string;
}
export interface ClimbBounds {
diff --git a/web/static/style.css b/web/static/style.css
index 755a5cb..61e482a 100644
--- a/web/static/style.css
+++ b/web/static/style.css
@@ -47,6 +47,11 @@
--color-profile-3-6: oklch(58% 0.17 255deg);
--color-profile-6-9: oklch(58% 0.2 25deg);
--color-profile-9-plus: oklch(0% 0 0deg);
+ --color-pass-road: oklch(51% 0.14 154deg);
+ --color-pass-track: oklch(58% 0.11 85deg);
+ --color-pass-path: oklch(65% 0.17 48deg);
+ --color-pass-hiking: oklch(52% 0.07 265deg);
+ --color-pass-unknown: oklch(70% 0.04 155deg);
--color-category-1: oklch(65% 0.16 15deg);
--color-category-2: oklch(65% 0.16 60deg);
--color-category-3: oklch(65% 0.16 105deg);
@@ -129,6 +134,11 @@ select { border: 1px solid var(--color-input-border); border-radius: .55rem; pad
.ride-map { min-height: 24rem; height: min(65vh, 40rem); }
.ride-map-pass-icon { display: grid; place-items: center; width: 1.75rem !important; height: 1.75rem !important; border: 2px solid var(--color-surface); border-radius: 50%; background: var(--color-leaf); color: var(--color-on-dark); box-shadow: 0 .15rem .4rem var(--color-panel-shadow); }
.ride-map-pass-icon svg { width: 1.15rem; height: 1.15rem; }
+.ride-map-pass-icon-road { background: var(--color-pass-road); }
+.ride-map-pass-icon-track { background: var(--color-pass-track); }
+.ride-map-pass-icon-path { background: var(--color-pass-path); }
+.ride-map-pass-icon-hiking { background: var(--color-pass-hiking); }
+.ride-map-pass-icon-unknown { background: var(--color-pass-unknown); }
.ride-map-climb-start-icon, .ride-map-climb-end-icon { display: grid; place-items: center; width: 1.625rem !important; height: 1.625rem !important; border: 2px solid var(--color-surface); box-shadow: 0 .15rem .4rem var(--color-panel-shadow); }
.ride-map-climb-start-icon { border-radius: 50%; background: var(--color-forest); color: var(--color-on-dark); }
.ride-map-climb-end-icon { border-radius: .3rem; background: var(--color-accent); color: var(--color-on-dark); }
diff --git a/web/views.go b/web/views.go
index 5c8d452..9a79906 100644
--- a/web/views.go
+++ b/web/views.go
@@ -82,6 +82,7 @@ type RideMapPass struct {
ElevationM int `json:"elevationM"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
+ Category string `json:"category"`
}
type RideProfile struct {
@@ -322,6 +323,7 @@ func buildRideMapPasses(passes []mountain_pass.MountainPass) []RideMapPass {
ElevationM: mountainPass.Elevation,
Latitude: mountainPass.Coord.Lat,
Longitude: mountainPass.Coord.Lon,
+ Category: mountainPass.Category,
})
}
return mapPasses