@zendir/ui 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +142 -84
- package/dist/react/astro/UnifiedTimeline.js +25 -2
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/charts/GroundTrackMap.d.ts +30 -1
- package/dist/react/charts/GroundTrackMap.js +41 -2
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.d.ts +8 -2
- package/dist/react/charts/GroundTrackMapLeaflet.js +396 -66
- package/dist/react/charts/GroundTrackMapLeaflet.js.map +1 -1
- package/dist/react/charts/groundTrackMapLeafletTiles.d.ts +10 -8
- package/dist/react/charts/groundTrackMapLeafletTiles.js +10 -3
- package/dist/react/charts/groundTrackMapLeafletTiles.js.map +1 -1
- package/dist/react/charts/index.d.ts +2 -1
- package/dist/react/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useRef, useState,
|
|
1
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState, useEffect, useCallback } from "react";
|
|
3
3
|
import L from "leaflet";
|
|
4
4
|
import "leaflet/dist/leaflet.css";
|
|
5
5
|
/* empty css */
|
|
6
6
|
import { geodesicCirclePoints, splitRingAtAntimeridian, segmentsWithWorldCopies, splitPolylineAtAntimeridian } from "./groundTrackMapLeafletUtils.js";
|
|
7
|
-
import {
|
|
7
|
+
import { CARTO_ATTRIBUTION, OSM_ATTRIBUTION, TILE_PRESETS, FALLBACK_TILE } from "./groundTrackMapLeafletTiles.js";
|
|
8
8
|
import { useTheme } from "../theme/ThemeProvider.js";
|
|
9
9
|
const STATUS_COLOR_MAP = {
|
|
10
10
|
normal: "#56f000",
|
|
@@ -143,13 +143,14 @@ function GroundTrackMapLeaflet({
|
|
|
143
143
|
showLegend = true,
|
|
144
144
|
showEquator = false,
|
|
145
145
|
showRecenterButton = true,
|
|
146
|
+
showMapStyleToggle = true,
|
|
146
147
|
defaultCenter = [20, 0],
|
|
147
148
|
defaultZoom = 2,
|
|
148
149
|
height = "100%",
|
|
149
150
|
width = "100%",
|
|
150
151
|
minHeight = "400px",
|
|
151
152
|
emptyMessage = "No orbital data available",
|
|
152
|
-
tileUrl
|
|
153
|
+
tileUrl,
|
|
153
154
|
nightTileUrl,
|
|
154
155
|
lightSources,
|
|
155
156
|
className = "",
|
|
@@ -159,7 +160,9 @@ function GroundTrackMapLeaflet({
|
|
|
159
160
|
pinsEditable = false,
|
|
160
161
|
onPinAdd,
|
|
161
162
|
onPinUpdate,
|
|
162
|
-
onPinRemove
|
|
163
|
+
onPinRemove,
|
|
164
|
+
customLayers,
|
|
165
|
+
onLayerChange
|
|
163
166
|
}) {
|
|
164
167
|
const { tokens } = useTheme();
|
|
165
168
|
const containerRef = useRef(null);
|
|
@@ -169,6 +172,71 @@ function GroundTrackMapLeaflet({
|
|
|
169
172
|
const controlsRef = useRef([]);
|
|
170
173
|
const pinsGroupRef = useRef(null);
|
|
171
174
|
const [ready, setReady] = useState(false);
|
|
175
|
+
const [layersPanelOpen, setLayersPanelOpen] = useState(false);
|
|
176
|
+
const layersPanelRef = useRef(null);
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (!layersPanelOpen) return;
|
|
179
|
+
const handleClickOutside = (e) => {
|
|
180
|
+
if (layersPanelRef.current && !layersPanelRef.current.contains(e.target)) {
|
|
181
|
+
setLayersPanelOpen(false);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
185
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
186
|
+
}, [layersPanelOpen]);
|
|
187
|
+
const TILE_STORAGE_KEY = "zendir-map-tile-style";
|
|
188
|
+
const isExplicitTileUrl = tileUrl !== void 0;
|
|
189
|
+
const [tileStyle, setTileStyle] = useState(() => {
|
|
190
|
+
if (isExplicitTileUrl) return "dark";
|
|
191
|
+
try {
|
|
192
|
+
const saved = localStorage.getItem(TILE_STORAGE_KEY);
|
|
193
|
+
if (saved === "dark" || saved === "satellite") return saved;
|
|
194
|
+
} catch {
|
|
195
|
+
}
|
|
196
|
+
return "dark";
|
|
197
|
+
});
|
|
198
|
+
const handleTileStyleChange = useCallback((style) => {
|
|
199
|
+
setTileStyle(style);
|
|
200
|
+
try {
|
|
201
|
+
localStorage.setItem(TILE_STORAGE_KEY, style);
|
|
202
|
+
} catch {
|
|
203
|
+
}
|
|
204
|
+
}, []);
|
|
205
|
+
const effectiveTileUrl = isExplicitTileUrl ? tileUrl : TILE_PRESETS[tileStyle];
|
|
206
|
+
const [internalTerminator, setInternalTerminator] = useState(showTerminator);
|
|
207
|
+
const [internalGrid, setInternalGrid] = useState(showGrid);
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
setInternalTerminator(showTerminator);
|
|
210
|
+
}, [showTerminator]);
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
setInternalGrid(showGrid);
|
|
213
|
+
}, [showGrid]);
|
|
214
|
+
const [customLayerState, setCustomLayerState] = useState(() => {
|
|
215
|
+
const state = {};
|
|
216
|
+
for (const l of customLayers ?? []) {
|
|
217
|
+
state[l.id] = l.defaultEnabled ?? true;
|
|
218
|
+
}
|
|
219
|
+
return state;
|
|
220
|
+
});
|
|
221
|
+
useEffect(() => {
|
|
222
|
+
setCustomLayerState((prev) => {
|
|
223
|
+
const next = { ...prev };
|
|
224
|
+
for (const l of customLayers ?? []) {
|
|
225
|
+
if (!(l.id in next)) next[l.id] = l.defaultEnabled ?? true;
|
|
226
|
+
}
|
|
227
|
+
return next;
|
|
228
|
+
});
|
|
229
|
+
}, [customLayers]);
|
|
230
|
+
const handleLayerToggle = useCallback((layerId, enabled) => {
|
|
231
|
+
if (layerId === "terminator") {
|
|
232
|
+
setInternalTerminator(enabled);
|
|
233
|
+
} else if (layerId === "grid") {
|
|
234
|
+
setInternalGrid(enabled);
|
|
235
|
+
} else {
|
|
236
|
+
setCustomLayerState((prev) => ({ ...prev, [layerId]: enabled }));
|
|
237
|
+
}
|
|
238
|
+
onLayerChange == null ? void 0 : onLayerChange(layerId, enabled);
|
|
239
|
+
}, [onLayerChange]);
|
|
172
240
|
const clearLayers = useCallback(() => {
|
|
173
241
|
var _a;
|
|
174
242
|
const map = mapRef.current;
|
|
@@ -200,40 +268,7 @@ function GroundTrackMapLeaflet({
|
|
|
200
268
|
maxBounds: [[-90, -540], [90, 540]],
|
|
201
269
|
maxBoundsViscosity: 1
|
|
202
270
|
});
|
|
203
|
-
L.control.zoom({ position: "topright" }).addTo(map);
|
|
204
271
|
map.attributionControl.setPrefix("");
|
|
205
|
-
const isCartoTiles = tileUrl.includes("cartocdn");
|
|
206
|
-
if (isCartoTiles) {
|
|
207
|
-
map.attributionControl.addAttribution(CARTO_ATTRIBUTION);
|
|
208
|
-
}
|
|
209
|
-
const tileOptions = {
|
|
210
|
-
maxZoom: 19,
|
|
211
|
-
subdomains: isCartoTiles ? "abcd" : "abc",
|
|
212
|
-
// crossOrigin avoids tainted-canvas errors when Leaflet tries to read tile pixels
|
|
213
|
-
crossOrigin: true
|
|
214
|
-
};
|
|
215
|
-
const tile = L.tileLayer(tileUrl, tileOptions);
|
|
216
|
-
tile.addTo(map);
|
|
217
|
-
tileLayerRef.current = tile;
|
|
218
|
-
let hasSwitchedToFallback = false;
|
|
219
|
-
const onTileError = () => {
|
|
220
|
-
if (hasSwitchedToFallback) return;
|
|
221
|
-
hasSwitchedToFallback = true;
|
|
222
|
-
tile.off("tileerror", onTileError);
|
|
223
|
-
tile.remove();
|
|
224
|
-
if (isCartoTiles) {
|
|
225
|
-
map.attributionControl.removeAttribution(CARTO_ATTRIBUTION);
|
|
226
|
-
map.attributionControl.addAttribution(OSM_ATTRIBUTION);
|
|
227
|
-
}
|
|
228
|
-
const fallback = L.tileLayer(FALLBACK_TILE, {
|
|
229
|
-
maxZoom: 19,
|
|
230
|
-
subdomains: "abc",
|
|
231
|
-
crossOrigin: true
|
|
232
|
-
});
|
|
233
|
-
fallback.addTo(map);
|
|
234
|
-
tileLayerRef.current = fallback;
|
|
235
|
-
};
|
|
236
|
-
tile.on("tileerror", onTileError);
|
|
237
272
|
const overlayGroup = L.layerGroup();
|
|
238
273
|
overlayGroup.addTo(map);
|
|
239
274
|
overlayGroupRef.current = overlayGroup;
|
|
@@ -261,12 +296,53 @@ function GroundTrackMapLeaflet({
|
|
|
261
296
|
mapRef.current = null;
|
|
262
297
|
overlayGroupRef.current = null;
|
|
263
298
|
};
|
|
264
|
-
}, [
|
|
299
|
+
}, [clearLayers]);
|
|
300
|
+
useEffect(() => {
|
|
301
|
+
const map = mapRef.current;
|
|
302
|
+
if (!map || !ready) return;
|
|
303
|
+
if (tileLayerRef.current) {
|
|
304
|
+
tileLayerRef.current.remove();
|
|
305
|
+
tileLayerRef.current = null;
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
map.attributionControl.removeAttribution(CARTO_ATTRIBUTION);
|
|
309
|
+
map.attributionControl.removeAttribution(OSM_ATTRIBUTION);
|
|
310
|
+
} catch {
|
|
311
|
+
}
|
|
312
|
+
const isCartoTiles = effectiveTileUrl.includes("cartocdn");
|
|
313
|
+
if (isCartoTiles) {
|
|
314
|
+
map.attributionControl.addAttribution(CARTO_ATTRIBUTION);
|
|
315
|
+
}
|
|
316
|
+
const tile = L.tileLayer(effectiveTileUrl, {
|
|
317
|
+
maxZoom: 19,
|
|
318
|
+
subdomains: isCartoTiles ? "abcd" : "abc",
|
|
319
|
+
crossOrigin: true
|
|
320
|
+
});
|
|
321
|
+
tile.addTo(map);
|
|
322
|
+
tile.bringToBack();
|
|
323
|
+
tileLayerRef.current = tile;
|
|
324
|
+
let hasSwitchedToFallback = false;
|
|
325
|
+
const onTileError = () => {
|
|
326
|
+
if (hasSwitchedToFallback) return;
|
|
327
|
+
hasSwitchedToFallback = true;
|
|
328
|
+
tile.off("tileerror", onTileError);
|
|
329
|
+
tile.remove();
|
|
330
|
+
const fallback = L.tileLayer(FALLBACK_TILE, {
|
|
331
|
+
maxZoom: 19,
|
|
332
|
+
subdomains: "abc",
|
|
333
|
+
crossOrigin: true
|
|
334
|
+
});
|
|
335
|
+
fallback.addTo(map);
|
|
336
|
+
fallback.bringToBack();
|
|
337
|
+
tileLayerRef.current = fallback;
|
|
338
|
+
};
|
|
339
|
+
tile.on("tileerror", onTileError);
|
|
340
|
+
}, [effectiveTileUrl, ready]);
|
|
265
341
|
useEffect(() => {
|
|
266
342
|
if (!ready || !mapRef.current) return;
|
|
267
343
|
const map = mapRef.current;
|
|
268
344
|
clearLayers();
|
|
269
|
-
if (nightTileUrl &&
|
|
345
|
+
if (nightTileUrl && internalTerminator) {
|
|
270
346
|
const nightTile = L.tileLayer(nightTileUrl, {
|
|
271
347
|
maxZoom: 19,
|
|
272
348
|
crossOrigin: true,
|
|
@@ -275,7 +351,7 @@ function GroundTrackMapLeaflet({
|
|
|
275
351
|
});
|
|
276
352
|
addLayer(nightTile);
|
|
277
353
|
}
|
|
278
|
-
if (
|
|
354
|
+
if (internalTerminator) {
|
|
279
355
|
const now = terminatorTime ?? /* @__PURE__ */ new Date();
|
|
280
356
|
const BAND_STEP = 2;
|
|
281
357
|
const MAX_DEP = 24;
|
|
@@ -308,8 +384,31 @@ function GroundTrackMapLeaflet({
|
|
|
308
384
|
});
|
|
309
385
|
prevOpacity = b.opacity;
|
|
310
386
|
}
|
|
387
|
+
const terminatorEdge = calculateTerminatorContinuous(now, 0);
|
|
388
|
+
if (terminatorEdge.sunset.length > 2) {
|
|
389
|
+
const sunsetLine = terminatorEdge.sunset.map(([lat, lon]) => [lat, lon]);
|
|
390
|
+
const sunriseLine = terminatorEdge.sunrise.map(([lat, lon]) => [lat, lon]);
|
|
391
|
+
[0, 360, -360].forEach((offset) => {
|
|
392
|
+
addLayer(L.polyline(
|
|
393
|
+
sunsetLine.map(([lat, lon]) => [lat, lon + offset]),
|
|
394
|
+
{ color: "#5a8ec8", weight: 4, opacity: 0.12, interactive: false, smoothFactor: 1.5 }
|
|
395
|
+
));
|
|
396
|
+
addLayer(L.polyline(
|
|
397
|
+
sunriseLine.map(([lat, lon]) => [lat, lon + offset]),
|
|
398
|
+
{ color: "#5a8ec8", weight: 4, opacity: 0.12, interactive: false, smoothFactor: 1.5 }
|
|
399
|
+
));
|
|
400
|
+
addLayer(L.polyline(
|
|
401
|
+
sunsetLine.map(([lat, lon]) => [lat, lon + offset]),
|
|
402
|
+
{ color: "#7aa4d4", weight: 1, opacity: 0.5, interactive: false, smoothFactor: 1.5 }
|
|
403
|
+
));
|
|
404
|
+
addLayer(L.polyline(
|
|
405
|
+
sunriseLine.map(([lat, lon]) => [lat, lon + offset]),
|
|
406
|
+
{ color: "#7aa4d4", weight: 1, opacity: 0.5, interactive: false, smoothFactor: 1.5 }
|
|
407
|
+
));
|
|
408
|
+
});
|
|
409
|
+
}
|
|
311
410
|
}
|
|
312
|
-
if (lightSources && lightSources.length > 0 &&
|
|
411
|
+
if (lightSources && lightSources.length > 0 && internalTerminator) {
|
|
313
412
|
const now = terminatorTime ?? /* @__PURE__ */ new Date();
|
|
314
413
|
const dayOfYear = Math.floor((now.getTime() - new Date(now.getFullYear(), 0, 0).getTime()) / 864e5);
|
|
315
414
|
const declination = -23.44 * Math.cos(2 * Math.PI / 365 * (dayOfYear + 10));
|
|
@@ -355,7 +454,7 @@ function GroundTrackMapLeaflet({
|
|
|
355
454
|
}
|
|
356
455
|
}
|
|
357
456
|
}
|
|
358
|
-
if (
|
|
457
|
+
if (internalGrid) {
|
|
359
458
|
const gridStyle = { color: "rgba(157, 112, 255, 0.12)", weight: 0.5, interactive: false };
|
|
360
459
|
[-360, 0, 360].forEach((offset) => {
|
|
361
460
|
for (let lon = -180; lon <= 180; lon += 30) {
|
|
@@ -547,11 +646,11 @@ function GroundTrackMapLeaflet({
|
|
|
547
646
|
ready,
|
|
548
647
|
allSatellites,
|
|
549
648
|
groundStations,
|
|
550
|
-
|
|
649
|
+
internalTerminator,
|
|
551
650
|
terminatorTime,
|
|
552
651
|
nightTileUrl,
|
|
553
652
|
lightSources,
|
|
554
|
-
|
|
653
|
+
internalGrid,
|
|
555
654
|
showEquator,
|
|
556
655
|
showLegend,
|
|
557
656
|
tokens.colors.text.secondary,
|
|
@@ -650,8 +749,42 @@ function GroundTrackMapLeaflet({
|
|
|
650
749
|
map.setView(defaultCenter, defaultZoom);
|
|
651
750
|
}
|
|
652
751
|
}, [allSatellites, groundStations, defaultCenter, defaultZoom]);
|
|
752
|
+
const handleZoomIn = useCallback(() => {
|
|
753
|
+
var _a;
|
|
754
|
+
(_a = mapRef.current) == null ? void 0 : _a.zoomIn();
|
|
755
|
+
}, []);
|
|
756
|
+
const handleZoomOut = useCallback(() => {
|
|
757
|
+
var _a;
|
|
758
|
+
(_a = mapRef.current) == null ? void 0 : _a.zoomOut();
|
|
759
|
+
}, []);
|
|
653
760
|
const resolvedMinHeight = minHeight || (typeof height === "number" ? `${height}px` : "400px");
|
|
654
761
|
const isEmpty = allSatellites.length === 0 && groundStations.length === 0 && (!pins || pins.length === 0);
|
|
762
|
+
const ctrlBtnBase = {
|
|
763
|
+
background: "rgba(20, 24, 38, 0.92)",
|
|
764
|
+
backdropFilter: "blur(8px)",
|
|
765
|
+
WebkitBackdropFilter: "blur(8px)",
|
|
766
|
+
border: "1px solid rgba(120, 100, 180, 0.18)",
|
|
767
|
+
color: "#c8c0d8",
|
|
768
|
+
cursor: "pointer",
|
|
769
|
+
display: "flex",
|
|
770
|
+
alignItems: "center",
|
|
771
|
+
justifyContent: "center",
|
|
772
|
+
transition: "background 0.15s, border-color 0.15s"
|
|
773
|
+
};
|
|
774
|
+
const ctrlHover = (e) => {
|
|
775
|
+
e.currentTarget.style.background = "rgba(30, 34, 52, 0.95)";
|
|
776
|
+
e.currentTarget.style.borderColor = "rgba(157, 112, 255, 0.4)";
|
|
777
|
+
};
|
|
778
|
+
const ctrlLeave = (e) => {
|
|
779
|
+
e.currentTarget.style.background = "rgba(20, 24, 38, 0.92)";
|
|
780
|
+
e.currentTarget.style.borderColor = "rgba(120, 100, 180, 0.18)";
|
|
781
|
+
};
|
|
782
|
+
const overlayItems = [];
|
|
783
|
+
overlayItems.push({ id: "terminator", label: "Day / Night", enabled: internalTerminator });
|
|
784
|
+
overlayItems.push({ id: "grid", label: "Grid Lines", enabled: internalGrid });
|
|
785
|
+
for (const l of customLayers ?? []) {
|
|
786
|
+
overlayItems.push({ id: l.id, label: l.label, enabled: customLayerState[l.id] ?? (l.defaultEnabled ?? true) });
|
|
787
|
+
}
|
|
655
788
|
return /* @__PURE__ */ jsxs(
|
|
656
789
|
"div",
|
|
657
790
|
{
|
|
@@ -689,35 +822,232 @@ function GroundTrackMapLeaflet({
|
|
|
689
822
|
children: emptyMessage
|
|
690
823
|
}
|
|
691
824
|
),
|
|
692
|
-
|
|
693
|
-
"
|
|
825
|
+
/* @__PURE__ */ jsxs(
|
|
826
|
+
"div",
|
|
694
827
|
{
|
|
695
|
-
type: "button",
|
|
696
|
-
onClick: handleRecenter,
|
|
697
|
-
title: "Recenter map",
|
|
698
|
-
"aria-label": "Recenter map",
|
|
699
828
|
style: {
|
|
700
829
|
position: "absolute",
|
|
701
|
-
top:
|
|
702
|
-
right:
|
|
830
|
+
top: 10,
|
|
831
|
+
right: 10,
|
|
703
832
|
zIndex: 1e3,
|
|
704
|
-
background: "rgba(24, 29, 46, 0.9)",
|
|
705
|
-
border: "1px solid rgba(157, 112, 255, 0.25)",
|
|
706
|
-
borderRadius: 6,
|
|
707
|
-
color: "#e4e0f0",
|
|
708
|
-
cursor: "pointer",
|
|
709
|
-
padding: "6px 10px",
|
|
710
|
-
fontSize: 12,
|
|
711
833
|
display: "flex",
|
|
712
|
-
|
|
713
|
-
gap: 4
|
|
834
|
+
flexDirection: "row",
|
|
835
|
+
gap: 4,
|
|
836
|
+
alignItems: "flex-start",
|
|
837
|
+
pointerEvents: "none"
|
|
714
838
|
},
|
|
715
839
|
children: [
|
|
716
|
-
/* @__PURE__ */
|
|
717
|
-
|
|
718
|
-
|
|
840
|
+
showRecenterButton && /* @__PURE__ */ jsx(
|
|
841
|
+
"button",
|
|
842
|
+
{
|
|
843
|
+
type: "button",
|
|
844
|
+
onClick: handleRecenter,
|
|
845
|
+
title: "Recenter map to fit all assets and ground stations",
|
|
846
|
+
"aria-label": "Recenter map",
|
|
847
|
+
style: {
|
|
848
|
+
...ctrlBtnBase,
|
|
849
|
+
borderRadius: 4,
|
|
850
|
+
padding: "6px 8px",
|
|
851
|
+
gap: 4,
|
|
852
|
+
fontSize: 10,
|
|
853
|
+
fontWeight: 500,
|
|
854
|
+
letterSpacing: "0.03em",
|
|
855
|
+
pointerEvents: "auto"
|
|
856
|
+
},
|
|
857
|
+
onMouseEnter: ctrlHover,
|
|
858
|
+
onMouseLeave: ctrlLeave,
|
|
859
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "13", height: "13", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", children: [
|
|
860
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" }),
|
|
861
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2v4M12 18v4M2 12h4M18 12h4" })
|
|
862
|
+
] })
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsxs("div", { ref: layersPanelRef, style: { position: "relative", pointerEvents: "auto" }, children: [
|
|
866
|
+
/* @__PURE__ */ jsx(
|
|
867
|
+
"button",
|
|
868
|
+
{
|
|
869
|
+
type: "button",
|
|
870
|
+
onClick: () => setLayersPanelOpen((o) => !o),
|
|
871
|
+
title: "Map layers",
|
|
872
|
+
"aria-label": "Toggle map layers panel",
|
|
873
|
+
"aria-expanded": layersPanelOpen,
|
|
874
|
+
style: {
|
|
875
|
+
...ctrlBtnBase,
|
|
876
|
+
borderRadius: 4,
|
|
877
|
+
padding: "6px 8px",
|
|
878
|
+
pointerEvents: "auto",
|
|
879
|
+
borderColor: layersPanelOpen ? "rgba(157, 112, 255, 0.4)" : void 0,
|
|
880
|
+
background: layersPanelOpen ? "rgba(30, 34, 52, 0.95)" : ctrlBtnBase.background
|
|
881
|
+
},
|
|
882
|
+
onMouseEnter: ctrlHover,
|
|
883
|
+
onMouseLeave: ctrlLeave,
|
|
884
|
+
children: /* @__PURE__ */ jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinejoin: "round", children: [
|
|
885
|
+
/* @__PURE__ */ jsx("path", { d: "M12 2L2 7l10 5 10-5-10-5z" }),
|
|
886
|
+
/* @__PURE__ */ jsx("path", { d: "M2 17l10 5 10-5" }),
|
|
887
|
+
/* @__PURE__ */ jsx("path", { d: "M2 12l10 5 10-5" })
|
|
888
|
+
] })
|
|
889
|
+
}
|
|
890
|
+
),
|
|
891
|
+
layersPanelOpen && /* @__PURE__ */ jsxs(
|
|
892
|
+
"div",
|
|
893
|
+
{
|
|
894
|
+
style: {
|
|
895
|
+
position: "absolute",
|
|
896
|
+
top: "calc(100% + 6px)",
|
|
897
|
+
right: 0,
|
|
898
|
+
minWidth: 180,
|
|
899
|
+
background: "rgba(16, 18, 30, 0.96)",
|
|
900
|
+
backdropFilter: "blur(16px)",
|
|
901
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
902
|
+
border: "1px solid rgba(120, 100, 180, 0.18)",
|
|
903
|
+
borderRadius: 6,
|
|
904
|
+
padding: "8px 0",
|
|
905
|
+
boxShadow: "0 8px 32px rgba(0,0,0,0.5)"
|
|
906
|
+
},
|
|
907
|
+
children: [
|
|
908
|
+
!isExplicitTileUrl && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
909
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
910
|
+
padding: "4px 12px 6px",
|
|
911
|
+
fontSize: 9,
|
|
912
|
+
fontWeight: 600,
|
|
913
|
+
letterSpacing: "0.08em",
|
|
914
|
+
textTransform: "uppercase",
|
|
915
|
+
color: "#7a748e"
|
|
916
|
+
}, children: "Base Map" }),
|
|
917
|
+
/* @__PURE__ */ jsx("div", { style: { display: "flex", gap: 2, padding: "0 8px 8px" }, children: ["dark", "satellite"].map((style) => /* @__PURE__ */ jsxs(
|
|
918
|
+
"button",
|
|
919
|
+
{
|
|
920
|
+
type: "button",
|
|
921
|
+
onClick: () => handleTileStyleChange(style),
|
|
922
|
+
"aria-pressed": tileStyle === style,
|
|
923
|
+
style: {
|
|
924
|
+
flex: 1,
|
|
925
|
+
background: tileStyle === style ? "rgba(157, 112, 255, 0.18)" : "rgba(255,255,255,0.03)",
|
|
926
|
+
border: `1px solid ${tileStyle === style ? "rgba(157, 112, 255, 0.35)" : "rgba(120, 100, 180, 0.1)"}`,
|
|
927
|
+
borderRadius: 4,
|
|
928
|
+
color: tileStyle === style ? "#d0c4ee" : "#7a748e",
|
|
929
|
+
cursor: "pointer",
|
|
930
|
+
padding: "5px 6px",
|
|
931
|
+
fontSize: 10,
|
|
932
|
+
fontWeight: tileStyle === style ? 600 : 400,
|
|
933
|
+
display: "flex",
|
|
934
|
+
alignItems: "center",
|
|
935
|
+
justifyContent: "center",
|
|
936
|
+
gap: 4,
|
|
937
|
+
transition: "all 0.15s ease"
|
|
938
|
+
},
|
|
939
|
+
children: [
|
|
940
|
+
style === "dark" ? /* @__PURE__ */ jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "currentColor", stroke: "none", children: /* @__PURE__ */ jsx("path", { d: "M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z" }) }) : /* @__PURE__ */ jsxs("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: [
|
|
941
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
942
|
+
/* @__PURE__ */ jsx("path", { d: "M2 12h20M12 2a15.3 15.3 0 014 10 15.3 15.3 0 01-4 10 15.3 15.3 0 01-4-10 15.3 15.3 0 014-10z" })
|
|
943
|
+
] }),
|
|
944
|
+
style === "dark" ? "Dark" : "Satellite"
|
|
945
|
+
]
|
|
946
|
+
},
|
|
947
|
+
style
|
|
948
|
+
)) }),
|
|
949
|
+
/* @__PURE__ */ jsx("div", { style: { height: 1, background: "rgba(120, 100, 180, 0.1)", margin: "0 8px" } })
|
|
950
|
+
] }),
|
|
951
|
+
/* @__PURE__ */ jsx("div", { style: {
|
|
952
|
+
padding: `${isExplicitTileUrl ? "4px" : "8px"} 12px 4px`,
|
|
953
|
+
fontSize: 9,
|
|
954
|
+
fontWeight: 600,
|
|
955
|
+
letterSpacing: "0.08em",
|
|
956
|
+
textTransform: "uppercase",
|
|
957
|
+
color: "#7a748e"
|
|
958
|
+
}, children: "Overlays" }),
|
|
959
|
+
overlayItems.map((item) => /* @__PURE__ */ jsxs(
|
|
960
|
+
"button",
|
|
961
|
+
{
|
|
962
|
+
type: "button",
|
|
963
|
+
onClick: () => handleLayerToggle(item.id, !item.enabled),
|
|
964
|
+
style: {
|
|
965
|
+
display: "flex",
|
|
966
|
+
alignItems: "center",
|
|
967
|
+
gap: 8,
|
|
968
|
+
width: "100%",
|
|
969
|
+
padding: "5px 12px",
|
|
970
|
+
background: "transparent",
|
|
971
|
+
border: "none",
|
|
972
|
+
color: item.enabled ? "#c8c0d8" : "#5a5470",
|
|
973
|
+
cursor: "pointer",
|
|
974
|
+
fontSize: 11,
|
|
975
|
+
textAlign: "left",
|
|
976
|
+
transition: "background 0.1s"
|
|
977
|
+
},
|
|
978
|
+
onMouseEnter: (e) => {
|
|
979
|
+
e.currentTarget.style.background = "rgba(157, 112, 255, 0.08)";
|
|
980
|
+
},
|
|
981
|
+
onMouseLeave: (e) => {
|
|
982
|
+
e.currentTarget.style.background = "transparent";
|
|
983
|
+
},
|
|
984
|
+
children: [
|
|
985
|
+
/* @__PURE__ */ jsx("span", { style: {
|
|
986
|
+
width: 14,
|
|
987
|
+
height: 14,
|
|
988
|
+
borderRadius: 3,
|
|
989
|
+
border: `1.5px solid ${item.enabled ? "rgba(157, 112, 255, 0.6)" : "rgba(120, 100, 180, 0.25)"}`,
|
|
990
|
+
background: item.enabled ? "rgba(157, 112, 255, 0.22)" : "transparent",
|
|
991
|
+
display: "flex",
|
|
992
|
+
alignItems: "center",
|
|
993
|
+
justifyContent: "center",
|
|
994
|
+
flexShrink: 0,
|
|
995
|
+
transition: "all 0.15s ease"
|
|
996
|
+
}, children: item.enabled && /* @__PURE__ */ jsx("svg", { width: "9", height: "9", viewBox: "0 0 12 12", fill: "none", stroke: "#d0c4ee", strokeWidth: "2", children: /* @__PURE__ */ jsx("path", { d: "M2 6l3 3 5-5" }) }) }),
|
|
997
|
+
item.label
|
|
998
|
+
]
|
|
999
|
+
},
|
|
1000
|
+
item.id
|
|
1001
|
+
))
|
|
1002
|
+
]
|
|
1003
|
+
}
|
|
1004
|
+
)
|
|
719
1005
|
] }),
|
|
720
|
-
"
|
|
1006
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", pointerEvents: "auto" }, children: [
|
|
1007
|
+
/* @__PURE__ */ jsx(
|
|
1008
|
+
"button",
|
|
1009
|
+
{
|
|
1010
|
+
type: "button",
|
|
1011
|
+
onClick: handleZoomIn,
|
|
1012
|
+
title: "Zoom in",
|
|
1013
|
+
"aria-label": "Zoom in",
|
|
1014
|
+
style: {
|
|
1015
|
+
...ctrlBtnBase,
|
|
1016
|
+
borderRadius: "4px 4px 0 0",
|
|
1017
|
+
borderBottom: "none",
|
|
1018
|
+
width: 30,
|
|
1019
|
+
height: 28,
|
|
1020
|
+
fontSize: 16,
|
|
1021
|
+
fontWeight: 300,
|
|
1022
|
+
pointerEvents: "auto"
|
|
1023
|
+
},
|
|
1024
|
+
onMouseEnter: ctrlHover,
|
|
1025
|
+
onMouseLeave: ctrlLeave,
|
|
1026
|
+
children: "+"
|
|
1027
|
+
}
|
|
1028
|
+
),
|
|
1029
|
+
/* @__PURE__ */ jsx(
|
|
1030
|
+
"button",
|
|
1031
|
+
{
|
|
1032
|
+
type: "button",
|
|
1033
|
+
onClick: handleZoomOut,
|
|
1034
|
+
title: "Zoom out",
|
|
1035
|
+
"aria-label": "Zoom out",
|
|
1036
|
+
style: {
|
|
1037
|
+
...ctrlBtnBase,
|
|
1038
|
+
borderRadius: "0 0 4px 4px",
|
|
1039
|
+
width: 30,
|
|
1040
|
+
height: 28,
|
|
1041
|
+
fontSize: 16,
|
|
1042
|
+
fontWeight: 300,
|
|
1043
|
+
pointerEvents: "auto"
|
|
1044
|
+
},
|
|
1045
|
+
onMouseEnter: ctrlHover,
|
|
1046
|
+
onMouseLeave: ctrlLeave,
|
|
1047
|
+
children: "−"
|
|
1048
|
+
}
|
|
1049
|
+
)
|
|
1050
|
+
] })
|
|
721
1051
|
]
|
|
722
1052
|
}
|
|
723
1053
|
)
|