feat(street-level): KartaView's SINCE is its upload date, noted in the panel

KartaView's server filters by upload date only, so SINCE goes by it
throughout for KartaView: the lines (as before), the photo a click opens
and the cones, the cut-off taken as its UTC day as KartaView's startDate
(passesKartaViewFilter). Providers may declare sinceBasis: 'upload'
(validated); while one is lit the panel shows "KartaView: by upload date"
under the SINCE slider, read out with it. The gate checks the note, and
step 13's picks get 60 s on a loaded machine.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Said TurkseverandClaude Opus 5.5 committed 2026-10-14 15:02:14 +01:00
1 parent b42ab9bb02
commit c4ecb11f75
18 files changed
+210 -40

No files matched your search

+14
View File
@@ -19,6 +19,7 @@ import { COLORS } from './policy.js';
* @property {Array<'pano'|'since'>} [filters]
* @property {{noun: string, action: string}|null} [coverageLabel]
* @property {boolean} [highlightsSequence] Its lines turn cyan when their sequence is selected.
* @property {'capture'|'upload'} [sinceBasis] What its SINCE compares.
*/
/**
@@ -72,6 +73,18 @@ export function filterControls(providers) {
return { pano: honoured('pano'), since: honoured('since') };
}
/**
* The note under SINCE when a lit provider dates its imagery by upload,
* e.g. "KartaView: by upload date", or null.
* @param {Array<ProviderSnapshot>} providers
*/
export function sinceNote(providers) {
const names = providers
.filter((p) => p.on && p.sinceBasis === 'upload')
.map((p) => p.name);
return names.length ? `${names.join(', ')}: by upload date` : null;
}
/**
* The panel snapshot from core state and provider snapshots. The legend has
* one swatch per active source that draws coverage lines, then Selected.
@@ -112,6 +125,7 @@ export function composeUIState({
keyRejected,
filter: { ...filter },
filterControls: filterControls(providers),
sinceNote: sinceNote(providers),
providers: providers.map((p) => ({ ...p })),
coverage,
legend,