openvibers/openvibe.tours Commits
Routes draw the walk; sign-in button readable (#21)
Changes
@@@ -29,7 +29,11 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex.tr-arc { opacity: .85; }.tr-land { fill: var(--room-accent, #F98942); }.tr-pin { fill: var(--room-accent, #F98942); stroke: var(--bg-primary, #0a0f1c); stroke-width: 2; }++/* The walk between the stops, in order, under the pins. */++.tr-path { fill: none; stroke: var(--room-accent, #F98942); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 7 8; opacity: .75; }.tr-pin-n { fill: #0a0f1c; font-size: 9px; font-weight: 800; }++/* On the route map, numbers readable once the 600-wide map is scaled to a phone (about 0.6). */++.tr-map-fallback .tr-pin-n { font-size: 14px; }.tr-walk { filter: drop-shadow(0 2px 8px rgba(0,0,0,.4)); }.tr-vis-badge { display: inline-block; margin-top: 6px; padding: 4px 10px; border-radius: 999px; font-size: .72rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--room-strong, var(--accent-light, #60a5fa)); border: 1px solid var(--border, color-mix(in srgb, var(--text-primary, #fff) 12%, transparent)); }@@@ -41,6 +45,10 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex.tr-field > span { color: var(--text-secondary, #96a7c2); font-size: .8rem; font-weight: 700; }.tr-field input, .tr-field select, .tr-field textarea { width: 100%; padding: 9px 11px; border-radius: 10px; border: 1px solid var(--border, rgba(255,255,255,.16)); background: var(--bg-primary, #0a0f1c); color: inherit; font: inherit; }.tr-field input:focus-visible, .tr-field select:focus-visible, .tr-field textarea:focus-visible { outline: 2px solid var(--room-accent, #F98942); outline-offset: 1px; }++/* A link styled as a button keeps the button's own colour: ".tr a" outranked ".tr-btn", and the sign-in button on /trips was orange++ on orange (2026-11-01). */++.tr a.tr-btn { color: var(--room-on, #0a0f1c); }++.tr a.tr-btn-quiet { color: var(--text-primary, #e6edf7); }.tr-btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; border-radius: 11px; border: 1px solid transparent; background: var(--room-accent, #F98942); color: var(--room-on, #0a0f1c); font-weight: 800; font-size: .95rem; text-decoration: none; cursor: pointer; }.tr-btn:hover { filter: brightness(1.06); }.tr-btn-quiet { background: transparent; color: var(--text-primary, #e6edf7); border-color: var(--border, rgba(255,255,255,.18)); }@@@ -44,6 +44,15 @@});try { map.fitBounds(bounds, { padding: 42, maxZoom: 15, duration: 0 }); } catch (e) { /* the centre is set */ }map.on('load', function () {++ // The walk itself: a dashed line through the stops in order, under the numbered pins (2026-11-01).++ var coords = stops.map(function (s) { return [Number(s.lon), Number(s.lat)]; }).filter(function (c) { return Number.isFinite(c[0]) && Number.isFinite(c[1]); });++ if (coords.length > 1) {++ try {++ var accent = (getComputedStyle(document.documentElement).getPropertyValue('--room-accent') || '').trim() || '#F98942';++ map.addSource('tr-walk', { type: 'geojson', data: { type: 'Feature', properties: {}, geometry: { type: 'LineString', coordinates: coords } } });++ map.addLayer({ id: 'tr-walk', type: 'line', source: 'tr-walk', layout: { 'line-join': 'round', 'line-cap': 'round' }, paint: { 'line-color': accent, 'line-width': 4, 'line-opacity': 0.85, 'line-dasharray': [1.2, 1.6] } });++ } catch (e) { /* the pins alone still show the route */ }++ }var fallback = document.getElementById('tr-map-fallback');if (fallback) fallback.classList.add('tr-map-fallback-out');});@@@ -281,7 +281,8 @@ function miniMap(stops, label) {return `<figure class="tr-map-fallback" id="tr-map-fallback"><svg viewBox="0 0 600 240" role="img" aria-label="${esc(label)}"><rect width="600" height="240" rx="14" class="tr-map-bg"/><path d="M0 80 H600 M0 160 H600 M120 0 V240 M300 0 V240 M480 0 V240" class="tr-map-grid"/>--${pts.map((p, i) => `<g><circle cx="${x(Number(p.lon)).toFixed(1)}" cy="${y(Number(p.lat)).toFixed(1)}" r="9" class="tr-pin"/><text x="${x(Number(p.lon)).toFixed(1)}" y="${(y(Number(p.lat)) + 4).toFixed(1)}" text-anchor="middle" class="tr-pin-n">${i + 1}</text></g>`).join('')}++${pts.length > 1 ? `<polyline points="${pts.map((p) => `${x(Number(p.lon)).toFixed(1)},${y(Number(p.lat)).toFixed(1)}`).join(' ')}" class="tr-path"/>` : ''}++${pts.map((p, i) => `<g><circle cx="${x(Number(p.lon)).toFixed(1)}" cy="${y(Number(p.lat)).toFixed(1)}" r="14" class="tr-pin"/><text x="${x(Number(p.lon)).toFixed(1)}" y="${(y(Number(p.lat)) + 5).toFixed(1)}" text-anchor="middle" class="tr-pin-n">${i + 1}</text></g>`).join('')}</svg><figcaption>${pts.length} ${pts.length === 1 ? 'stop' : 'stops'} on the map. ${SOURCE.osm}</figcaption></figure>`;}
@@ -29,7 +29,11 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
@@ -29,7 +29,11 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
.tr-arc { opacity: .85; }
.tr-arc { opacity: .85; }
.tr-land { fill: var(--room-accent, #F98942); }
.tr-land { fill: var(--room-accent, #F98942); }
.tr-pin { fill: var(--room-accent, #F98942); stroke: var(--bg-primary, #0a0f1c); stroke-width: 2; }
.tr-pin { fill: var(--room-accent, #F98942); stroke: var(--bg-primary, #0a0f1c); stroke-width: 2; }
+/* The walk between the stops, in order, under the pins. */
+.tr-path { fill: none; stroke: var(--room-accent, #F98942); stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 7 8; opacity: .75; }
.tr-pin-n { fill: #0a0f1c; font-size: 9px; font-weight: 800; }
.tr-pin-n { fill: #0a0f1c; font-size: 9px; font-weight: 800; }
+/* On the route map, numbers readable once the 600-wide map is scaled to a phone (about 0.6). */
+.tr-map-fallback .tr-pin-n { font-size: 14px; }
.tr-walk { filter: drop-shadow(0 2px 8px rgba(0,0,0,.4)); }
.tr-walk { filter: drop-shadow(0 2px 8px rgba(0,0,0,.4)); }
.tr-vis-badge { display: inline-block; margin-top: 6px; padding: 4px 10px; border-radius: 999px; font-size: .72rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--room-strong, var(--accent-light, #60a5fa)); border: 1px solid var(--border, color-mix(in srgb, var(--text-primary, #fff) 12%, transparent)); }
.tr-vis-badge { display: inline-block; margin-top: 6px; padding: 4px 10px; border-radius: 999px; font-size: .72rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--room-strong, var(--accent-light, #60a5fa)); border: 1px solid var(--border, color-mix(in srgb, var(--text-primary, #fff) 12%, transparent)); }
@@ -41,6 +45,10 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
@@ -41,6 +45,10 @@ html, body { margin: 0; background: var(--bg-primary, #0a0f1c); color: var(--tex
.tr-field > span { color: var(--text-secondary, #96a7c2); font-size: .8rem; font-weight: 700; }
.tr-field > span { color: var(--text-secondary, #96a7c2); font-size: .8rem; font-weight: 700; }
.tr-field input, .tr-field select, .tr-field textarea { width: 100%; padding: 9px 11px; border-radius: 10px; border: 1px solid var(--border, rgba(255,255,255,.16)); background: var(--bg-primary, #0a0f1c); color: inherit; font: inherit; }
.tr-field input, .tr-field select, .tr-field textarea { width: 100%; padding: 9px 11px; border-radius: 10px; border: 1px solid var(--border, rgba(255,255,255,.16)); background: var(--bg-primary, #0a0f1c); color: inherit; font: inherit; }
.tr-field input:focus-visible, .tr-field select:focus-visible, .tr-field textarea:focus-visible { outline: 2px solid var(--room-accent, #F98942); outline-offset: 1px; }
.tr-field input:focus-visible, .tr-field select:focus-visible, .tr-field textarea:focus-visible { outline: 2px solid var(--room-accent, #F98942); outline-offset: 1px; }
+/* A link styled as a button keeps the button's own colour: ".tr a" outranked ".tr-btn", and the sign-in button on /trips was orange
+ on orange (2026-11-01). */
+.tr a.tr-btn { color: var(--room-on, #0a0f1c); }
+.tr a.tr-btn-quiet { color: var(--text-primary, #e6edf7); }
.tr-btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; border-radius: 11px; border: 1px solid transparent; background: var(--room-accent, #F98942); color: var(--room-on, #0a0f1c); font-weight: 800; font-size: .95rem; text-decoration: none; cursor: pointer; }
.tr-btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 18px; border-radius: 11px; border: 1px solid transparent; background: var(--room-accent, #F98942); color: var(--room-on, #0a0f1c); font-weight: 800; font-size: .95rem; text-decoration: none; cursor: pointer; }
.tr-btn:hover { filter: brightness(1.06); }
.tr-btn:hover { filter: brightness(1.06); }
.tr-btn-quiet { background: transparent; color: var(--text-primary, #e6edf7); border-color: var(--border, rgba(255,255,255,.18)); }
.tr-btn-quiet { background: transparent; color: var(--text-primary, #e6edf7); border-color: var(--border, rgba(255,255,255,.18)); }
@@ -44,6 +44,15 @@
@@ -44,6 +44,15 @@
});
});
try { map.fitBounds(bounds, { padding: 42, maxZoom: 15, duration: 0 }); } catch (e) { /* the centre is set */ }
try { map.fitBounds(bounds, { padding: 42, maxZoom: 15, duration: 0 }); } catch (e) { /* the centre is set */ }
map.on('load', function () {
map.on('load', function () {
+ // The walk itself: a dashed line through the stops in order, under the numbered pins (2026-11-01).
+ var coords = stops.map(function (s) { return [Number(s.lon), Number(s.lat)]; }).filter(function (c) { return Number.isFinite(c[0]) && Number.isFinite(c[1]); });
+ if (coords.length > 1) {
+ try {
+ var accent = (getComputedStyle(document.documentElement).getPropertyValue('--room-accent') || '').trim() || '#F98942';
+ map.addSource('tr-walk', { type: 'geojson', data: { type: 'Feature', properties: {}, geometry: { type: 'LineString', coordinates: coords } } });
+ map.addLayer({ id: 'tr-walk', type: 'line', source: 'tr-walk', layout: { 'line-join': 'round', 'line-cap': 'round' }, paint: { 'line-color': accent, 'line-width': 4, 'line-opacity': 0.85, 'line-dasharray': [1.2, 1.6] } });
+ } catch (e) { /* the pins alone still show the route */ }
+ }
var fallback = document.getElementById('tr-map-fallback');
var fallback = document.getElementById('tr-map-fallback');
if (fallback) fallback.classList.add('tr-map-fallback-out');
if (fallback) fallback.classList.add('tr-map-fallback-out');
});
});
@@ -281,7 +281,8 @@ function miniMap(stops, label) {
@@ -281,7 +281,8 @@ function miniMap(stops, label) {
return `<figure class="tr-map-fallback" id="tr-map-fallback"><svg viewBox="0 0 600 240" role="img" aria-label="${esc(label)}">
return `<figure class="tr-map-fallback" id="tr-map-fallback"><svg viewBox="0 0 600 240" role="img" aria-label="${esc(label)}">
<rect width="600" height="240" rx="14" class="tr-map-bg"/>
<rect width="600" height="240" rx="14" class="tr-map-bg"/>
<path d="M0 80 H600 M0 160 H600 M120 0 V240 M300 0 V240 M480 0 V240" class="tr-map-grid"/>
<path d="M0 80 H600 M0 160 H600 M120 0 V240 M300 0 V240 M480 0 V240" class="tr-map-grid"/>
-${pts.map((p, i) => `<g><circle cx="${x(Number(p.lon)).toFixed(1)}" cy="${y(Number(p.lat)).toFixed(1)}" r="9" class="tr-pin"/><text x="${x(Number(p.lon)).toFixed(1)}" y="${(y(Number(p.lat)) + 4).toFixed(1)}" text-anchor="middle" class="tr-pin-n">${i + 1}</text></g>`).join('')}
+${pts.length > 1 ? `<polyline points="${pts.map((p) => `${x(Number(p.lon)).toFixed(1)},${y(Number(p.lat)).toFixed(1)}`).join(' ')}" class="tr-path"/>` : ''}
+${pts.map((p, i) => `<g><circle cx="${x(Number(p.lon)).toFixed(1)}" cy="${y(Number(p.lat)).toFixed(1)}" r="14" class="tr-pin"/><text x="${x(Number(p.lon)).toFixed(1)}" y="${(y(Number(p.lat)) + 5).toFixed(1)}" text-anchor="middle" class="tr-pin-n">${i + 1}</text></g>`).join('')}
</svg><figcaption>${pts.length} ${pts.length === 1 ? 'stop' : 'stops'} on the map. ${SOURCE.osm}</figcaption></figure>`;
</svg><figcaption>${pts.length} ${pts.length === 1 ? 'stop' : 'stops'} on the map. ${SOURCE.osm}</figcaption></figure>`;
}
}