feat(street-level): one colour per imagery source

As more sources arrive, each one reads the same everywhere it appears: its
PROVIDERS chip, coverage lines, overview points, image cones and a single
legend swatch. The palette lives in one place, PROVIDER_COLORS in
src/layers/streetLevel/policy.js: Mapillary green (#05cb63), Panoramax
purple, Google Street View blue.

Mapillary drops its age dimming and magenta panoramas: lines and overview
points are Mapillary green, cones are green too and 360° images keep their
ring shape; the 360°/FLAT filter still separates them, and the selected
sequence stays GEV cyan.

The provider contract loses `legend`: `colors.coverage` is the source's one
colour, and the core composes the legend as one swatch per active source
(its name, its colour) followed by Selected. The chip group takes an
optional per-chip colour as a `--chip-color` CSS variable, written only
when it changes; Street Level chips show it as a swatch dot and, while on,
as the chip's border, text and a faint fill.

The feature gate checks the legend has one swatch per source plus Selected
and that the Mapillary chip carries #05cb63.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-09-29 00:03:00 +01:00
1 parent d5da45eacb
commit 0f2cac2ca2
21 files changed
+188 -99

No files matched your search

+21 -5
View File
@@ -18,7 +18,7 @@ const provider = (overrides = {}) => ({
count: 0,
hint: '',
error: null,
legend: [],
color: '#05cb63',
...overrides,
});
@@ -30,9 +30,7 @@ function snapshot(overrides = {}) {
providers: [provider()],
coverage: { loading: false, count: 0, hint: '', error: null },
legend: [
{ key: 'mapillary:recent', label: 'Recent (≤2 yr)', color: '#05cb63' },
{ key: 'mapillary:older', label: 'Older', color: '#2e7d5b' },
{ key: 'mapillary:pano', label: '360°', color: '#ff4fd8' },
{ key: 'mapillary', label: 'Mapillary', color: '#05cb63' },
{ key: 'selected', label: 'Selected', color: '#00d4ff' },
],
sequence: { providerId: null, selectedId: null, images: 0, loading: false },
@@ -239,7 +237,25 @@ test('legend passes through in the layer’s order', () => {
const view = presentStreetLevelPanel(snapshot());
assert.deepEqual(
view.legend.map((entry) => entry.key),
['mapillary:recent', 'mapillary:older', 'mapillary:pano', 'selected'],
['mapillary', 'selected'],
);
});
test('each provider chip carries its source colour', () => {
const view = presentStreetLevelPanel(
snapshot({
providers: [
provider(),
provider({ id: 'panoramax', label: 'PANORAMAX', color: '#a66bff' }),
],
}),
);
assert.deepEqual(
view.providers.map((chip) => [chip.id, chip.color]),
[
['mapillary', '#05cb63'],
['panoramax', '#a66bff'],
],
);
});