mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-05 10:53:59 +00:00
refactor(street-level): rename the Mapillary layer to street-level
Pure move: the layer id, panel id, CSS prefix, classes, exports and config paths become provider-neutral (street-level, #street-level-panel, sl-); the Mapillary-specific modules move under providers/mapillary/. Behaviour is unchanged. The two sprite collections now register under distinct ids instead of overwriting each other under 'mapillary'. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
547b706f67
commit
2dbc684fb1
38 files changed
+401
-381
No files matched your search
@@ -0,0 +1,174 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
import {
|
||||
mapillaryImageUrl,
|
||||
presentStreetLevelPanel,
|
||||
} from './streetLevelPresentation.js';
|
||||
|
||||
function snapshot(overrides = {}) {
|
||||
const base = {
|
||||
enabled: false,
|
||||
keyRequired: false,
|
||||
coverage: {
|
||||
zoom: null,
|
||||
kind: null,
|
||||
filter: { pano: 'all', sinceMs: null },
|
||||
legend: [
|
||||
{ key: 'recent', label: 'Recent (≤2 yr)', color: '#05cb63' },
|
||||
{ key: 'older', label: 'Older', color: '#2e7d5b' },
|
||||
{ key: 'pano', label: '360°', color: '#ff4fd8' },
|
||||
{ key: 'selected', label: 'Selected', color: '#00d4ff' },
|
||||
],
|
||||
loading: false,
|
||||
sequences: 0,
|
||||
hint: '',
|
||||
error: null,
|
||||
},
|
||||
sequence: { selectedId: null, images: 0, loading: false },
|
||||
street: {
|
||||
open: false,
|
||||
follow: false,
|
||||
loading: false,
|
||||
error: null,
|
||||
imageId: null,
|
||||
position: null,
|
||||
bearing: null,
|
||||
isPano: false,
|
||||
capturedAt: null,
|
||||
sequenceId: null,
|
||||
creator: null,
|
||||
renderMode: 'letterbox',
|
||||
},
|
||||
};
|
||||
return deepMerge(base, overrides);
|
||||
}
|
||||
|
||||
function deepMerge(target, source) {
|
||||
const out = { ...target };
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
out[key] =
|
||||
value &&
|
||||
typeof value === 'object' &&
|
||||
!Array.isArray(value) &&
|
||||
target[key] &&
|
||||
typeof target[key] === 'object'
|
||||
? deepMerge(target[key], value)
|
||||
: value;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
test('a missing Mapillary token gates every control and flags KEY REQUIRED', () => {
|
||||
const view = presentStreetLevelPanel(snapshot({ keyRequired: true }));
|
||||
assert.equal(view.controlsDisabled, true);
|
||||
assert.deepEqual(view.status, { text: 'KEY REQUIRED', tone: 'warn' });
|
||||
});
|
||||
|
||||
test('status reads LOADING while coverage streams, then ON or OFF', () => {
|
||||
assert.deepEqual(presentStreetLevelPanel(snapshot()).status, {
|
||||
text: 'OFF',
|
||||
tone: '',
|
||||
});
|
||||
assert.deepEqual(
|
||||
presentStreetLevelPanel(
|
||||
snapshot({ enabled: true, coverage: { loading: true } }),
|
||||
).status,
|
||||
{ text: 'LOADING', tone: 'busy' },
|
||||
);
|
||||
assert.deepEqual(
|
||||
presentStreetLevelPanel(snapshot({ enabled: true })).status,
|
||||
{
|
||||
text: 'ON',
|
||||
tone: 'on',
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test('errors from the viewer or the coverage web surface in one alert', () => {
|
||||
assert.equal(presentStreetLevelPanel(snapshot()).error, null);
|
||||
assert.equal(
|
||||
presentStreetLevelPanel(
|
||||
snapshot({ street: { error: 'Image could not be opened' } }),
|
||||
).error,
|
||||
'Image could not be opened',
|
||||
);
|
||||
assert.equal(
|
||||
presentStreetLevelPanel(snapshot({ coverage: { error: 'Tile HTTP 502' } }))
|
||||
.error,
|
||||
'Tile HTTP 502',
|
||||
);
|
||||
});
|
||||
|
||||
test('legend passes through in the layer’s order', () => {
|
||||
const view = presentStreetLevelPanel(snapshot());
|
||||
assert.deepEqual(
|
||||
view.legend.map((entry) => entry.key),
|
||||
['recent', 'older', 'pano', 'selected'],
|
||||
);
|
||||
});
|
||||
|
||||
test('the meta line never mixes the visible-sequence count with the selected sequence', () => {
|
||||
assert.equal(presentStreetLevelPanel(snapshot()).meta, '');
|
||||
const browsing = presentStreetLevelPanel(
|
||||
snapshot({ enabled: true, coverage: { zoom: 14, sequences: 812 } }),
|
||||
);
|
||||
assert.match(browsing.meta, /^812 sequences in view · click a line/);
|
||||
const selected = presentStreetLevelPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
coverage: { zoom: 14, sequences: 812 },
|
||||
sequence: { selectedId: 'abc', images: 33 },
|
||||
}),
|
||||
);
|
||||
assert.equal(selected.meta, '33 images in this sequence · Esc clears');
|
||||
assert.doesNotMatch(selected.meta, /sequences in view/);
|
||||
const hinted = presentStreetLevelPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
coverage: { hint: 'Point the camera at the globe' },
|
||||
}),
|
||||
);
|
||||
assert.equal(hinted.meta, 'Point the camera at the globe');
|
||||
});
|
||||
|
||||
test('viewer caption reads "Image by" left and date right, with a deep link', () => {
|
||||
const view = presentStreetLevelPanel(
|
||||
snapshot({
|
||||
enabled: true,
|
||||
street: {
|
||||
open: true,
|
||||
imageId: '1814275685699406',
|
||||
creator: 'mapfool',
|
||||
capturedAt: Date.UTC(2023, 9, 8),
|
||||
bearing: 93.4,
|
||||
isPano: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
assert.equal(view.viewer.captionLeft, 'Image by mapfool');
|
||||
assert.equal(view.viewer.captionRight, '360° · 93° · 2023-10-08');
|
||||
assert.equal(
|
||||
view.viewer.link,
|
||||
'https://www.mapillary.com/app/?pKey=1814275685699406&focus=photo',
|
||||
);
|
||||
assert.equal(view.viewer.follow.disabled, false);
|
||||
assert.equal(view.wantsOpen, true);
|
||||
});
|
||||
|
||||
test('an image without a creator name leaves the left caption empty', () => {
|
||||
const view = presentStreetLevelPanel(
|
||||
snapshot({
|
||||
street: { open: true, imageId: '1', capturedAt: Date.UTC(2024, 0, 2) },
|
||||
}),
|
||||
);
|
||||
assert.equal(view.viewer.captionLeft, '');
|
||||
assert.equal(view.viewer.captionRight, '2024-01-02');
|
||||
});
|
||||
|
||||
test('image deep links match the mapillary.com share format', () => {
|
||||
assert.equal(
|
||||
mapillaryImageUrl(1814275685699406),
|
||||
'https://www.mapillary.com/app/?pKey=1814275685699406&focus=photo',
|
||||
);
|
||||
assert.equal(mapillaryImageUrl(' '), 'https://www.mapillary.com/app/');
|
||||
});
|
||||
Reference in new issue
Block a user