Skip to content

Commit fc6ed31

Browse files
committed
feat: add Overture Maps plugin under the Plugins menu
Add maplibre-gl-overture-maps as a new Overture Maps plugin, listed after Esri Wayback in the Plugins menu and defaulting to the top-left control position. The panel opens on activation and remembers its release, visibility, and opacity across reposition and project reload. Theme the control, panel, and inspect popup from the app light/dark toggle by remapping the upstream --ovt-* tokens to the app theme tokens, overriding the package's prefers-color-scheme defaults. Depends on maplibre-gl-overture-maps 0.2.0, which re-applies its sources and layers after a basemap style change.
1 parent c34459e commit fc6ed31

7 files changed

Lines changed: 163 additions & 0 deletions

File tree

apps/geolibre-desktop/src/hooks/usePlugins.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
maplibreLidarPlugin,
1616
maplibreNasaEarthdataPlugin,
1717
maplibreNationalMapPlugin,
18+
maplibreOvertureMapsPlugin,
1819
maplibreStreetViewPlugin,
1920
maplibreSwipePlugin,
2021
PluginManager,
@@ -50,6 +51,7 @@ manager.registerAll([
5051
maplibreEnviroAtlasPlugin,
5152
maplibreNationalMapPlugin,
5253
maplibreEsriWaybackPlugin,
54+
maplibreOvertureMapsPlugin,
5355
maplibreGeoAgentPlugin,
5456
maplibreGeoEditorPlugin,
5557
maplibreLidarPlugin,

apps/geolibre-desktop/src/index.css

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,3 +1962,37 @@ html.dark .maplibregl-popup-anchor-right:has(.vector-control-popup) .maplibregl-
19621962

19631963
color-scheme: dark;
19641964
}
1965+
1966+
/* maplibre-gl-overture-maps themes its control, panel, and inspect popup
1967+
from prefers-color-scheme (the OS theme): in `auto` mode it stamps a hard
1968+
`ovt-theme-light`/`ovt-theme-dark` class on the elements from the system
1969+
preference, so a light OS keeps the panel light even when the app is in
1970+
dark mode. Remapping the upstream `--ovt-*` tokens to the app theme tokens
1971+
keys the control to the app's light/dark toggle instead. The repeated
1972+
classes outrank the upstream `.overture-control.ovt-theme-*` and
1973+
prefers-color-scheme blocks regardless of stylesheet order. */
1974+
.overture-control.overture-control.overture-control,
1975+
.overture-control-panel.overture-control-panel.overture-control-panel,
1976+
.overture-popup-content.overture-popup-content.overture-popup-content {
1977+
--ovt-bg: hsl(var(--popover));
1978+
--ovt-fg: hsl(var(--popover-foreground));
1979+
--ovt-text: hsl(var(--popover-foreground));
1980+
--ovt-muted: hsl(var(--muted-foreground));
1981+
--ovt-border: hsl(var(--border));
1982+
--ovt-input-border: hsl(var(--input));
1983+
--ovt-input-bg: hsl(var(--popover));
1984+
--ovt-hover: hsl(var(--foreground) / 0.06);
1985+
--ovt-accent: hsl(var(--primary));
1986+
--ovt-scrollbar: hsl(var(--border));
1987+
--ovt-scrollbar-hover: hsl(var(--input));
1988+
--ovt-error-bg: hsl(var(--destructive) / 0.15);
1989+
--ovt-error-fg: hsl(var(--destructive));
1990+
1991+
color-scheme: light;
1992+
}
1993+
1994+
.dark .overture-control.overture-control.overture-control,
1995+
.dark .overture-control-panel.overture-control-panel.overture-control-panel,
1996+
.dark .overture-popup-content.overture-popup-content.overture-popup-content {
1997+
color-scheme: dark;
1998+
}

apps/geolibre-desktop/src/main.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import "maplibre-gl-geo-editor/style.css";
1414
import "maplibre-gl-geoagent/style.css";
1515
import "maplibre-gl-nasa-earthdata/style.css";
1616
import "maplibre-gl-national-map/style.css";
17+
import "maplibre-gl-overture-maps/style.css";
1718
import "maplibre-gl-planetary-computer/style.css";
1819
import "maplibre-gl-raster/style.css";
1920
import "maplibre-gl-streetview/style.css";

package-lock.json

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/plugins/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"maplibre-gl-lidar": "^0.14.1",
4141
"maplibre-gl-nasa-earthdata": "^0.1.2",
4242
"maplibre-gl-national-map": "^0.1.1",
43+
"maplibre-gl-overture-maps": "^0.2.0",
4344
"maplibre-gl-planetary-computer": "^0.3.0",
4445
"maplibre-gl-raster": "^0.2.0",
4546
"maplibre-gl-streetview": "^0.4.0",

packages/plugins/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export { maplibreGeoAgentPlugin } from "./plugins/maplibre-geoagent";
8686
export { maplibreLidarPlugin } from "./plugins/maplibre-lidar";
8787
export { maplibreNasaEarthdataPlugin } from "./plugins/maplibre-nasa-earthdata";
8888
export { maplibreNationalMapPlugin } from "./plugins/maplibre-national-map";
89+
export { maplibreOvertureMapsPlugin } from "./plugins/maplibre-overture-maps";
8990
export { maplibreStreetViewPlugin } from "./plugins/maplibre-streetview";
9091
export { maplibreSwipePlugin } from "./plugins/maplibre-swipe";
9192
export {
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import {
2+
OvertureMapsControl,
3+
type OvertureMapsControlOptions,
4+
type OvertureMapsState,
5+
} from "maplibre-gl-overture-maps";
6+
import type {
7+
GeoLibreAppAPI,
8+
GeoLibreMapControlPosition,
9+
GeoLibrePlugin,
10+
} from "../types";
11+
12+
let overturePosition: GeoLibreMapControlPosition = "top-left";
13+
14+
const OVERTURE_OPTIONS = {
15+
collapsed: false,
16+
title: "Overture Maps",
17+
panelWidth: 340,
18+
className: "geolibre-overture-control",
19+
} satisfies Omit<OvertureMapsControlOptions, "position">;
20+
21+
let overtureControl: OvertureMapsControl | null = null;
22+
// Holds the panel state while the control is detached so re-activating or
23+
// repositioning it restores the user's release, visibility, and opacity.
24+
let pendingState: Partial<OvertureMapsState> | null = null;
25+
26+
function getOvertureControlOptions(): OvertureMapsControlOptions {
27+
return {
28+
...OVERTURE_OPTIONS,
29+
...(pendingState?.collapsed != null
30+
? { collapsed: pendingState.collapsed }
31+
: {}),
32+
...(pendingState?.panelWidth != null
33+
? { panelWidth: pendingState.panelWidth }
34+
: {}),
35+
...(pendingState?.release ? { release: pendingState.release } : {}),
36+
position: overturePosition,
37+
};
38+
}
39+
40+
function createOvertureControl(): OvertureMapsControl {
41+
const control = new OvertureMapsControl(getOvertureControlOptions());
42+
if (pendingState) {
43+
control.setState(pendingState);
44+
}
45+
return control;
46+
}
47+
48+
function isOvertureMapsState(
49+
value: unknown,
50+
): value is Partial<OvertureMapsState> {
51+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
52+
}
53+
54+
export const maplibreOvertureMapsPlugin: GeoLibrePlugin = {
55+
id: "maplibre-gl-overture-maps",
56+
name: "Overture Maps",
57+
version: "0.2.0",
58+
activate: (app: GeoLibreAppAPI) => {
59+
if (!overtureControl) {
60+
overtureControl = createOvertureControl();
61+
}
62+
const added = app.addMapControl(overtureControl, overturePosition);
63+
if (!added) {
64+
overtureControl = null;
65+
return false;
66+
}
67+
// Open the panel on activation. Deferring past the current click avoids
68+
// the menu click that activated the plugin being treated as a
69+
// click-outside that immediately re-collapses the panel.
70+
setTimeout(() => overtureControl?.expand(), 0);
71+
},
72+
deactivate: (app: GeoLibreAppAPI) => {
73+
if (!overtureControl) return;
74+
pendingState = overtureControl.getState();
75+
app.removeMapControl(overtureControl);
76+
overtureControl = null;
77+
},
78+
getMapControlPosition: () => overturePosition,
79+
setMapControlPosition: (
80+
app: GeoLibreAppAPI,
81+
position: GeoLibreMapControlPosition,
82+
) => {
83+
overturePosition = position;
84+
if (!overtureControl) return;
85+
app.removeMapControl(overtureControl);
86+
const added = app.addMapControl(overtureControl, overturePosition);
87+
if (!added) {
88+
pendingState = overtureControl.getState();
89+
overtureControl = null;
90+
return false;
91+
}
92+
setTimeout(() => overtureControl?.expand(), 0);
93+
},
94+
getProjectState: () =>
95+
overtureControl?.getState() ?? pendingState ?? undefined,
96+
applyProjectState: (_app: GeoLibreAppAPI, state: unknown) => {
97+
if (!isOvertureMapsState(state)) return false;
98+
pendingState = state;
99+
overtureControl?.setState(state);
100+
},
101+
};

0 commit comments

Comments
 (0)