@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.
Files changed (279) hide show
  1. package/dist/lib/LoadScreen.svelte +68 -0
  2. package/dist/lib/LoadScreen.svelte.d.ts +25 -0
  3. package/dist/lib/MainMapView.svelte +1 -0
  4. package/dist/lib/MainMapView.svelte.d.ts +26 -0
  5. package/dist/lib/MapLegend.svelte +15 -0
  6. package/dist/lib/MapLegend.svelte.d.ts +18 -0
  7. package/dist/lib/MonitorDetailPanel.svelte +152 -0
  8. package/dist/lib/MonitorDetailPanel.svelte.d.ts +3 -0
  9. package/dist/lib/MonitorMapLayout.svelte +193 -0
  10. package/dist/lib/MonitorMapLayout.svelte.d.ts +7 -0
  11. package/dist/lib/actions.d.ts +3 -0
  12. package/dist/lib/actions.js +12 -8
  13. package/dist/lib/assets/icons/adjustment-horizontal.svg +3 -0
  14. package/dist/lib/assets/logos/airgradient-blue.svg +63 -0
  15. package/dist/lib/assets/logos/airnow-compact.jpg +0 -0
  16. package/dist/lib/assets/logos/carb-compact.jpg +0 -0
  17. package/dist/lib/assets/logos/purpleair-compact.png +0 -0
  18. package/dist/lib/assets/logos/sjvair-parts/sjvair-air.webp +0 -0
  19. package/dist/lib/assets/logos/sjvair-parts/sjvair-icon.webp +0 -0
  20. package/dist/lib/assets/logos/sjvair-parts/sjvair-sjv.webp +0 -0
  21. package/dist/lib/assets/logos/sjvair-white.svg +115 -0
  22. package/dist/lib/assets/logos/sjvair.svg +96 -0
  23. package/dist/lib/collocation-sites/CollocationTooltip.svelte +98 -0
  24. package/dist/lib/collocation-sites/CollocationTooltip.svelte.d.ts +7 -0
  25. package/dist/lib/collocation-sites/collocation-utils.d.ts +3 -0
  26. package/dist/lib/collocation-sites/collocation-utils.js +30 -0
  27. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.d.ts +7 -0
  28. package/dist/lib/collocation-sites/collocations-icon-manager.svelte.js +17 -20
  29. package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +18 -0
  30. package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +98 -83
  31. package/dist/lib/collocation-sites/collocations.svelte.d.ts +9 -0
  32. package/dist/lib/collocation-sites/collocations.svelte.js +17 -26
  33. package/dist/lib/collocation-sites/types.d.ts +8 -0
  34. package/dist/lib/collocation-sites/types.js +1 -0
  35. package/dist/lib/colors.d.ts +17 -0
  36. package/dist/lib/colors.js +29 -23
  37. package/dist/lib/components/DataBox.svelte +29 -0
  38. package/dist/lib/components/DataBox.svelte.d.ts +9 -0
  39. package/dist/lib/components/DisplayOption.svelte +7 -0
  40. package/dist/lib/components/DisplayOption.svelte.d.ts +5 -0
  41. package/dist/lib/components/MapLayersDisplayOptions.svelte +42 -0
  42. package/dist/lib/components/MapLayersDisplayOptions.svelte.d.ts +18 -0
  43. package/dist/lib/components/SegmentedControl.svelte +61 -0
  44. package/dist/lib/components/SegmentedControl.svelte.d.ts +11 -0
  45. package/dist/lib/components/ToggleSwitch.svelte +93 -0
  46. package/dist/lib/components/ToggleSwitch.svelte.d.ts +9 -0
  47. package/dist/lib/components/ui/button/button.svelte +89 -0
  48. package/dist/lib/components/ui/button/button.svelte.d.ts +70 -0
  49. package/dist/lib/components/ui/button/index.d.ts +2 -0
  50. package/dist/lib/components/ui/button/index.js +4 -0
  51. package/dist/lib/components/ui/range-calendar/index.d.ts +19 -0
  52. package/dist/lib/components/ui/range-calendar/index.js +21 -0
  53. package/dist/lib/components/ui/range-calendar/range-calendar-caption.svelte +76 -0
  54. package/dist/lib/components/ui/range-calendar/range-calendar-caption.svelte.d.ts +19 -0
  55. package/dist/lib/components/ui/range-calendar/range-calendar-cell.svelte +19 -0
  56. package/dist/lib/components/ui/range-calendar/range-calendar-cell.svelte.d.ts +4 -0
  57. package/dist/lib/components/ui/range-calendar/range-calendar-day.svelte +36 -0
  58. package/dist/lib/components/ui/range-calendar/range-calendar-day.svelte.d.ts +4 -0
  59. package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.svelte +7 -0
  60. package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.svelte.d.ts +4 -0
  61. package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.svelte +7 -0
  62. package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.svelte.d.ts +4 -0
  63. package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.svelte +12 -0
  64. package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.svelte.d.ts +4 -0
  65. package/dist/lib/components/ui/range-calendar/range-calendar-grid.svelte +16 -0
  66. package/dist/lib/components/ui/range-calendar/range-calendar-grid.svelte.d.ts +4 -0
  67. package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.svelte +19 -0
  68. package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.svelte.d.ts +4 -0
  69. package/dist/lib/components/ui/range-calendar/range-calendar-header.svelte +19 -0
  70. package/dist/lib/components/ui/range-calendar/range-calendar-header.svelte.d.ts +4 -0
  71. package/dist/lib/components/ui/range-calendar/range-calendar-heading.svelte +16 -0
  72. package/dist/lib/components/ui/range-calendar/range-calendar-heading.svelte.d.ts +4 -0
  73. package/dist/lib/components/ui/range-calendar/range-calendar-month-select.svelte +44 -0
  74. package/dist/lib/components/ui/range-calendar/range-calendar-month-select.svelte.d.ts +4 -0
  75. package/dist/lib/components/ui/range-calendar/range-calendar-month.svelte +15 -0
  76. package/dist/lib/components/ui/range-calendar/range-calendar-month.svelte.d.ts +5 -0
  77. package/dist/lib/components/ui/range-calendar/range-calendar-months.svelte +19 -0
  78. package/dist/lib/components/ui/range-calendar/range-calendar-months.svelte.d.ts +5 -0
  79. package/dist/lib/components/ui/range-calendar/range-calendar-nav.svelte +19 -0
  80. package/dist/lib/components/ui/range-calendar/range-calendar-nav.svelte.d.ts +5 -0
  81. package/dist/lib/components/ui/range-calendar/range-calendar-next-button.svelte +36 -0
  82. package/dist/lib/components/ui/range-calendar/range-calendar-next-button.svelte.d.ts +8 -0
  83. package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.svelte +36 -0
  84. package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.svelte.d.ts +8 -0
  85. package/dist/lib/components/ui/range-calendar/range-calendar-year-select.svelte +43 -0
  86. package/dist/lib/components/ui/range-calendar/range-calendar-year-select.svelte.d.ts +4 -0
  87. package/dist/lib/components/ui/range-calendar/range-calendar.svelte +112 -0
  88. package/dist/lib/components/ui/range-calendar/range-calendar.svelte.d.ts +21 -0
  89. package/dist/lib/data-chart/DataChart.svelte +303 -0
  90. package/dist/lib/data-chart/DataChart.svelte.d.ts +7 -0
  91. package/dist/lib/data-chart/DateRange.d.ts +6 -0
  92. package/dist/lib/data-chart/DateRange.js +15 -14
  93. package/dist/lib/data-chart/chart-utils.d.ts +3 -0
  94. package/dist/lib/data-chart/chart-utils.js +157 -93
  95. package/dist/lib/data-chart/data-chart.svelte.d.ts +7 -0
  96. package/dist/lib/data-chart/data-chart.svelte.js +7 -28
  97. package/dist/lib/data-chart/requests.d.ts +3 -0
  98. package/dist/lib/data-chart/requests.js +36 -28
  99. package/dist/lib/data-chart/tooltip.d.ts +10 -0
  100. package/dist/lib/data-chart/tooltip.js +160 -98
  101. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte +16 -0
  102. package/dist/lib/ev-stations/components/EvStationClusterTooltip.svelte.d.ts +7 -0
  103. package/dist/lib/ev-stations/components/EvStationTooltip.svelte +127 -0
  104. package/dist/lib/ev-stations/components/EvStationTooltip.svelte.d.ts +7 -0
  105. package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte +46 -0
  106. package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte.d.ts +18 -0
  107. package/dist/lib/ev-stations/data-maps.d.ts +5 -0
  108. package/dist/lib/ev-stations/data-maps.js +152 -4
  109. package/dist/lib/ev-stations/ev-station-icons.d.ts +16 -0
  110. package/dist/lib/ev-stations/ev-station-icons.js +21 -27
  111. package/dist/lib/ev-stations/ev-stations-cluster-renderer.d.ts +19 -0
  112. package/dist/lib/ev-stations/ev-stations-cluster-renderer.js +130 -117
  113. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.d.ts +31 -0
  114. package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +206 -180
  115. package/dist/lib/ev-stations/ev-stations.svelte.d.ts +9 -0
  116. package/dist/lib/ev-stations/ev-stations.svelte.js +54 -32
  117. package/dist/lib/ev-stations/types.d.ts +53 -0
  118. package/dist/lib/ev-stations/types.js +1 -0
  119. package/dist/lib/ev-stations/zip-codes.d.ts +13 -0
  120. package/dist/lib/ev-stations/zip-codes.js +457 -135
  121. package/dist/lib/hms/components/HMSFireLegend.svelte +21 -0
  122. package/dist/lib/hms/components/HMSFireLegend.svelte.d.ts +18 -0
  123. package/dist/lib/hms/hms-fire-icon-manager.d.ts +5 -0
  124. package/dist/lib/hms/hms-fire-icon-manager.js +28 -37
  125. package/dist/lib/hms/hms-fire-map-integration.svelte.d.ts +23 -0
  126. package/dist/lib/hms/hms-fire-map-integration.svelte.js +94 -97
  127. package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +19 -0
  128. package/dist/lib/hms/hms-smoke-map-integration.svelte.js +68 -84
  129. package/dist/lib/hms/hms.svelte.d.ts +19 -0
  130. package/dist/lib/hms/hms.svelte.js +225 -76
  131. package/dist/lib/index.d.ts +68 -0
  132. package/dist/lib/index.js +56 -21
  133. package/dist/lib/map/Map.svelte +13 -0
  134. package/dist/lib/map/Map.svelte.d.ts +8 -0
  135. package/dist/lib/map/MapStyleDisplayOptions.svelte +61 -0
  136. package/dist/lib/map/MapStyleDisplayOptions.svelte.d.ts +3 -0
  137. package/dist/lib/map/Menu.svelte +64 -0
  138. package/dist/lib/map/Menu.svelte.d.ts +5 -0
  139. package/dist/lib/map/icons.d.ts +7 -0
  140. package/dist/lib/map/icons.js +24 -22
  141. package/dist/lib/map/integrations/base-layer-seperator.d.ts +9 -0
  142. package/dist/lib/map/integrations/base-layer-seperator.js +11 -12
  143. package/dist/lib/map/integrations/click-manager.d.ts +14 -0
  144. package/dist/lib/map/integrations/click-manager.js +52 -33
  145. package/dist/lib/map/integrations/integrations-manager.d.ts +8 -0
  146. package/dist/lib/map/integrations/integrations-manager.js +20 -12
  147. package/dist/lib/map/integrations/map-display-option.svelte.d.ts +7 -0
  148. package/dist/lib/map/integrations/map-display-option.svelte.js +10 -18
  149. package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +13 -0
  150. package/dist/lib/map/integrations/map-geojson-integration.svelte.js +21 -17
  151. package/dist/lib/map/integrations/map-icon-manager.d.ts +15 -0
  152. package/dist/lib/map/integrations/map-icon-manager.js +52 -46
  153. package/dist/lib/map/integrations/map-integration.svelte.d.ts +6 -0
  154. package/dist/lib/map/integrations/map-integration.svelte.js +2 -5
  155. package/dist/lib/map/integrations/map-layer-integration.svelte.d.ts +11 -0
  156. package/dist/lib/map/integrations/map-layer-integration.svelte.js +36 -23
  157. package/dist/lib/map/integrations/tooltip.svelte.d.ts +28 -0
  158. package/dist/lib/map/integrations/tooltip.svelte.js +120 -78
  159. package/dist/lib/map/integrations/types.d.ts +14 -0
  160. package/dist/lib/map/integrations/types.js +1 -0
  161. package/dist/lib/map/map.svelte.d.ts +14 -0
  162. package/dist/lib/map/map.svelte.js +48 -50
  163. package/dist/lib/map/utils.d.ts +7 -0
  164. package/dist/lib/map/utils.js +32 -29
  165. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte +112 -0
  166. package/dist/lib/monitors/components/MonitorClusterTooltip.svelte.d.ts +7 -0
  167. package/dist/lib/monitors/components/MonitorMarkersLegend.svelte +41 -0
  168. package/dist/lib/monitors/components/MonitorMarkersLegend.svelte.d.ts +3 -0
  169. package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte +128 -0
  170. package/dist/lib/monitors/components/MonitorSubscriptionManager.svelte.d.ts +6 -0
  171. package/dist/lib/monitors/components/MonitorTooltip.svelte +61 -0
  172. package/dist/lib/monitors/components/MonitorTooltip.svelte.d.ts +7 -0
  173. package/dist/lib/monitors/components/MonitorWidgetModal.svelte +100 -0
  174. package/dist/lib/monitors/components/MonitorWidgetModal.svelte.d.ts +6 -0
  175. package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte +79 -0
  176. package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte.d.ts +3 -0
  177. package/dist/lib/monitors/monitor-utils.d.ts +4 -0
  178. package/dist/lib/monitors/monitor-utils.js +33 -23
  179. package/dist/lib/monitors/monitors-cluster-renderer.d.ts +33 -0
  180. package/dist/lib/monitors/monitors-cluster-renderer.js +218 -209
  181. package/dist/lib/monitors/monitors-icon-manager.svelte.d.ts +13 -0
  182. package/dist/lib/monitors/monitors-icon-manager.svelte.js +75 -70
  183. package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +40 -0
  184. package/dist/lib/monitors/monitors-map-integration.svelte.js +278 -270
  185. package/dist/lib/monitors/monitors.svelte.d.ts +16 -0
  186. package/dist/lib/monitors/monitors.svelte.js +38 -63
  187. package/dist/lib/monitors/types.d.ts +26 -0
  188. package/dist/lib/monitors/types.js +1 -0
  189. package/dist/lib/reactivity.svelte.d.ts +0 -0
  190. package/dist/lib/reactivity.svelte.js +83 -0
  191. package/dist/lib/router-context.d.ts +27 -0
  192. package/dist/lib/router-context.js +11 -11
  193. package/dist/lib/routes.d.ts +2 -0
  194. package/dist/lib/routes.js +10 -9
  195. package/dist/lib/search/Search.svelte +189 -0
  196. package/dist/lib/search/Search.svelte.d.ts +3 -0
  197. package/dist/lib/search/service.d.ts +17 -0
  198. package/dist/lib/search/service.js +75 -85
  199. package/dist/lib/utils.d.ts +13 -0
  200. package/dist/lib/utils.js +10 -12
  201. package/dist/lib/weather.d.ts +1 -0
  202. package/dist/lib/weather.js +11 -7
  203. package/dist/lib/wind/wind.svelte.d.ts +10 -0
  204. package/dist/lib/wind/wind.svelte.js +13 -21
  205. package/package.json +9 -7
  206. package/src/lib/LoadScreen.svelte +3 -3
  207. package/src/lib/hms/components/HMSFireLegend.svelte +1 -1
  208. package/src/lib/hms/hms.svelte.ts +8 -9
  209. package/src/lib/index.ts +18 -0
  210. package/src/lib/routes.ts +6 -1
  211. package/src/lib/utils.ts +1 -1
  212. package/dist/lib/LoadScreen.js +0 -73
  213. package/dist/lib/MainMapView.js +0 -7
  214. package/dist/lib/MapLegend.js +0 -13
  215. package/dist/lib/MonitorDetailPanel.js +0 -169
  216. package/dist/lib/MonitorMapLayout.js +0 -91
  217. package/dist/lib/_virtual/_rolldown/runtime.js +0 -11
  218. package/dist/lib/assets/logos/airgradient-blue.js +0 -4
  219. package/dist/lib/assets/logos/airnow-compact.js +0 -4
  220. package/dist/lib/assets/logos/carb-compact.js +0 -4
  221. package/dist/lib/assets/logos/purpleair-compact.js +0 -4
  222. package/dist/lib/assets/logos/sjvair.js +0 -4
  223. package/dist/lib/collocation-sites/CollocationTooltip.js +0 -105
  224. package/dist/lib/components/DataBox.js +0 -30
  225. package/dist/lib/components/DisplayOption.js +0 -10
  226. package/dist/lib/components/MapLayersDisplayOptions.js +0 -87
  227. package/dist/lib/components/SegmentedControl.js +0 -37
  228. package/dist/lib/components/ToggleSwitch.js +0 -17
  229. package/dist/lib/components/ui/button/button.js +0 -34
  230. package/dist/lib/components/ui/range-calendar/range-calendar-caption.js +0 -82
  231. package/dist/lib/components/ui/range-calendar/range-calendar-cell.js +0 -35
  232. package/dist/lib/components/ui/range-calendar/range-calendar-day.js +0 -35
  233. package/dist/lib/components/ui/range-calendar/range-calendar-grid-body.js +0 -27
  234. package/dist/lib/components/ui/range-calendar/range-calendar-grid-head.js +0 -27
  235. package/dist/lib/components/ui/range-calendar/range-calendar-grid-row.js +0 -35
  236. package/dist/lib/components/ui/range-calendar/range-calendar-grid.js +0 -35
  237. package/dist/lib/components/ui/range-calendar/range-calendar-head-cell.js +0 -35
  238. package/dist/lib/components/ui/range-calendar/range-calendar-header.js +0 -35
  239. package/dist/lib/components/ui/range-calendar/range-calendar-month-select.js +0 -61
  240. package/dist/lib/components/ui/range-calendar/range-calendar-month.js +0 -25
  241. package/dist/lib/components/ui/range-calendar/range-calendar-months.js +0 -25
  242. package/dist/lib/components/ui/range-calendar/range-calendar-nav.js +0 -25
  243. package/dist/lib/components/ui/range-calendar/range-calendar-next-button.js +0 -58
  244. package/dist/lib/components/ui/range-calendar/range-calendar-prev-button.js +0 -58
  245. package/dist/lib/components/ui/range-calendar/range-calendar-year-select.js +0 -59
  246. package/dist/lib/components/ui/range-calendar/range-calendar.js +0 -272
  247. package/dist/lib/data-chart/DataChart.js +0 -142
  248. package/dist/lib/ev-stations/components/EvStationClusterTooltip.js +0 -16
  249. package/dist/lib/ev-stations/components/EvStationTooltip.js +0 -120
  250. package/dist/lib/ev-stations/components/EvStationsDisplayOptions.js +0 -41
  251. package/dist/lib/hms/components/HMSFireLegend.js +0 -35
  252. package/dist/lib/map/Map.js +0 -14
  253. package/dist/lib/map/MapStyleDisplayOptions.js +0 -43
  254. package/dist/lib/map/Menu.js +0 -44
  255. package/dist/lib/monitors/components/MonitorClusterTooltip.js +0 -83
  256. package/dist/lib/monitors/components/MonitorMarkersLegend.js +0 -35
  257. package/dist/lib/monitors/components/MonitorSubscriptionManager.js +0 -104
  258. package/dist/lib/monitors/components/MonitorTooltip.js +0 -59
  259. package/dist/lib/monitors/components/MonitorWidgetModal.js +0 -40
  260. package/dist/lib/monitors/components/MonitorsDisplayOptions.js +0 -76
  261. package/dist/lib/search/Search.js +0 -124
  262. package/dist/lib/sjvair-air.avif +0 -0
  263. package/dist/lib/sjvair-air.png +0 -0
  264. package/dist/lib/sjvair-air.webp +0 -0
  265. package/dist/lib/sjvair-air2.avif +0 -0
  266. package/dist/lib/sjvair-air2.png +0 -0
  267. package/dist/lib/sjvair-air2.webp +0 -0
  268. package/dist/lib/sjvair-icon.avif +0 -0
  269. package/dist/lib/sjvair-icon.png +0 -0
  270. package/dist/lib/sjvair-icon.webp +0 -0
  271. package/dist/lib/sjvair-icon2.avif +0 -0
  272. package/dist/lib/sjvair-icon2.png +0 -0
  273. package/dist/lib/sjvair-icon2.webp +0 -0
  274. package/dist/lib/sjvair-sjv.avif +0 -0
  275. package/dist/lib/sjvair-sjv.png +0 -0
  276. package/dist/lib/sjvair-sjv.webp +0 -0
  277. package/dist/lib/sjvair-sjv2.avif +0 -0
  278. package/dist/lib/sjvair-sjv2.png +0 -0
  279. 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,6 @@
