fix(1506): restore marker-stroke server defaults to v3.7.2 visual (#1507)

# fix(1506): restore marker-stroke server defaults to v3.7.2 visual

Closes #1506. Refs #1494, #1488.

## Why
PR #1494 introduced operator-tunable marker stroke via
`--mc-marker-stroke-*` CSS vars but chose new server defaults
(translucent white, 1px) that look weak next to the v3.7.2 baseline
(solid white, 2px). Operators upgrading from v3.7.x see a visible
regression on the map.

## What
Restore the v3.7.2 visual as the server default. Customizer + config
plumbing are unchanged — anyone who preferred the thinner translucent
style can dial it back via the in-app customizer (Colors → Marker
Stroke).

| File | Before | After |
|---|---|---|
| `public/style.css` `:root` | `rgba(255,255,255,0.85)` / `1` / `1` |
`#fff` / `2` / `1` |
| `public/customize-v2.js` `msWidth` fallback | `1` | `2` |
| `config.example.json` `markerStroke.color/width` | `rgba(...,0.85)` /
`1` | `#fff` / `2` |

Customizer overrides already in localStorage continue to take effect —
only the unset baseline shifts.

## TDD
- Red commit (`cdabb905`): adds gate F to
`test-issue-1488-marker-stroke-vars.js` asserting style.css /
customize-v2.js / config.example.json defaults match v3.7.2 (solid
white, 2px). Fails on master with 5 assertion errors.
- Green commit (`abfa9b6b`): three small data edits flip all five
assertions to pass.

## Acceptance
- After upgrade, markers visually match v3.7.2 stroke (solid white, 2px)
by default 
- Customizer slider still functional 
- Existing custom values in localStorage still take effect (no reset) 

---------

Co-authored-by: mc-bot <bot@meshcore.local>
This commit is contained in:
Kpa-clawbot
2026-05-30 00:54:24 +00:00
committed by GitHub
co-authored by mc-bot
parent 9b6453807d
commit a7b156dafc
4 changed files with 38 additions and 6 deletions
+3 -3
View File
@@ -48,10 +48,10 @@
"_comment": "Marker/badge colors per node role. Used on map, nodes list, and live feed."
},
"markerStroke": {
"color": "rgba(255,255,255,0.85)",
"width": 1,
"color": "#fff",
"width": 2,
"opacity": 1,
"_comment": "#1488 — outline around each map marker (live + map pages). 'color' accepts any CSS color (hex, rgb, rgba); use rgba() or drop 'opacity' below ~0.5 to soften the outline when hundreds of nodes feel overwhelming. 'width' is the SVG stroke width (0 hides the outline entirely). Operators can override per-browser via the in-app Theme Customizer (Colors tab → Marker Stroke)."
"_comment": "#1488/#1506 — outline around each map marker (live + map pages). Defaults restored to v3.7.2 visual (solid white, 2px). 'color' accepts any CSS color (hex, rgb, rgba); use rgba() or drop 'opacity' below ~0.5 to soften the outline when hundreds of nodes feel overwhelming. 'width' is the SVG stroke width (0 hides the outline entirely). Operators can override per-browser via the in-app Theme Customizer (Colors tab → Marker Stroke)."
},
"mapDarkTileProvider": "carto-dark",
"_comment_mapDarkTileProvider": "Default dark-mode basemap provider. Allowed: 'carto-dark' (Carto dark_all — default), 'esri-darkgray-labels' (Esri Dark Gray Canvas + reference labels), 'voyager-inverted' (Carto Voyager with CSS invert filter), 'positron-inverted' (Carto Positron with CSS invert filter). Light mode is unaffected. Users can override per-browser via the in-app customizer (persisted to localStorage). #1420.",
+1 -1
View File
@@ -1309,7 +1309,7 @@
// local override) so the operator sees what's actually painted.
var ms = eff.markerStroke || {};
var msColor = typeof ms.color === 'string' && ms.color ? ms.color : '#ffffff';
var msWidth = ms.width != null && isFinite(ms.width) ? Number(ms.width) : 1;
var msWidth = ms.width != null && isFinite(ms.width) ? Number(ms.width) : 2;
var msOpacity = ms.opacity != null && isFinite(ms.opacity) ? Number(ms.opacity) : 1;
var msOpacityPct = Math.round(msOpacity * 100);
+2 -2
View File
@@ -3724,8 +3724,8 @@ th.sort-active { color: var(--accent, #60a5fa); }
* tiles; operators dial these via the customizer (Colors Marker
* Stroke) or via config.json (markerStroke.*). All SVG marker builders
* read these vars so changes propagate live without a reload. */
--mc-marker-stroke-color: rgba(255,255,255,0.85);
--mc-marker-stroke-width: 1;
--mc-marker-stroke-color: #fff;
--mc-marker-stroke-width: 2;
--mc-marker-stroke-opacity: 1;
/* #1407 per-role text colors paired with each --mc-role-X bg so
+32
View File
@@ -94,6 +94,38 @@ console.log('\n=== #1488 E: customize-v2.js exposes marker stroke controls ===')
'customize-v2.js writes --mc-marker-stroke-opacity');
}
console.log('\n=== #1506 F: server defaults restored to v3.7.2 (solid white, 2px) ===');
{
// Locate the :root block in style.css and pull the marker-stroke
// var defaults; assert they match the v3.7.2 visual (solid white, 2px,
// fully opaque). The customizer can dial them down per-operator.
var colorMatch = styleSrc.match(/--mc-marker-stroke-color\s*:\s*([^;]+);/);
var widthMatch = styleSrc.match(/--mc-marker-stroke-width\s*:\s*([^;]+);/);
var opacityMatch = styleSrc.match(/--mc-marker-stroke-opacity\s*:\s*([^;]+);/);
assert(colorMatch && /^(#fff|#ffffff|white|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\))$/i.test(colorMatch[1].trim()),
'style.css --mc-marker-stroke-color is solid white (got: ' + (colorMatch ? colorMatch[1].trim() : 'MISSING') + ')');
assert(widthMatch && Number(widthMatch[1].trim()) === 2,
'style.css --mc-marker-stroke-width is 2 (got: ' + (widthMatch ? widthMatch[1].trim() : 'MISSING') + ')');
assert(opacityMatch && Number(opacityMatch[1].trim()) === 1,
'style.css --mc-marker-stroke-opacity is 1 (got: ' + (opacityMatch ? opacityMatch[1].trim() : 'MISSING') + ')');
// customize-v2.js fallback defaults (when neither server config nor
// local override provides a value) must match the new server defaults
// so the customizer UI shows what's actually painted.
var fallbackWidth = customizeSrc.match(/ms\.width\s*!=\s*null[^?]*\?\s*Number\(ms\.width\)\s*:\s*(\d+(?:\.\d+)?)/);
assert(fallbackWidth && Number(fallbackWidth[1]) === 2,
'customize-v2.js msWidth fallback is 2 (got: ' + (fallbackWidth ? fallbackWidth[1] : 'MISSING') + ')');
// config.example.json defaults must also match so fresh deploys ship
// the v3.7.2 visual without operator action.
var configSrc = fs.readFileSync(path.join(__dirname, 'config.example.json'), 'utf8');
var cfg = JSON.parse(configSrc);
assert(cfg.markerStroke && /^(#fff|#ffffff|white|rgb\(\s*255\s*,\s*255\s*,\s*255\s*\))$/i.test(String(cfg.markerStroke.color || '').trim()),
'config.example.json markerStroke.color is solid white (got: ' + (cfg.markerStroke && cfg.markerStroke.color) + ')');
assert(cfg.markerStroke && cfg.markerStroke.width === 2,
'config.example.json markerStroke.width is 2 (got: ' + (cfg.markerStroke && cfg.markerStroke.width) + ')');
}
console.log('\n--- Summary ---');
console.log(passed + ' passed, ' + failed + ' failed');
process.exit(failed > 0 ? 1 : 0);