From 04f666638e7bacef9f41de9f0c24830a58ec56dd Mon Sep 17 00:00:00 2001 From: Claude VM Date: Mon, 25 May 2026 07:03:51 +0300 Subject: [PATCH] =?UTF-8?q?feat(geoportal-v2):=20"S2"=20basemap=20?= =?UTF-8?q?=E2=80=94=20Sentinel-2=20cloudless=20annual=20mosaics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a 6th basemap option ("S2") backed by EOX's free, public, CORS-open Sentinel-2 cloudless WMTS service. Annual mosaics from 2016 to 2024 (2025/2026 not yet shipped by EOX); 10 m/pixel resolution good for large-scale rural change detection (deforestation, greenhouses, halls, agriculture) but not for individual buildings. Companion to the Wayback basemap shipped earlier — Wayback gives high-res city detail at irregular snapshot dates, Sentinel-2 gives predictable yearly cadence at coarse rural-scale resolution. UI mirrors Wayback: when "S2" is selected the switcher reveals a year dropdown beneath the basemap row; the map-viewer rebuilds the raster source with the right EOX layer ID. Default year = latest (2024). Note on licensing: EOX's 2018+ mosaics are CC BY-NC-SA 4.0 — non- commercial. The UI surfaces this + the commercial-licence pointer (cloudless.eox.at). 2016 (s2cloudless) + 2017 are CC BY 4.0, no non-commercial restriction. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/modules/geoportal/v2/basemap-switcher.tsx | 46 ++++++++++++++++- src/modules/geoportal/v2/geoportal-v2.tsx | 5 ++ src/modules/geoportal/v2/map-viewer.tsx | 28 ++++++++++- src/modules/geoportal/v2/sentinel-catalog.ts | 50 +++++++++++++++++++ 4 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 src/modules/geoportal/v2/sentinel-catalog.ts diff --git a/src/modules/geoportal/v2/basemap-switcher.tsx b/src/modules/geoportal/v2/basemap-switcher.tsx index 79df8ef..3e1c5f3 100644 --- a/src/modules/geoportal/v2/basemap-switcher.tsx +++ b/src/modules/geoportal/v2/basemap-switcher.tsx @@ -8,8 +8,15 @@ import { latestWaybackRelease, type WaybackRelease, } from "./wayback-catalog"; +import { SENTINEL_YEARS, type SentinelYear } from "./sentinel-catalog"; -export type BasemapId = "liberty" | "dark" | "satellite" | "google" | "wayback"; +export type BasemapId = + | "liberty" + | "dark" + | "satellite" + | "google" + | "wayback" + | "sentinel"; const OPTIONS: Array<{ id: BasemapId; label: string }> = [ { id: "liberty", label: "Liberty" }, @@ -17,6 +24,7 @@ const OPTIONS: Array<{ id: BasemapId; label: string }> = [ { id: "satellite", label: "Satelit" }, { id: "google", label: "Google" }, { id: "wayback", label: "Istoric" }, + { id: "sentinel", label: "S2" }, ]; interface Props { @@ -26,6 +34,10 @@ interface Props { waybackReleaseId?: string | null; /** Fired when the user picks a different Wayback date. */ onWaybackReleaseChange?: (release: WaybackRelease) => void; + /** Selected Sentinel-2 cloudless year (only meaningful when value=sentinel). */ + sentinelYear?: string | null; + /** Fired when the user picks a different Sentinel-2 year. */ + onSentinelYearChange?: (year: SentinelYear) => void; } export function BasemapSwitcher({ @@ -33,6 +45,8 @@ export function BasemapSwitcher({ onChange, waybackReleaseId, onWaybackReleaseChange, + sentinelYear, + onSentinelYearChange, }: Props) { const [releases, setReleases] = useState(null); const [loading, setLoading] = useState(false); @@ -80,6 +94,36 @@ export function BasemapSwitcher({ + {value === "sentinel" && ( +
+ + +

+ Mozaic anual cloud-free Sentinel-2 (rezoluție ~10 m). Bun + pentru schimbări rurale large-scale (defrișări, hale, + sere). Nu vezi case sau detalii fine. © EOX / Copernicus. + Uz comercial: cloudless.eox.at. +

+
+ )} + {value === "wayback" && (