1
+ interface MonitorWidgetModalProps {
2
+ monitorId: string;
3
+ }
4
+ declare const MonitorWidgetModal: import("svelte").Component<MonitorWidgetModalProps, {}, "">;
5
+ type MonitorWidgetModal = ReturnType<typeof MonitorWidgetModal>;
6
+ export default MonitorWidgetModal;
@@ -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,3 @@
1
+ declare const MonitorsDisplayOptions: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type MonitorsDisplayOptions = ReturnType<typeof MonitorsDisplayOptions>;
3
+ export default MonitorsDisplayOptions;
@@ -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
- //#region src/lib/monitors/monitor-utils.ts
2
- function e(e, t) {
3
- return e = typeof e == "string" ? parseInt(e, 10) : e, t.find((t) => e >= t.range[0] && e <= t.range[1]);
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 t(e) {
6
- switch (e.type) {
7
- case "airgradient": return 5;
8
- case "airnow": return 2;
9
- case "aqview": return 3;
10
- case "bam1022": return 6;
11
- case "purpleair": return e.is_sjvair ? 4 : 1;
12
- default: throw Error(`Map ordering for ${e.device} has not been set`);
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 n(e) {
16
- switch (e) {
17
- case "airgradient": return "circle";
18
- case "airnow":
19
- case "aqview":
20
- case "bam1022": return "triangle";
21
- case "purpleair": return "square";
22
- default: return "circle";
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
+ }