@sjvair/monitor-map 3.0.3 → 3.0.5
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/dist/lib/LoadScreen.svelte +68 -0
- package/dist/lib/LoadScreen.svelte.d.ts +25 -0
- package/dist/lib/MainMapView.svelte +1 -0
- package/dist/lib/MainMapView.svelte.d.ts +26 -0
- package/dist/lib/MapLegend.svelte +15 -0
- package/dist/lib/MapLegend.svelte.d.ts +18 -0
- package/dist/lib/MonitorDetailPanel.svelte +152 -0
- package/dist/lib/MonitorDetailPanel.svelte.d.ts +3 -0
- package/dist/lib/MonitorMapLayout.svelte +193 -0
- package/dist/lib/MonitorMapLayout.svelte.d.ts +7 -0
- package/dist/lib/actions.d.ts +3 -0
- package/dist/lib/actions.js +12 -8
- package/dist/lib/assets/icons/adjustment-horizontal.svg +3 -0
- package/dist/lib/assets/logos/airgradient-blue.svg +63 -0
- package/dist/lib/assets/logos/airnow-compact.jpg +0 -0
- package/dist/lib/assets/logos/carb-compact.jpg +0 -0
- package/dist/lib/assets/logos/purpleair-compact.png +0 -0
- package/dist/lib/assets/logos/sjvair-parts/sjvair-air.webp +0 -0
- package/dist/lib/assets/logos/sjvair-parts/sjvair-icon.webp +0 -0
- package/dist/lib/assets/logos/sjvair-parts/sjvair-sjv.webp +0 -0
- package/dist/lib/assets/logos/sjvair-white.svg +115 -0
- package/dist/lib/assets/logos/sjvair.svg +96 -0
- package/dist/lib/collocation-sites/CollocationTooltip.svelte +98 -0
- package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +7 -0
- package/dist/lib/collocation-sites/collocation-utils.d.ts +3 -0
- package/dist/lib/collocation-sites/collocation-utils.js +30 -0
- package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +7 -0
- package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +17 -20
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +18 -0
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +98 -83
- package/dist/lib/collocation-sites/collocations.svelte.d.ts +9 -0
- package/dist/lib/collocation-sites/collocations.svelte.js +17 -26
- package/dist/lib/collocation-sites/types.d.ts +8 -0
- package/dist/lib/collocation-sites/types.js +1 -0
- package/dist/lib/colors.d.ts +17 -0
- package/dist/lib/colors.js +29 -23
- package/dist/lib/components/DataBox.svelte +29 -0
- package/dist/lib/components/DataBox.svelte.d.ts +9 -0
- package/dist/lib/components/DisplayOption.svelte +7 -0
- package/dist/lib/components/DisplayOption.svelte.d.ts +5 -0
- package/dist/lib/components/MapLayersDisplayOptions.svelte +42 -0
- package/dist/lib/components/MapLayersDisplayOptions.svelte.d.ts +18 -0
- package/dist/lib/components/SegmentedControl.svelte +61 -0
- package/dist/lib/components/SegmentedControl.svelte.d.ts +11 -0
- package/dist/lib/components/ToggleSwitch.svelte +93 -0
- package/dist/lib/components/ToggleSwitch.svelte.d.ts +9 -0
- package/dist/lib/components/ui/button/button.svelte +89 -0
- package/dist/lib/components/ui/button/button.svelte.d.ts +70 -0
- package/dist/lib/components/ui/button/index.d.ts +2 -0
- package/dist/lib/components/ui/button/index.js +4 -0
- package/dist/lib/components/ui/range-calendar/index.d.ts +19 -0
- package/dist/lib/components/ui/range-calendar/index.js +21 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-caption.svelte +76 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-caption.svelte.d.ts +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-cell.svelte +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-cell.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-day.svelte +36 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-day.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.svelte +7 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.svelte +7 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.svelte +12 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid.svelte +16 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-grid.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.svelte +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-header.svelte +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-header.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-heading.svelte +16 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-heading.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-month-select.svelte +44 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-month-select.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-month.svelte +15 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-month.svelte.d.ts +5 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-months.svelte +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-months.svelte.d.ts +5 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-nav.svelte +19 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-nav.svelte.d.ts +5 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-next-button.svelte +36 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-next-button.svelte.d.ts +8 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.svelte +36 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.svelte.d.ts +8 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-year-select.svelte +43 -0
- package/dist/lib/components/ui/range-calendar/range-calendar-year-select.svelte.d.ts +4 -0
- package/dist/lib/components/ui/range-calendar/range-calendar.svelte +112 -0
- package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +21 -0
- package/dist/lib/data-chart/DataChart.svelte +303 -0
- package/dist/lib/data-chart/DataChart.svelte.d.ts +7 -0
- package/dist/lib/data-chart/DateRange.d.ts +6 -0
- package/dist/lib/data-chart/DateRange.js +15 -14
- package/dist/lib/data-chart/chart-utils.d.ts +3 -0
- package/dist/lib/data-chart/chart-utils.js +157 -93
- package/dist/lib/data-chart/data-chart.svelte.d.ts +7 -0
- package/dist/lib/data-chart/data-chart.svelte.js +7 -28
- package/dist/lib/data-chart/requests.d.ts +3 -0
- package/dist/lib/data-chart/requests.js +36 -28
- package/dist/lib/data-chart/tooltip.d.ts +10 -0
- package/dist/lib/data-chart/tooltip.js +160 -98
- package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +16 -0
- package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +7 -0
- package/dist/lib/ev-stations/components/EvStationTooltip.svelte +127 -0
- package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +7 -0
- package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte +46 -0
- package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte.d.ts +18 -0
- package/dist/lib/ev-stations/data-maps.d.ts +5 -0
- package/dist/lib/ev-stations/data-maps.js +152 -4
- package/dist/lib/ev-stations/ev-station-icons.d.ts +16 -0
- package/dist/lib/ev-stations/ev-station-icons.js +21 -27
- package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +19 -0
- package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +130 -117
- package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +31 -0
- package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +206 -180
- package/dist/lib/ev-stations/ev-stations.svelte.d.ts +9 -0
- package/dist/lib/ev-stations/ev-stations.svelte.js +54 -32
- package/dist/lib/ev-stations/types.d.ts +53 -0
- package/dist/lib/ev-stations/types.js +1 -0
- package/dist/lib/ev-stations/zip-codes.d.ts +13 -0
- package/dist/lib/ev-stations/zip-codes.js +457 -135
- package/dist/lib/hms/components/HMSFireLegend.svelte +21 -0
- package/dist/lib/hms/components/HMSFireLegend.svelte.d.ts +18 -0
- package/dist/lib/hms/hms-fire-icon-manager.d.ts +5 -0
- package/dist/lib/hms/hms-fire-icon-manager.js +28 -37
- package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +23 -0
- package/dist/lib/hms/hms-fire-map-integration.svelte.js +94 -97
- package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +19 -0
- package/dist/lib/hms/hms-smoke-map-integration.svelte.js +68 -84
- package/dist/lib/hms/hms.svelte.d.ts +19 -0
- package/dist/lib/hms/hms.svelte.js +225 -76
- package/dist/lib/index.d.ts +68 -0
- package/dist/lib/index.js +56 -21
- package/dist/lib/map/Map.svelte +13 -0
- package/dist/lib/map/Map.svelte.d.ts +8 -0
- package/dist/lib/map/MapStyleDisplayOptions.svelte +61 -0
- package/dist/lib/map/MapStyleDisplayOptions.svelte.d.ts +3 -0
- package/dist/lib/map/Menu.svelte +64 -0
- package/dist/lib/map/Menu.svelte.d.ts +5 -0
- package/dist/lib/map/icons.d.ts +7 -0
- package/dist/lib/map/icons.js +24 -22
- package/dist/lib/map/integrations/base-layer-seperator.d.ts +9 -0
- package/dist/lib/map/integrations/base-layer-seperator.js +11 -12
- package/dist/lib/map/integrations/click-manager.d.ts +14 -0
- package/dist/lib/map/integrations/click-manager.js +52 -33
- package/dist/lib/map/integrations/integrations-manager.d.ts +8 -0
- package/dist/lib/map/integrations/integrations-manager.js +20 -12
- package/dist/lib/map/integrations/map-display-option.svelte.d.ts +7 -0
- package/dist/lib/map/integrations/map-display-option.svelte.js +10 -18
- package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +13 -0
- package/dist/lib/map/integrations/map-geojson-integration.svelte.js +21 -17
- package/dist/lib/map/integrations/map-icon-manager.d.ts +15 -0
- package/dist/lib/map/integrations/map-icon-manager.js +52 -46
- package/dist/lib/map/integrations/map-integration.svelte.d.ts +6 -0
- package/dist/lib/map/integrations/map-integration.svelte.js +2 -5
- package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +11 -0
- package/dist/lib/map/integrations/map-layer-integration.svelte.js +36 -23
- package/dist/lib/map/integrations/tooltip.svelte.d.ts +28 -0
- package/dist/lib/map/integrations/tooltip.svelte.js +120 -78
- package/dist/lib/map/integrations/types.d.ts +14 -0
- package/dist/lib/map/integrations/types.js +1 -0
- package/dist/lib/map/map.svelte.d.ts +14 -0
- package/dist/lib/map/map.svelte.js +48 -50
- package/dist/lib/map/utils.d.ts +7 -0
- package/dist/lib/map/utils.js +32 -29
- package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +112 -0
- package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +7 -0
- package/dist/lib/monitors/components/MonitorMarkersLegend.svelte +41 -0
- package/dist/lib/monitors/components/MonitorMarkersLegend.svelte.d.ts +3 -0
- package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +128 -0
- package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte.d.ts +6 -0
- package/dist/lib/monitors/components/MonitorTooltip.svelte +61 -0
- package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +7 -0
- package/dist/lib/monitors/components/MonitorWidgetModal.svelte +100 -0
- package/dist/lib/monitors/components/MonitorWidgetModal.svelte.d.ts +6 -0
- package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte +79 -0
- package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte.d.ts +3 -0
- package/dist/lib/monitors/monitor-utils.d.ts +4 -0
- package/dist/lib/monitors/monitor-utils.js +33 -23
- package/dist/lib/monitors/monitors-cluster-renderer.d.ts +33 -0
- package/dist/lib/monitors/monitors-cluster-renderer.js +218 -209
- package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +13 -0
- package/dist/lib/monitors/monitors-icon-manager.svelte.js +75 -70
- package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +40 -0
- package/dist/lib/monitors/monitors-map-integration.svelte.js +278 -270
- package/dist/lib/monitors/monitors.svelte.d.ts +16 -0
- package/dist/lib/monitors/monitors.svelte.js +38 -63
- package/dist/lib/monitors/types.d.ts +26 -0
- package/dist/lib/monitors/types.js +1 -0
- package/dist/lib/reactivity.svelte.d.ts +0 -0
- package/dist/lib/reactivity.svelte.js +83 -0
- package/dist/lib/router-context.d.ts +27 -0
- package/dist/lib/router-context.js +11 -11
- package/dist/lib/routes.d.ts +2 -0
- package/dist/lib/routes.js +10 -9
- package/dist/lib/search/Search.svelte +189 -0
- package/dist/lib/search/Search.svelte.d.ts +3 -0
- package/dist/lib/search/service.d.ts +17 -0
- package/dist/lib/search/service.js +75 -85
- package/dist/lib/utils.d.ts +13 -0
- package/dist/lib/utils.js +10 -12
- package/dist/lib/weather.d.ts +1 -0
- package/dist/lib/weather.js +11 -7
- package/dist/lib/wind/wind.svelte.d.ts +10 -0
- package/dist/lib/wind/wind.svelte.js +13 -21
- package/package.json +9 -7
- package/src/lib/LoadScreen.svelte +3 -3
- package/src/lib/hms/components/HMSFireLegend.svelte +1 -1
- package/src/lib/hms/hms.svelte.ts +8 -9
- package/src/lib/index.ts +18 -0
- package/src/lib/routes.ts +6 -1
- package/src/lib/utils.ts +1 -1
- package/dist/lib/LoadScreen.js +0 -73
- package/dist/lib/MainMapView.js +0 -7
- package/dist/lib/MapLegend.js +0 -13
- package/dist/lib/MonitorDetailPanel.js +0 -169
- package/dist/lib/MonitorMapLayout.js +0 -91
- package/dist/lib/_virtual/_rolldown/runtime.js +0 -11
- package/dist/lib/assets/logos/airgradient-blue.js +0 -4
- package/dist/lib/assets/logos/airnow-compact.js +0 -4
- package/dist/lib/assets/logos/carb-compact.js +0 -4
- package/dist/lib/assets/logos/purpleair-compact.js +0 -4
- package/dist/lib/assets/logos/sjvair.js +0 -4
- package/dist/lib/collocation-sites/CollocationTooltip.js +0 -105
- package/dist/lib/components/DataBox.js +0 -30
- package/dist/lib/components/DisplayOption.js +0 -10
- package/dist/lib/components/MapLayersDisplayOptions.js +0 -87
- package/dist/lib/components/SegmentedControl.js +0 -37
- package/dist/lib/components/ToggleSwitch.js +0 -17
- package/dist/lib/components/ui/button/button.js +0 -34
- package/dist/lib/components/ui/range-calendar/range-calendar-caption.js +0 -82
- package/dist/lib/components/ui/range-calendar/range-calendar-cell.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-day.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.js +0 -27
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.js +0 -27
- package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-grid.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-header.js +0 -35
- package/dist/lib/components/ui/range-calendar/range-calendar-month-select.js +0 -61
- package/dist/lib/components/ui/range-calendar/range-calendar-month.js +0 -25
- package/dist/lib/components/ui/range-calendar/range-calendar-months.js +0 -25
- package/dist/lib/components/ui/range-calendar/range-calendar-nav.js +0 -25
- package/dist/lib/components/ui/range-calendar/range-calendar-next-button.js +0 -58
- package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.js +0 -58
- package/dist/lib/components/ui/range-calendar/range-calendar-year-select.js +0 -59
- package/dist/lib/components/ui/range-calendar/range-calendar.js +0 -272
- package/dist/lib/data-chart/DataChart.js +0 -142
- package/dist/lib/ev-stations/components/EvStationClusterTooltip.js +0 -16
- package/dist/lib/ev-stations/components/EvStationTooltip.js +0 -120
- package/dist/lib/ev-stations/components/EvStationsDisplayOptions.js +0 -41
- package/dist/lib/hms/components/HMSFireLegend.js +0 -35
- package/dist/lib/map/Map.js +0 -14
- package/dist/lib/map/MapStyleDisplayOptions.js +0 -43
- package/dist/lib/map/Menu.js +0 -44
- package/dist/lib/monitors/components/MonitorClusterTooltip.js +0 -83
- package/dist/lib/monitors/components/MonitorMarkersLegend.js +0 -35
- package/dist/lib/monitors/components/MonitorSubscriptionManager.js +0 -104
- package/dist/lib/monitors/components/MonitorTooltip.js +0 -59
- package/dist/lib/monitors/components/MonitorWidgetModal.js +0 -40
- package/dist/lib/monitors/components/MonitorsDisplayOptions.js +0 -76
- package/dist/lib/search/Search.js +0 -124
- package/dist/lib/sjvair-air.avif +0 -0
- package/dist/lib/sjvair-air.png +0 -0
- package/dist/lib/sjvair-air.webp +0 -0
- package/dist/lib/sjvair-air2.avif +0 -0
- package/dist/lib/sjvair-air2.png +0 -0
- package/dist/lib/sjvair-air2.webp +0 -0
- package/dist/lib/sjvair-icon.avif +0 -0
- package/dist/lib/sjvair-icon.png +0 -0
- package/dist/lib/sjvair-icon.webp +0 -0
- package/dist/lib/sjvair-icon2.avif +0 -0
- package/dist/lib/sjvair-icon2.png +0 -0
- package/dist/lib/sjvair-icon2.webp +0 -0
- package/dist/lib/sjvair-sjv.avif +0 -0
- package/dist/lib/sjvair-sjv.png +0 -0
- package/dist/lib/sjvair-sjv.webp +0 -0
- package/dist/lib/sjvair-sjv2.avif +0 -0
- package/dist/lib/sjvair-sjv2.png +0 -0
- package/dist/lib/sjvair-sjv2.webp +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { BellCheckIcon, BellOffIcon, ChevronDownIcon } from "@lucide/svelte";
|
|
3
|
+
import { getSubscriptions, subscribe, unsubscribe } from "@sjvair/sdk/account";
|
|
4
|
+
import { monitorsManager } from "../..";
|
|
5
|
+
|
|
6
|
+
interface MonitorSubscriptionManagerProps {
|
|
7
|
+
monitorId: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const ALERT_LEVEL_NAMES = [
|
|
11
|
+
"unhealthy_sensitive",
|
|
12
|
+
"unhealthy",
|
|
13
|
+
"very_unhealthy",
|
|
14
|
+
"hazardous"
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
const { monitorId }: MonitorSubscriptionManagerProps = $props();
|
|
18
|
+
|
|
19
|
+
let open = $state(false);
|
|
20
|
+
let loading = $state(false);
|
|
21
|
+
let saving = $state(false);
|
|
22
|
+
let subscribedLevel: string | null = $state(null);
|
|
23
|
+
|
|
24
|
+
const alertLevels = $derived.by(() => {
|
|
25
|
+
if (!monitorsManager.meta) return [];
|
|
26
|
+
try {
|
|
27
|
+
return monitorsManager.meta
|
|
28
|
+
.entryType("pm25")
|
|
29
|
+
.asIter.levels!.filter((level) =>
|
|
30
|
+
ALERT_LEVEL_NAMES.includes(level.name as (typeof ALERT_LEVEL_NAMES)[number])
|
|
31
|
+
);
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
$effect(() => {
|
|
38
|
+
void monitorId;
|
|
39
|
+
open = false;
|
|
40
|
+
subscribedLevel = null;
|
|
41
|
+
loadSubscription();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
async function loadSubscription() {
|
|
45
|
+
const id = monitorId;
|
|
46
|
+
loading = true;
|
|
47
|
+
try {
|
|
48
|
+
const subscriptions = await getSubscriptions("");
|
|
49
|
+
if (id !== monitorId) return;
|
|
50
|
+
const match = subscriptions.find((s) => s.monitor === id);
|
|
51
|
+
subscribedLevel = match?.level ?? null;
|
|
52
|
+
} finally {
|
|
53
|
+
if (id === monitorId) loading = false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function handleLevelClick(levelName: string | null) {
|
|
58
|
+
if (saving || !levelName) return;
|
|
59
|
+
saving = true;
|
|
60
|
+
const previous = subscribedLevel;
|
|
61
|
+
try {
|
|
62
|
+
if (levelName === subscribedLevel) {
|
|
63
|
+
await unsubscribe({ monitorId, apiToken: "", level: levelName });
|
|
64
|
+
subscribedLevel = null;
|
|
65
|
+
} else {
|
|
66
|
+
await subscribe({ monitorId, apiToken: "", level: levelName });
|
|
67
|
+
subscribedLevel = levelName;
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
subscribedLevel = previous;
|
|
71
|
+
return;
|
|
72
|
+
} finally {
|
|
73
|
+
saving = false;
|
|
74
|
+
}
|
|
75
|
+
open = false;
|
|
76
|
+
}
|
|
77
|
+
</script>
|
|
78
|
+
|
|
79
|
+
<div class="relative select-none">
|
|
80
|
+
<button
|
|
81
|
+
class={[
|
|
82
|
+
"flex w-full cursor-pointer items-center justify-center gap-2 rounded border px-3 py-1.5 text-sm font-semibold text-white",
|
|
83
|
+
subscribedLevel
|
|
84
|
+
? "border-green-700 bg-green-600 hover:bg-green-700"
|
|
85
|
+
: "border-blue-600 bg-blue-500 hover:bg-blue-600"
|
|
86
|
+
]}
|
|
87
|
+
disabled={loading}
|
|
88
|
+
onclick={() => (open = !open)}
|
|
89
|
+
>
|
|
90
|
+
{subscribedLevel ? "Manage Subscription" : "Subscribe to Alerts"}
|
|
91
|
+
<ChevronDownIcon
|
|
92
|
+
size={16}
|
|
93
|
+
class={["transition-transform duration-300", open ? "rotate-180" : ""]}
|
|
94
|
+
/>
|
|
95
|
+
</button>
|
|
96
|
+
|
|
97
|
+
{#if open}
|
|
98
|
+
<button aria-label="Close" class="fixed inset-0 z-10" onclick={() => (open = false)}></button>
|
|
99
|
+
<div class="absolute top-full left-0 z-20 mt-1 w-full overflow-hidden rounded shadow-lg">
|
|
100
|
+
{#if subscribedLevel}
|
|
101
|
+
<button
|
|
102
|
+
class="cursor-pointer px-4 py-2 text-sm rounded-t w-full flex items-center justify-between border border-black/30 hover:bg-[#F5F5F3]"
|
|
103
|
+
onclick={() => handleLevelClick(subscribedLevel)}
|
|
104
|
+
>
|
|
105
|
+
Unsubscribe
|
|
106
|
+
<BellOffIcon size={14} />
|
|
107
|
+
</button>
|
|
108
|
+
{/if}
|
|
109
|
+
{#each alertLevels as level (level.name)}
|
|
110
|
+
{@const isSubscribed = level.name === subscribedLevel}
|
|
111
|
+
<button
|
|
112
|
+
class={[
|
|
113
|
+
"flex w-full items-center justify-between px-4 py-2 text-sm text-white last:rounded-b",
|
|
114
|
+
!isSubscribed ? "first:rounded-t hover:brightness-90 cursor-pointer" : ""
|
|
115
|
+
]}
|
|
116
|
+
style="background-color: {level.color}"
|
|
117
|
+
disabled={saving}
|
|
118
|
+
onclick={!isSubscribed ? () => handleLevelClick(level.name) : null}
|
|
119
|
+
>
|
|
120
|
+
<span>{level.label}</span>
|
|
121
|
+
{#if isSubscribed}
|
|
122
|
+
<BellCheckIcon size={14} />
|
|
123
|
+
{/if}
|
|
124
|
+
</button>
|
|
125
|
+
{/each}
|
|
126
|
+
</div>
|
|
127
|
+
{/if}
|
|
128
|
+
</div>
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
interface MonitorSubscriptionManagerProps {
|
|
2
|
+
monitorId: string;
|
|
3
|
+
}
|
|
4
|
+
declare const MonitorSubscriptionManager: import("svelte").Component<MonitorSubscriptionManagerProps, {}, "">;
|
|
5
|
+
type MonitorSubscriptionManager = ReturnType<typeof MonitorSubscriptionManager>;
|
|
6
|
+
export default MonitorSubscriptionManager;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { SJVAirEntryLevel } from "@sjvair/sdk";
|
|
3
|
+
import { format, formatDistanceToNow } from "date-fns";
|
|
4
|
+
import DataBox from "../../components/DataBox.svelte";
|
|
5
|
+
import { monitorsManager } from "../monitors.svelte";
|
|
6
|
+
import { getCurrentLevel } from "../monitor-utils";
|
|
7
|
+
import type { MonitorMapFeature } from "../types";
|
|
8
|
+
|
|
9
|
+
interface MonitorTooltipProps {
|
|
10
|
+
feature: MonitorMapFeature;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const { feature }: MonitorTooltipProps = $props();
|
|
14
|
+
|
|
15
|
+
const data = $derived.by(() => {
|
|
16
|
+
const monitor = monitorsManager.latest?.get(feature.properties.id);
|
|
17
|
+
|
|
18
|
+
if (!monitor || !monitorsManager.meta) return;
|
|
19
|
+
|
|
20
|
+
const entryType = monitorsManager.meta.entryType(monitor.latest.entry_type);
|
|
21
|
+
const level: SJVAirEntryLevel | undefined = getCurrentLevel(
|
|
22
|
+
monitor.latest.value,
|
|
23
|
+
entryType.asIter.levels!
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const updateDuration = monitorsManager.meta.monitorType(monitor.type).expected_interval;
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
color: level?.color ?? "",
|
|
30
|
+
header: entryType.label,
|
|
31
|
+
date: {
|
|
32
|
+
formatted: format(monitor.latest.timestamp, "h:mm:aaa EEEE MMM dd, yyyy"),
|
|
33
|
+
diference: formatDistanceToNow(monitor.latest.timestamp, {
|
|
34
|
+
addSuffix: true,
|
|
35
|
+
includeSeconds: true
|
|
36
|
+
})
|
|
37
|
+
},
|
|
38
|
+
subheading: `(${updateDuration} avg)`,
|
|
39
|
+
value: Math.round(parseInt(monitor.latest.value, 10)).toString()
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
{#if data}
|
|
45
|
+
<div class="flex gap-2">
|
|
46
|
+
<DataBox
|
|
47
|
+
color={data.color}
|
|
48
|
+
header={data.header}
|
|
49
|
+
subheading={data.subheading}
|
|
50
|
+
value={data.value}
|
|
51
|
+
/>
|
|
52
|
+
<div class="flex flex-col">
|
|
53
|
+
<p>{data.date.formatted}</p>
|
|
54
|
+
<h1 class="text-lg font-bold underline">{feature.properties.name}</h1>
|
|
55
|
+
<div class="mt-auto">
|
|
56
|
+
<p class="text-base leading-none">Last updated</p>
|
|
57
|
+
<p class="text-base leading-none">{data.date.diference}</p>
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
</div>
|
|
61
|
+
{/if}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MonitorMapFeature } from "../types";
|
|
2
|
+
interface MonitorTooltipProps {
|
|
3
|
+
feature: MonitorMapFeature;
|
|
4
|
+
}
|
|
5
|
+
declare const MonitorTooltip: import("svelte").Component<MonitorTooltipProps, {}, "">;
|
|
6
|
+
type MonitorTooltip = ReturnType<typeof MonitorTooltip>;
|
|
7
|
+
export default MonitorTooltip;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { portal } from "../../actions";
|
|
3
|
+
import { SquareX } from "@lucide/svelte";
|
|
4
|
+
import { origin } from "@sjvair/sdk/http";
|
|
5
|
+
|
|
6
|
+
interface MonitorWidgetModalProps {
|
|
7
|
+
monitorId: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const widgetStyles = {
|
|
11
|
+
overflow: "hidden",
|
|
12
|
+
width: "290px",
|
|
13
|
+
height: "390px"
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const { monitorId }: MonitorWidgetModalProps = $props();
|
|
17
|
+
|
|
18
|
+
let modalOpen = $state(false);
|
|
19
|
+
let copied = $state(false);
|
|
20
|
+
|
|
21
|
+
const iframeSrc = $derived.by(() => {
|
|
22
|
+
return `${origin}/widget/#/${monitorId}`;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const iframeCode = $derived.by(() => {
|
|
26
|
+
return `<iframe src="${iframeSrc}" frameborder="0" allowtransparency="true" style="overflow: ${widgetStyles.overflow}; width: ${widgetStyles.width}; height: ${widgetStyles.height};"></iframe>`;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function copyToClipboard() {
|
|
30
|
+
navigator.clipboard.writeText(iframeCode);
|
|
31
|
+
copied = true;
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
copied = false;
|
|
34
|
+
}, 1000 * 2);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function openModal() {
|
|
38
|
+
modalOpen = true;
|
|
39
|
+
document.body.style.overflow = "hidden";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function closeModal() {
|
|
43
|
+
modalOpen = false;
|
|
44
|
+
document.body.style.overflow = "auto";
|
|
45
|
+
}
|
|
46
|
+
</script>
|
|
47
|
+
|
|
48
|
+
<div class="select-none">
|
|
49
|
+
<button
|
|
50
|
+
class="cursor-pointer rounded border border-blue-400 bg-blue-500 px-3 py-1.5 text-sm font-semibold text-white hover:bg-blue-600"
|
|
51
|
+
onclick={openModal}>Get the widget!</button
|
|
52
|
+
>
|
|
53
|
+
|
|
54
|
+
<div
|
|
55
|
+
use:portal
|
|
56
|
+
class={[
|
|
57
|
+
"fixed inset-0 z-9999 flex items-center justify-center bg-black/50 backdrop-blur-sm transition-all duration-200",
|
|
58
|
+
modalOpen ? "visible" : "invisible"
|
|
59
|
+
]}
|
|
60
|
+
>
|
|
61
|
+
<div
|
|
62
|
+
class="m-4 flex max-w-[min(450px,calc(100vw-2rem))] flex-col items-center justify-center rounded bg-white p-4 shadow-lg"
|
|
63
|
+
>
|
|
64
|
+
<button translate="no" class="cursor-pointer self-end" onclick={closeModal}>
|
|
65
|
+
<SquareX />
|
|
66
|
+
</button>
|
|
67
|
+
|
|
68
|
+
<!-- eslint-disable-next-line svelte/no-at-html-tags -->
|
|
69
|
+
<div translate="no">{@html iframeCode}</div>
|
|
70
|
+
|
|
71
|
+
<p class="mb-4 text-center">Copy the following code and paste it in your website</p>
|
|
72
|
+
|
|
73
|
+
<div
|
|
74
|
+
class="group relative flex w-full items-center overflow-hidden bg-neutral-800 hover:bg-neutral-600"
|
|
75
|
+
>
|
|
76
|
+
<code class="cursor-text overflow-x-scroll bg-inherit text-gray-300 select-text">
|
|
77
|
+
{iframeCode}
|
|
78
|
+
</code>
|
|
79
|
+
<div
|
|
80
|
+
class="invisible absolute top-1/2 left-[calc(100%-3rem)] flex -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-black/80 p-2 group-hover:visible"
|
|
81
|
+
>
|
|
82
|
+
<button
|
|
83
|
+
aria-label="Copy"
|
|
84
|
+
translate="no"
|
|
85
|
+
class="svg-icon content-copy cursor-pointer bg-gray-300"
|
|
86
|
+
onclick={copyToClipboard}
|
|
87
|
+
></button>
|
|
88
|
+
</div>
|
|
89
|
+
<div
|
|
90
|
+
class={[
|
|
91
|
+
"absolute flex h-full w-full items-center justify-center bg-[#1fb9ef] text-white transition-all duration-200 [text-shadow:1px_2px_4px_#333]",
|
|
92
|
+
copied ? "left-0" : "left-[120%]"
|
|
93
|
+
]}
|
|
94
|
+
>
|
|
95
|
+
Copied to clipboard!
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</div>
|
|
99
|
+
</div>
|
|
100
|
+
</div>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { MonitorsMeta, SJVAirMonitorDeviceMeta } from "@sjvair/sdk";
|
|
3
|
+
import DisplayOption from "../../components/DisplayOption.svelte";
|
|
4
|
+
import SegmentedControl from "../../components/SegmentedControl.svelte";
|
|
5
|
+
import ToggleSwitch from "../../components/ToggleSwitch.svelte";
|
|
6
|
+
import { monitorsManager } from "../monitors.svelte";
|
|
7
|
+
import { monitorsMapIntegration } from "../monitors-map-integration.svelte";
|
|
8
|
+
|
|
9
|
+
interface PollutantDisplayOptions {
|
|
10
|
+
label: string;
|
|
11
|
+
value: MonitorsMeta["default_pollutant"];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const pollutants: Array<PollutantDisplayOptions> = [
|
|
15
|
+
{
|
|
16
|
+
label: "PM 2.5",
|
|
17
|
+
value: "pm25"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
label: "Ozone",
|
|
21
|
+
value: "o3"
|
|
22
|
+
}
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const monitorDisplayOptions = $derived.by(() => {
|
|
26
|
+
if (monitorsManager.pollutant && monitorsManager.pollutant === "pm25")
|
|
27
|
+
return Object.entries(monitorsMapIntegration.displayOptions);
|
|
28
|
+
|
|
29
|
+
const validOptions = Object.entries(monitorsMapIntegration.displayOptions).filter(
|
|
30
|
+
([key, opt]) =>
|
|
31
|
+
key === "inactive" ||
|
|
32
|
+
monitorsManager.meta?.asIter.monitors.some(
|
|
33
|
+
(m: SJVAirMonitorDeviceMeta) =>
|
|
34
|
+
m.label === opt.label &&
|
|
35
|
+
monitorsManager.pollutant &&
|
|
36
|
+
monitorsManager.pollutant in m.entries
|
|
37
|
+
)
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
return validOptions;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
$effect(() => {
|
|
44
|
+
monitorsManager.list = [];
|
|
45
|
+
monitorsManager.latest = null;
|
|
46
|
+
monitorsManager.update();
|
|
47
|
+
});
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<DisplayOption>
|
|
51
|
+
<p class="text-lg font-bold underline">Air Monitors</p>
|
|
52
|
+
<div class="mb-2 w-full text-xs">
|
|
53
|
+
<div class="w-fit">
|
|
54
|
+
<ToggleSwitch
|
|
55
|
+
id="monitor-clusters"
|
|
56
|
+
label="Marker Clusters"
|
|
57
|
+
bind:value={monitorsMapIntegration.clustered}
|
|
58
|
+
></ToggleSwitch>
|
|
59
|
+
</div>
|
|
60
|
+
{#if monitorsManager.pollutant}
|
|
61
|
+
<SegmentedControl
|
|
62
|
+
segmentLabel="Pollutant:"
|
|
63
|
+
options={pollutants}
|
|
64
|
+
bind:group={monitorsManager.pollutant}
|
|
65
|
+
/>
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
{#each monitorDisplayOptions as [id, option] (option.label)}
|
|
70
|
+
{@const inputId = `${id}-monitor-display-option`}
|
|
71
|
+
<label for={inputId} class="flex gap-1 cursor-pointer whitespace-nowrap select-none">
|
|
72
|
+
<input type="checkbox" id={inputId} name={option.label} bind:checked={option.value} />
|
|
73
|
+
{#if option.icon}
|
|
74
|
+
<img class="w-3" src={option.icon.image.src} alt={option.icon.image.alt} />
|
|
75
|
+
{/if}
|
|
76
|
+
{option.label}
|
|
77
|
+
</label>
|
|
78
|
+
{/each}
|
|
79
|
+
</DisplayOption>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MonitorData, SJVAirEntryLevel } from "@sjvair/sdk";
|
|
2
|
+
export declare function getCurrentLevel(value: string | number, levels: Array<SJVAirEntryLevel>): SJVAirEntryLevel | undefined;
|
|
3
|
+
export declare function getOrder(monitor: MonitorData): number;
|
|
4
|
+
export declare function getTypeShape(type: string): string;
|
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
export function getCurrentLevel(value, levels) {
|
|
2
|
+
value = typeof value === "string" ? parseInt(value, 10) : value;
|
|
3
|
+
return levels.find((lvl) => {
|
|
4
|
+
return value >= lvl.range[0] && value <= lvl.range[1];
|
|
5
|
+
});
|
|
4
6
|
}
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
export function getOrder(monitor) {
|
|
8
|
+
switch (monitor.type) {
|
|
9
|
+
case "airgradient":
|
|
10
|
+
return 5;
|
|
11
|
+
case "airnow":
|
|
12
|
+
return 2;
|
|
13
|
+
case "aqview":
|
|
14
|
+
return 3;
|
|
15
|
+
case "bam1022":
|
|
16
|
+
return 6;
|
|
17
|
+
case "purpleair":
|
|
18
|
+
return monitor.is_sjvair ? 4 : 1;
|
|
19
|
+
default:
|
|
20
|
+
throw new Error(`Map ordering for ${monitor.device} has not been set`);
|
|
21
|
+
}
|
|
14
22
|
}
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
export function getTypeShape(type) {
|
|
24
|
+
switch (type) {
|
|
25
|
+
case "airgradient":
|
|
26
|
+
return "circle";
|
|
27
|
+
case "airnow":
|
|
28
|
+
case "aqview":
|
|
29
|
+
case "bam1022":
|
|
30
|
+
return "triangle";
|
|
31
|
+
case "purpleair":
|
|
32
|
+
return "square";
|
|
33
|
+
default:
|
|
34
|
+
return "circle";
|
|
35
|
+
}
|
|
24
36
|
}
|
|
25
|
-
//#endregion
|
|
26
|
-
export { e as getCurrentLevel, t as getOrder, n as getTypeShape };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { FilterSpecification, MapLayerEventType, Popup } from "@maptiler/sdk";
|
|
2
|
+
import type { SJVAirEntryLevel } from "@sjvair/sdk";
|
|
3
|
+
import { type ClickHandler } from "../map/integrations/click-manager.ts";
|
|
4
|
+
import { TooltipManager } from "../map/integrations/tooltip.svelte.ts";
|
|
5
|
+
import type { MonitorMapFeature } from "./types.ts";
|
|
6
|
+
export declare function monitorTooltip(evt: MapLayerEventType["mousemove"] & object): Popup | void;
|
|
7
|
+
export interface MonitorsClusterContext {
|
|
8
|
+
referenceId: string;
|
|
9
|
+
featuresByType: Record<string, MonitorMapFeature[]>;
|
|
10
|
+
filters: FilterSpecification;
|
|
11
|
+
clusterIconThresholds: SJVAirEntryLevel[];
|
|
12
|
+
beforeLayer?: string;
|
|
13
|
+
tooltipManager: TooltipManager;
|
|
14
|
+
}
|
|
15
|
+
export declare class MonitorsClusterRenderer {
|
|
16
|
+
private ctx;
|
|
17
|
+
private _clusterTypes;
|
|
18
|
+
constructor(ctx: MonitorsClusterContext);
|
|
19
|
+
apply(monitorClickHandler: ClickHandler): void;
|
|
20
|
+
remove(): void;
|
|
21
|
+
get unclusteredLayerIds(): string[];
|
|
22
|
+
syncFeatures(): void;
|
|
23
|
+
syncFilter(): void;
|
|
24
|
+
syncThresholds(): void;
|
|
25
|
+
private makeClusterClickHandler;
|
|
26
|
+
private clusterLayerIds;
|
|
27
|
+
private get clusterTextColorThreshold();
|
|
28
|
+
private clusterTextColorExpr;
|
|
29
|
+
private buildClusterIconExpression;
|
|
30
|
+
private monitorTypeIconsLayer;
|
|
31
|
+
private clusterCountLayer;
|
|
32
|
+
private unclusteredLayer;
|
|
33
|
+
}
|