neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
⭐
Log in to mark this repository.
Draw the Plani's radius ring in the theme accent
8809785 · Gabriel Morell · 2026-09-03 19:21
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