Draw the Plani's radius ring in the theme accent

8809785 · Gabriel Morell · 2026-09-03 19:21

13 files +39 -8
Message
{commit_body(@commit)}

Files changed

modified apps/room_sanctum/assets/js/leaflet/basemap.js
+18 −3
@@ -126,6 +126,23 @@ function asColor(value) {
126 126 return /^[\d.]+\s+[\d.]+%\s+[\d.]+%$/.test(value) ? `hsl(${value})` : value
127 127 }
128 128
129 +/**
130 + * A colour that may be named as a theme variable.
131 + *
132 + * `--a` reads the current theme's accent, `#38bdf8` is passed through, and
133 + * anything falsy comes back null so the caller can pick its own default. The
134 + * rule the basemap's `tint` option already used, pulled out so a line can be
135 + * coloured by the same names -- otherwise every new caller reinvents which of
136 + * these two forms it accepts, and they drift.
137 + *
138 + * `el` is the element to resolve against, which matters inside a shadow root
139 + * whose host may sit under a different data-theme than <html>.
140 + */
141 +export function themeColor(value, el) {
142 + if (!value) return null
143 + return asColor(value.startsWith('--') ? cssVar(value, el) : value)
144 +}
145 +
129 146 // Themes here range from near-black to a deep navy, and the basemap has to
130 147 // match the surrounding chrome or the map reads as a hole punched in the page.
131 148 // base-100's lightness is the same signal daisyUI itself uses.
@@ -255,9 +272,7 @@ export function addBasemap(map, opts = {}) {
255 272 tiles.setUrl(baseUrl())
256 273 if (labelTiles) labelTiles.setUrl(styleFor().labels)
257 274
258 − const color = tintOpt === 'none' ? null : asColor(
259 − tintOpt.startsWith('--') ? cssVar(tintOpt, styleFrom) : tintOpt
260 − )
275 + const color = tintOpt === 'none' ? null : themeColor(tintOpt, styleFrom)
261 276
262 277 tint.style.background = color || 'transparent'
263 278 tint.style.opacity = color ? String(strength) : '0'
modified apps/room_sanctum/assets/js/leaflet/leaflet-line.js
+7 −2
@@ -1,3 +1,5 @@
1 +import { themeColor } from './basemap'
2 +
1 3 // A polyline expressed as a DOM child of <leaflet-map>, so route geometry
2 4 // arrives and leaves the same way markers do -- LiveView adds and removes the
3 5 // elements, the map's MutationObserver notices.
@@ -46,9 +48,12 @@ class LeafletLine extends HTMLElement {
46 48 }
47 49 }
48 50
49 − getStyle() {
51 + // `styleFrom` is the element to resolve theme variables against -- the map
52 + // passes its own container, since this element lives in a shadow root and
53 + // is display:none besides.
54 + getStyle(styleFrom) {
50 55 return {
51 − color: this.getAttribute('color') || '#94a3b8',
56 + color: themeColor(this.getAttribute('color'), styleFrom) || '#94a3b8',
52 57 weight: parseFloat(this.getAttribute('weight')) || 2,
53 58 opacity: this.hasAttribute('opacity') ? parseFloat(this.getAttribute('opacity')) : 0.35
54 59 };
modified apps/room_sanctum/assets/js/leaflet/leaflet-map.js
+9 −2
@@ -392,7 +392,14 @@ class LeafletMap extends HTMLElement {
392 392 // The charge ramp is anchored to the surface it is drawn on, so a theme
393 393 // flip restyles the bikes rather than leaving a scale reading against
394 394 // its own background.
395 − this.unwatchTheme = onThemeChange(() => this.repaintChargeMarkers());
395 + this.unwatchTheme = onThemeChange(() => {
396 + this.repaintChargeMarkers();
397 + // A line coloured by a theme variable has no attribute change to
398 + // react to when the theme flips -- only what the name resolves to
399 + // moved. One subscription for both, since it is one signal and
400 + // disconnectedCallback already tears this one down.
401 + this.querySelectorAll('leaflet-line').forEach((lineEl) => this.addLineElement(lineEl));
402 + });
396 403
397 404 // After the initial setView, so it is not mistaken for a user move.
398 405 this.watchForUserView();
@@ -539,7 +546,7 @@ class LeafletMap extends HTMLElement {
539 546 this.removeLineById(lineId);
540 547 if (points.length < 2) return;
541 548
542 − const style = lineEl.getStyle();
549 + const style = lineEl.getStyle(this.map.getContainer());
543 550 const polyline = L.polyline(points, {
544 551 renderer: this.lineRenderer,
545 552 pane: 'routeLines',
modified apps/room_sanctum/lib/room_sanctum_web/live/cfg_plani_live/show.ex
+5 −1
@@ -101,7 +101,11 @@ defmodule RoomSanctumWeb.PlaniLive.Show do
101 101 [lat + d_lat * :math.sin(angle), lon + d_lon * :math.cos(angle)]
102 102 end
103 103
104 − [%{id: "radius", points: points, color: "#38bdf8"}]
104 + # The theme's accent rather than a fixed blue: the ring is the page's own
105 + # annotation on the map, not something read off a feed, and it followed the
106 + # theme everywhere else on the page but here. Resolved in the browser, so
107 + # it also survives a theme switch without a reload.
108 + [%{id: "radius", points: points, color: "--a"}]
105 109 end
106 110
107 111 def radius_ring(_where, _radius), do: []

Parents: 4935db2