feat(street-level): one imagery source at a time; IC8 review fixes

- One provider is lit at a time: lighting a chip darkens the others, and a
  chip click records every registered provider's switch in one update so
  the share link keeps the swap (also off Google 3D, where Street View is
  not listed). The layer starts with the first default-on provider
  (Mapillary, free); params that light several keep the one already on,
  so reapplying them never flips (litByParams). The now-unreachable
  "several lit" chip paths are gone.
- Leaving Google 3D during a Street View lookup ends it without an error
  or a stuck loading state (openImage's early return resets it; the
  lookup loop rechecks availability).
- A source swap during a lookup no longer reports "no imagery".
- Street View lit off Google 3D says the panel needs the Google 3D map.
- Comments trimmed to the why; keySetupCore.test.mjs back to upstream's
  formatting plus the one new test (was a 551-line reformat).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-13 15:10:58 +01:00
1 parent 64d939f3d2
commit b1efd22f02
24 files changed
+388 -625

No files matched your search

+5 -9
View File
@@ -15,8 +15,8 @@ import { COLORS } from './policy.js';
* @property {string} hint
* @property {string|null} error
* @property {string} color The source's one colour.
* @property {boolean} [groundClick] Draws no coverage: opens where the user clicks.
* @property {Array<'pano'|'since'>} [filters] Imagery filters it honours.
* @property {boolean} [groundClick]
* @property {Array<'pano'|'since'>} [filters]
*/
/**
@@ -45,8 +45,7 @@ export function summarizeCoverage(providers) {
/**
* Switched-off providers that would draw with a key already set, offered
* while the switched-on ones lack theirs (Street View beside a Mapillary
* layer with no token).
* while the switched-on ones lack theirs.
* @param {Array<ProviderSnapshot>} providers
* @returns {Array<{id: string, label: string, requiresKeyId: string|null}>}
*/
@@ -58,8 +57,7 @@ export function keyAlternatives(providers) {
}
/**
* Which filter controls mean anything: those a switched-on provider honours.
* With none switched on, both show (they apply once one is).
* The filter controls a switched-on provider honours (both when none is on).
* @param {Array<ProviderSnapshot>} providers
*/
export function filterControls(providers) {
@@ -72,8 +70,7 @@ export function filterControls(providers) {
/**
* The panel snapshot from core state and provider snapshots. The legend has
* one swatch per active source that draws coverage lines, then the shared
* selection colour; a source that only opens where the user clicks has none.
* one swatch per active source that draws coverage lines, then Selected.
* @param {{enabled: boolean, filter: object, providers: Array<ProviderSnapshot>, street: object, sequence: object}} input
*/
export function composeUIState({
@@ -99,7 +96,6 @@ export function composeUIState({
legend.push({ key: 'selected', label: 'Selected', color: COLORS.selected });
return {
enabled,
/** The camera is at street zoom: a ground-click provider can open here. */
groundClickReady: groundClickReady === true,
keyRequired,
keyAlternatives: keyAlternatives(providers),