@sjvair/monitor-map 3.6.2 → 4.0.0
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/README.md +2 -2
- package/dist/lib/MonitorMapLayout.svelte +74 -36
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.d.ts +3 -0
- package/dist/lib/collocation-sites/collocations-map-integration.svelte.js +15 -1
- package/dist/lib/ev-stations/ev-stations-map-integration.svelte.js +27 -6
- package/dist/lib/hms/hms-fire-icon-manager.d.ts +8 -0
- package/dist/lib/hms/hms-fire-icon-manager.js +10 -1
- package/dist/lib/hms/hms-fire-map-integration.svelte.js +1 -1
- package/dist/lib/hms/hms-smoke-map-integration.svelte.d.ts +20 -0
- package/dist/lib/hms/hms-smoke-map-integration.svelte.js +22 -7
- package/dist/lib/index.d.ts +21 -7
- package/dist/lib/index.js +22 -7
- package/dist/lib/legend/Legend.svelte +40 -0
- package/dist/lib/legend/Legend.svelte.d.ts +7 -0
- package/dist/lib/legend/LegendBar.svelte +45 -0
- package/dist/lib/legend/LegendBar.svelte.d.ts +7 -0
- package/dist/lib/legend/legend-data.d.ts +40 -0
- package/dist/lib/legend/legend-data.js +65 -0
- package/dist/lib/map/MapShell.svelte +7 -6
- package/dist/lib/map/MapShell.svelte.d.ts +3 -1
- package/dist/lib/map/basemap.d.ts +14 -0
- package/dist/lib/map/basemap.js +10 -0
- package/dist/lib/map/integrations/map-geojson-integration.svelte.d.ts +6 -0
- package/dist/lib/map/integrations/map-geojson-integration.svelte.js +15 -2
- package/dist/lib/map/integrations/map-layer-integration.svelte.js +7 -3
- package/dist/lib/map/map-style-state.svelte.d.ts +13 -0
- package/dist/lib/map/map-style-state.svelte.js +35 -0
- package/dist/lib/map/map.svelte.d.ts +6 -0
- package/dist/lib/map/map.svelte.js +6 -0
- package/dist/lib/monitors/monitor-groups.d.ts +11 -0
- package/dist/lib/monitors/monitor-groups.js +7 -0
- package/dist/lib/monitors/monitor-utils.js +1 -3
- package/dist/lib/monitors/monitors-icon-manager.svelte.js +2 -5
- package/dist/lib/monitors/monitors-map-integration.svelte.d.ts +4 -4
- package/dist/lib/monitors/monitors-map-integration.svelte.js +43 -30
- package/dist/lib/monitors/monitors.svelte.d.ts +1 -0
- package/dist/lib/monitors/monitors.svelte.js +22 -0
- package/dist/lib/options/OptionsBar.svelte +96 -0
- package/dist/lib/options/OptionsBar.svelte.d.ts +10 -0
- package/dist/lib/options/OptionsGroup.svelte +12 -0
- package/dist/lib/options/OptionsGroup.svelte.d.ts +7 -0
- package/dist/lib/options/OptionsMenu.svelte +71 -0
- package/dist/lib/options/OptionsMenu.svelte.d.ts +15 -0
- package/dist/lib/options/group-state.d.ts +7 -0
- package/dist/lib/options/group-state.js +15 -0
- package/dist/lib/options/layout.d.ts +7 -0
- package/dist/lib/options/layout.js +9 -0
- package/dist/lib/options/map-option-defaults.d.ts +56 -0
- package/dist/lib/options/map-option-defaults.js +47 -0
- package/dist/lib/options/menus/LayersMenu.svelte +47 -0
- package/dist/lib/options/menus/LayersMenu.svelte.d.ts +3 -0
- package/dist/lib/options/menus/MonitorsMenu.svelte +68 -0
- package/dist/lib/options/menus/MonitorsMenu.svelte.d.ts +3 -0
- package/dist/lib/options/menus/OverlaysMenu.svelte +18 -0
- package/dist/lib/{MapLegend.svelte.d.ts → options/menus/OverlaysMenu.svelte.d.ts} +3 -3
- package/dist/lib/options/menus/PollutantMenu.svelte +79 -0
- package/dist/lib/options/menus/PollutantMenu.svelte.d.ts +3 -0
- package/dist/lib/options/menus/SettingsMenu.svelte +73 -0
- package/dist/lib/{hms/components/HMSFireLegend.svelte.d.ts → options/menus/SettingsMenu.svelte.d.ts} +3 -3
- package/dist/lib/options/options-state.svelte.d.ts +12 -0
- package/dist/lib/options/options-state.svelte.js +42 -0
- package/dist/lib/options/pollutant-param.d.ts +17 -0
- package/dist/lib/options/pollutant-param.js +14 -0
- package/dist/lib/options/reset-map-options.d.ts +2 -0
- package/dist/lib/options/reset-map-options.js +24 -0
- package/dist/lib/options/rows/CheckboxRow.svelte +51 -0
- package/dist/lib/options/rows/CheckboxRow.svelte.d.ts +13 -0
- package/dist/lib/options/rows/GroupRow.svelte +43 -0
- package/dist/lib/options/rows/GroupRow.svelte.d.ts +17 -0
- package/dist/lib/options/rows/MarkerIcon.svelte +10 -0
- package/dist/lib/options/rows/MarkerIcon.svelte.d.ts +8 -0
- package/dist/lib/options/rows/RadioRow.svelte +33 -0
- package/dist/lib/options/rows/RadioRow.svelte.d.ts +13 -0
- package/dist/lib/options/rows/SubmenuRow.svelte +22 -0
- package/dist/lib/options/rows/SubmenuRow.svelte.d.ts +11 -0
- package/dist/lib/search/Search.svelte +6 -6
- package/package.json +6 -4
- package/src/lib/MonitorMapLayout.svelte +74 -36
- package/src/lib/collocation-sites/collocations-map-integration.svelte.ts +17 -1
- package/src/lib/ev-stations/ev-stations-map-integration.svelte.ts +26 -6
- package/src/lib/hms/hms-fire-icon-manager.ts +16 -2
- package/src/lib/hms/hms-fire-map-integration.svelte.ts +1 -1
- package/src/lib/hms/hms-smoke-map-integration.svelte.ts +25 -7
- package/src/lib/index.ts +31 -7
- package/src/lib/legend/Legend.svelte +40 -0
- package/src/lib/legend/LegendBar.svelte +45 -0
- package/src/lib/legend/legend-data.ts +101 -0
- package/src/lib/map/MapShell.svelte +7 -6
- package/src/lib/map/basemap.ts +24 -0
- package/src/lib/map/integrations/map-geojson-integration.svelte.ts +15 -2
- package/src/lib/map/integrations/map-layer-integration.svelte.ts +6 -3
- package/src/lib/map/map-style-state.svelte.ts +42 -0
- package/src/lib/map/map.svelte.ts +6 -0
- package/src/lib/monitors/monitor-groups.ts +20 -0
- package/src/lib/monitors/monitor-utils.ts +1 -5
- package/src/lib/monitors/monitors-icon-manager.svelte.ts +2 -8
- package/src/lib/monitors/monitors-map-integration.svelte.ts +37 -27
- package/src/lib/monitors/monitors.svelte.ts +22 -0
- package/src/lib/options/OptionsBar.svelte +96 -0
- package/src/lib/options/OptionsGroup.svelte +12 -0
- package/src/lib/options/OptionsMenu.svelte +71 -0
- package/src/lib/options/group-state.ts +16 -0
- package/src/lib/options/layout.ts +10 -0
- package/src/lib/options/map-option-defaults.ts +71 -0
- package/src/lib/options/menus/LayersMenu.svelte +47 -0
- package/src/lib/options/menus/MonitorsMenu.svelte +68 -0
- package/src/lib/options/menus/OverlaysMenu.svelte +18 -0
- package/src/lib/options/menus/PollutantMenu.svelte +79 -0
- package/src/lib/options/menus/SettingsMenu.svelte +73 -0
- package/src/lib/options/options-state.svelte.ts +48 -0
- package/src/lib/options/pollutant-param.ts +35 -0
- package/src/lib/options/reset-map-options.ts +28 -0
- package/src/lib/options/rows/CheckboxRow.svelte +51 -0
- package/src/lib/options/rows/GroupRow.svelte +43 -0
- package/src/lib/options/rows/MarkerIcon.svelte +10 -0
- package/src/lib/options/rows/RadioRow.svelte +33 -0
- package/src/lib/options/rows/SubmenuRow.svelte +22 -0
- package/src/lib/search/Search.svelte +6 -6
- package/dist/lib/MapLegend.svelte +0 -15
- package/dist/lib/collocation-sites/collocation-utils.d.ts +0 -3
- package/dist/lib/collocation-sites/collocation-utils.js +0 -30
- package/dist/lib/components/DisplayOption.svelte +0 -7
- package/dist/lib/components/DisplayOption.svelte.d.ts +0 -5
- package/dist/lib/components/MapLayersDisplayOptions.svelte +0 -42
- package/dist/lib/components/MapLayersDisplayOptions.svelte.d.ts +0 -18
- package/dist/lib/components/SegmentedControl.svelte +0 -52
- package/dist/lib/components/SegmentedControl.svelte.d.ts +0 -11
- package/dist/lib/components/ToggleSwitch.svelte +0 -93
- package/dist/lib/components/ToggleSwitch.svelte.d.ts +0 -9
- package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte +0 -46
- package/dist/lib/ev-stations/components/EvStationsDisplayOptions.svelte.d.ts +0 -18
- package/dist/lib/hms/components/HMSFireLegend.svelte +0 -21
- package/dist/lib/map/MapStyleDisplayOptions.svelte +0 -61
- package/dist/lib/map/MapStyleDisplayOptions.svelte.d.ts +0 -3
- package/dist/lib/map/Menu.svelte +0 -65
- package/dist/lib/map/Menu.svelte.d.ts +0 -5
- package/dist/lib/monitors/components/MonitorMarkersLegend.svelte +0 -41
- package/dist/lib/monitors/components/MonitorMarkersLegend.svelte.d.ts +0 -3
- package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte +0 -85
- package/dist/lib/monitors/components/MonitorsDisplayOptions.svelte.d.ts +0 -3
- package/src/lib/MapLegend.svelte +0 -15
- package/src/lib/collocation-sites/collocation-utils.ts +0 -41
- package/src/lib/components/DisplayOption.svelte +0 -7
- package/src/lib/components/MapLayersDisplayOptions.svelte +0 -42
- package/src/lib/components/SegmentedControl.svelte +0 -52
- package/src/lib/components/ToggleSwitch.svelte +0 -93
- package/src/lib/ev-stations/components/EvStationsDisplayOptions.svelte +0 -46
- package/src/lib/hms/components/HMSFireLegend.svelte +0 -21
- package/src/lib/map/MapStyleDisplayOptions.svelte +0 -61
- package/src/lib/map/Menu.svelte +0 -65
- package/src/lib/monitors/components/MonitorMarkersLegend.svelte +0 -41
- package/src/lib/monitors/components/MonitorsDisplayOptions.svelte +0 -85
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ContrastIcon, MapIcon, NetworkIcon, RotateCcwIcon, SettingsIcon } from "@lucide/svelte";
|
|
3
|
+
import OptionsMenu from "../OptionsMenu.svelte";
|
|
4
|
+
import CheckboxRow from "../rows/CheckboxRow.svelte";
|
|
5
|
+
import RadioRow from "../rows/RadioRow.svelte";
|
|
6
|
+
import { resetMapOptions } from "../reset-map-options";
|
|
7
|
+
import { MAP_STYLE_OPTIONS } from "../../map/utils";
|
|
8
|
+
import { mapStyleState } from "../../map/map-style-state.svelte.js";
|
|
9
|
+
import { monitorsMapIntegration } from "../../monitors/monitors-map-integration.svelte";
|
|
10
|
+
import { evStationsMapIntegration } from "../../ev-stations/ev-stations-map-integration.svelte";
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<OptionsMenu id="settings" label="Settings" iconOnly alignRight>
|
|
14
|
+
{#snippet icon()}
|
|
15
|
+
<SettingsIcon size={20} color="#696969" />
|
|
16
|
+
{/snippet}
|
|
17
|
+
<CheckboxRow
|
|
18
|
+
label="Marker Clusters"
|
|
19
|
+
bind:checked={
|
|
20
|
+
() => monitorsMapIntegration.clustered && evStationsMapIntegration.clustered,
|
|
21
|
+
(value) => {
|
|
22
|
+
monitorsMapIntegration.clustered = value;
|
|
23
|
+
evStationsMapIntegration.clustered = value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
>
|
|
27
|
+
{#snippet icon()}
|
|
28
|
+
<NetworkIcon size={18} color="#1e90ff" />
|
|
29
|
+
{/snippet}
|
|
30
|
+
</CheckboxRow>
|
|
31
|
+
<hr class="my-1 border-gray-200" />
|
|
32
|
+
<div class="px-3 py-1.5 text-sm">
|
|
33
|
+
<label for="monitor-map-basemap" class="mb-1 flex items-center gap-2 font-semibold">
|
|
34
|
+
<MapIcon size={18} color="#708090" />
|
|
35
|
+
Basemap
|
|
36
|
+
</label>
|
|
37
|
+
<select
|
|
38
|
+
id="monitor-map-basemap"
|
|
39
|
+
class="w-full rounded-md border border-gray-300 bg-white p-1.5"
|
|
40
|
+
bind:value={
|
|
41
|
+
() => mapStyleState.referenceStyle, (style) => mapStyleState.selectReferenceStyle(style)
|
|
42
|
+
}
|
|
43
|
+
>
|
|
44
|
+
{#each MAP_STYLE_OPTIONS as style (style.getId())}
|
|
45
|
+
<option value={style}>{style.getName()}</option>
|
|
46
|
+
{/each}
|
|
47
|
+
</select>
|
|
48
|
+
</div>
|
|
49
|
+
<hr class="my-1 border-gray-200" />
|
|
50
|
+
<p class="flex items-center gap-2 px-3 pt-1.5 text-sm font-semibold">
|
|
51
|
+
<ContrastIcon size={18} color="#708090" />
|
|
52
|
+
Theme
|
|
53
|
+
</p>
|
|
54
|
+
{#each mapStyleState.referenceStyle.getVariants() as variant (variant.getId())}
|
|
55
|
+
<RadioRow
|
|
56
|
+
name="monitor-map-theme"
|
|
57
|
+
label={variant.getName()}
|
|
58
|
+
checked={variant === mapStyleState.variant}
|
|
59
|
+
onselect={() => mapStyleState.selectVariant(variant)}
|
|
60
|
+
/>
|
|
61
|
+
{/each}
|
|
62
|
+
<hr class="my-1 border-gray-200" />
|
|
63
|
+
<div class="px-3 py-1.5">
|
|
64
|
+
<button
|
|
65
|
+
type="button"
|
|
66
|
+
class="flex w-full items-center justify-center gap-2 rounded-md border border-gray-300 px-3 py-1.5 text-sm hover:bg-gray-100"
|
|
67
|
+
onclick={resetMapOptions}
|
|
68
|
+
>
|
|
69
|
+
<RotateCcwIcon size={16} />
|
|
70
|
+
Reset Map Options
|
|
71
|
+
</button>
|
|
72
|
+
</div>
|
|
73
|
+
</OptionsMenu>
|
package/dist/lib/{hms/components/HMSFireLegend.svelte.d.ts → options/menus/SettingsMenu.svelte.d.ts}
RENAMED
|
@@ -11,8 +11,8 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
|
|
|
11
11
|
};
|
|
12
12
|
z_$$bindings?: Bindings;
|
|
13
13
|
}
|
|
14
|
-
declare const
|
|
14
|
+
declare const SettingsMenu: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
15
|
[evt: string]: CustomEvent<any>;
|
|
16
16
|
}, {}, {}, string>;
|
|
17
|
-
type
|
|
18
|
-
export default
|
|
17
|
+
type SettingsMenu = InstanceType<typeof SettingsMenu>;
|
|
18
|
+
export default SettingsMenu;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Which menus are opened by click: at most one on the toolbar, any number in the panel. */
|
|
2
|
+
export declare class OptionsMenusState {
|
|
3
|
+
private open;
|
|
4
|
+
isOpen(id: string): boolean;
|
|
5
|
+
toggle(id: string): void;
|
|
6
|
+
/** Hovering another toolbar trigger closes any dropdown left open by a click. */
|
|
7
|
+
closeOthers(id: string): void;
|
|
8
|
+
close(id: string): void;
|
|
9
|
+
closeAll(): void;
|
|
10
|
+
}
|
|
11
|
+
export declare function provideOptionsMenus(): OptionsMenusState;
|
|
12
|
+
export declare function useOptionsMenus(): OptionsMenusState;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { getContext, setContext } from "svelte";
|
|
2
|
+
import { SvelteSet } from "svelte/reactivity";
|
|
3
|
+
import { isWideLayout } from "./layout";
|
|
4
|
+
const OPTIONS_MENUS_KEY = Symbol("monitor-map-options-menus");
|
|
5
|
+
/** Which menus are opened by click: at most one on the toolbar, any number in the panel. */
|
|
6
|
+
export class OptionsMenusState {
|
|
7
|
+
open = new SvelteSet();
|
|
8
|
+
isOpen(id) {
|
|
9
|
+
return this.open.has(id);
|
|
10
|
+
}
|
|
11
|
+
toggle(id) {
|
|
12
|
+
if (this.open.has(id)) {
|
|
13
|
+
this.open.delete(id);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
if (isWideLayout())
|
|
17
|
+
this.open.clear();
|
|
18
|
+
this.open.add(id);
|
|
19
|
+
}
|
|
20
|
+
/** Hovering another toolbar trigger closes any dropdown left open by a click. */
|
|
21
|
+
closeOthers(id) {
|
|
22
|
+
for (const other of [...this.open]) {
|
|
23
|
+
if (other !== id)
|
|
24
|
+
this.open.delete(other);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
close(id) {
|
|
28
|
+
this.open.delete(id);
|
|
29
|
+
}
|
|
30
|
+
closeAll() {
|
|
31
|
+
this.open.clear();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function provideOptionsMenus() {
|
|
35
|
+
return setContext(OPTIONS_MENUS_KEY, new OptionsMenusState());
|
|
36
|
+
}
|
|
37
|
+
export function useOptionsMenus() {
|
|
38
|
+
const menus = getContext(OPTIONS_MENUS_KEY);
|
|
39
|
+
if (!menus)
|
|
40
|
+
throw new Error("OptionsMenu must be rendered inside OptionsBar");
|
|
41
|
+
return menus;
|
|
42
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { MonitorsPollutant } from "../monitors/types";
|
|
2
|
+
/**
|
|
3
|
+
* What the Pollutant menu shows. "none" is not a monitorsManager.pollutant value — it means
|
|
4
|
+
* the monitors integration is disabled while the manager keeps its last real pollutant.
|
|
5
|
+
*/
|
|
6
|
+
export type PollutantSelection = MonitorsPollutant | "none";
|
|
7
|
+
export interface PollutantTargets {
|
|
8
|
+
manager: {
|
|
9
|
+
pollutant: MonitorsPollutant | null;
|
|
10
|
+
};
|
|
11
|
+
integration: {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export declare function parsePollutantParam(value: unknown): PollutantSelection | null;
|
|
16
|
+
export declare function currentSelection(pollutant: MonitorsPollutant | null, monitorsEnabled: boolean): PollutantSelection | null;
|
|
17
|
+
export declare function applyPollutantSelection(selection: PollutantSelection, targets: PollutantTargets): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function parsePollutantParam(value) {
|
|
2
|
+
return value === "pm25" || value === "o3" || value === "none" ? value : null;
|
|
3
|
+
}
|
|
4
|
+
export function currentSelection(pollutant, monitorsEnabled) {
|
|
5
|
+
return monitorsEnabled ? pollutant : "none";
|
|
6
|
+
}
|
|
7
|
+
export function applyPollutantSelection(selection, targets) {
|
|
8
|
+
if (selection === "none") {
|
|
9
|
+
targets.integration.enabled = false;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
targets.manager.pollutant = selection;
|
|
13
|
+
targets.integration.enabled = true;
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { monitorsManager } from "../monitors/monitors.svelte";
|
|
2
|
+
import { monitorsMapIntegration } from "../monitors/monitors-map-integration.svelte";
|
|
3
|
+
import { collocationSitesMapIntegration } from "../collocation-sites/collocations-map-integration.svelte";
|
|
4
|
+
import { hmsFireMapIntegration } from "../hms/hms-fire-map-integration.svelte";
|
|
5
|
+
import { hmsSmokeMapIntegration } from "../hms/hms-smoke-map-integration.svelte";
|
|
6
|
+
import { evStationsMapIntegration } from "../ev-stations/ev-stations-map-integration.svelte";
|
|
7
|
+
import { windMapIntegration } from "../wind/wind.svelte";
|
|
8
|
+
import { mapStyleState } from "../map/map-style-state.svelte.js";
|
|
9
|
+
import { applyMapOptionDefaults } from "./map-option-defaults";
|
|
10
|
+
/** "Reset Map Options": restores every map option to its default. */
|
|
11
|
+
export function resetMapOptions() {
|
|
12
|
+
applyMapOptionDefaults({
|
|
13
|
+
manager: monitorsManager,
|
|
14
|
+
integration: monitorsMapIntegration,
|
|
15
|
+
collocationSites: collocationSitesMapIntegration,
|
|
16
|
+
hmsFire: hmsFireMapIntegration,
|
|
17
|
+
hmsSmoke: hmsSmokeMapIntegration,
|
|
18
|
+
evStations: evStationsMapIntegration,
|
|
19
|
+
wind: windMapIntegration,
|
|
20
|
+
// The basemap reset may start loading a new style; integrations skip the style while
|
|
21
|
+
// mapManager.styleLoading is set and the refresh on "style.load" re-applies them.
|
|
22
|
+
mapStyle: mapStyleState
|
|
23
|
+
}, monitorsManager.meta?.default_pollutant ?? null);
|
|
24
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import type { Attachment } from "svelte/attachments";
|
|
4
|
+
import { ChevronDownIcon } from "@lucide/svelte";
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
label: string;
|
|
8
|
+
checked: boolean;
|
|
9
|
+
icon?: Snippet;
|
|
10
|
+
indeterminate?: boolean;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
/** When set, shows a chevron reflecting whether this row's children are expanded */
|
|
13
|
+
expanded?: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
let {
|
|
17
|
+
label,
|
|
18
|
+
checked = $bindable(),
|
|
19
|
+
icon,
|
|
20
|
+
indeterminate = false,
|
|
21
|
+
disabled = false,
|
|
22
|
+
expanded
|
|
23
|
+
}: Props = $props();
|
|
24
|
+
|
|
25
|
+
// indeterminate is a DOM property with no HTML attribute; re-runs when the prop changes.
|
|
26
|
+
const syncIndeterminate: Attachment<HTMLInputElement> = (input) => {
|
|
27
|
+
input.indeterminate = indeterminate;
|
|
28
|
+
};
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<label
|
|
32
|
+
class="flex cursor-pointer items-center gap-2 px-3 py-1.5 text-sm whitespace-nowrap select-none hover:bg-gray-100 has-disabled:cursor-not-allowed has-disabled:opacity-50"
|
|
33
|
+
>
|
|
34
|
+
<input
|
|
35
|
+
type="checkbox"
|
|
36
|
+
class="accent-brand size-4 shrink-0"
|
|
37
|
+
bind:checked
|
|
38
|
+
{disabled}
|
|
39
|
+
{@attach syncIndeterminate}
|
|
40
|
+
/>
|
|
41
|
+
{#if icon}
|
|
42
|
+
<span class="flex size-5 shrink-0 items-center justify-center">{@render icon()}</span>
|
|
43
|
+
{/if}
|
|
44
|
+
<span class="flex-1">{label}</span>
|
|
45
|
+
{#if expanded !== undefined}
|
|
46
|
+
<ChevronDownIcon
|
|
47
|
+
size={16}
|
|
48
|
+
class="ml-3 shrink-0 text-gray-500 transition-transform {expanded ? '' : '-rotate-90'}"
|
|
49
|
+
/>
|
|
50
|
+
{/if}
|
|
51
|
+
</label>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
label: string;
|
|
4
|
+
checked: boolean;
|
|
5
|
+
icon?: Snippet;
|
|
6
|
+
indeterminate?: boolean;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
/** When set, shows a chevron reflecting whether this row's children are expanded */
|
|
9
|
+
expanded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
declare const CheckboxRow: import("svelte").Component<Props, {}, "checked">;
|
|
12
|
+
type CheckboxRow = ReturnType<typeof CheckboxRow>;
|
|
13
|
+
export default CheckboxRow;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import CheckboxRow from "./CheckboxRow.svelte";
|
|
4
|
+
import SubmenuRow from "./SubmenuRow.svelte";
|
|
5
|
+
import { groupState, setGroup } from "../group-state";
|
|
6
|
+
|
|
7
|
+
interface GroupOption {
|
|
8
|
+
key: string;
|
|
9
|
+
label: string;
|
|
10
|
+
option: { value: boolean };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface Props {
|
|
14
|
+
label: string;
|
|
15
|
+
/** Only the rows currently visible; hidden rows are never touched by select-all */
|
|
16
|
+
options: Array<GroupOption>;
|
|
17
|
+
icon?: Snippet;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let { label, options, icon }: Props = $props();
|
|
21
|
+
|
|
22
|
+
const status = $derived(groupState(options.map((child) => child.option.value)));
|
|
23
|
+
</script>
|
|
24
|
+
|
|
25
|
+
{#if status !== "empty"}
|
|
26
|
+
<SubmenuRow
|
|
27
|
+
{label}
|
|
28
|
+
{icon}
|
|
29
|
+
indeterminate={status === "indeterminate"}
|
|
30
|
+
bind:checked={
|
|
31
|
+
() => status === "checked",
|
|
32
|
+
(value) =>
|
|
33
|
+
setGroup(
|
|
34
|
+
options.map((child) => child.option),
|
|
35
|
+
value
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
>
|
|
39
|
+
{#each options as child (child.key)}
|
|
40
|
+
<CheckboxRow label={child.label} bind:checked={child.option.value} />
|
|
41
|
+
{/each}
|
|
42
|
+
</SubmenuRow>
|
|
43
|
+
{/if}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface GroupOption {
|
|
3
|
+
key: string;
|
|
4
|
+
label: string;
|
|
5
|
+
option: {
|
|
6
|
+
value: boolean;
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
label: string;
|
|
11
|
+
/** Only the rows currently visible; hidden rows are never touched by select-all */
|
|
12
|
+
options: Array<GroupOption>;
|
|
13
|
+
icon?: Snippet;
|
|
14
|
+
}
|
|
15
|
+
declare const GroupRow: import("svelte").Component<Props, {}, "">;
|
|
16
|
+
type GroupRow = ReturnType<typeof GroupRow>;
|
|
17
|
+
export default GroupRow;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { MapImageIcon } from "../../map/integrations/types";
|
|
3
|
+
|
|
4
|
+
let { icon, class: className = "w-4" }: { icon: MapImageIcon | undefined; class?: string } =
|
|
5
|
+
$props();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
{#if icon}
|
|
9
|
+
<img src={icon.image.src} alt="" class={className} />
|
|
10
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { MapImageIcon } from "../../map/integrations/types";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
icon: MapImageIcon | undefined;
|
|
4
|
+
class?: string;
|
|
5
|
+
};
|
|
6
|
+
declare const MarkerIcon: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type MarkerIcon = ReturnType<typeof MarkerIcon>;
|
|
8
|
+
export default MarkerIcon;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
name: string;
|
|
6
|
+
label: string;
|
|
7
|
+
checked: boolean;
|
|
8
|
+
onselect: () => void;
|
|
9
|
+
unit?: string;
|
|
10
|
+
help?: string;
|
|
11
|
+
icon?: Snippet;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
let { name, label, checked, onselect, unit, help, icon }: Props = $props();
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
<label
|
|
18
|
+
class="flex cursor-pointer flex-col gap-0.5 px-3 py-1.5 text-sm select-none hover:bg-gray-100"
|
|
19
|
+
>
|
|
20
|
+
<span class="flex items-center gap-2 whitespace-nowrap">
|
|
21
|
+
<input type="radio" class="accent-brand size-4 shrink-0" {name} {checked} onchange={onselect} />
|
|
22
|
+
{#if icon}
|
|
23
|
+
<span class="flex size-5 shrink-0 items-center justify-center">{@render icon()}</span>
|
|
24
|
+
{/if}
|
|
25
|
+
<span>
|
|
26
|
+
{label}
|
|
27
|
+
{#if unit}<span class="text-xs text-gray-500">({unit})</span>{/if}
|
|
28
|
+
</span>
|
|
29
|
+
</span>
|
|
30
|
+
{#if help}
|
|
31
|
+
<span class="pl-6 text-xs whitespace-normal text-gray-500">{help}</span>
|
|
32
|
+
{/if}
|
|
33
|
+
</label>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
name: string;
|
|
4
|
+
label: string;
|
|
5
|
+
checked: boolean;
|
|
6
|
+
onselect: () => void;
|
|
7
|
+
unit?: string;
|
|
8
|
+
help?: string;
|
|
9
|
+
icon?: Snippet;
|
|
10
|
+
}
|
|
11
|
+
declare const RadioRow: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type RadioRow = ReturnType<typeof RadioRow>;
|
|
13
|
+
export default RadioRow;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from "svelte";
|
|
3
|
+
import CheckboxRow from "./CheckboxRow.svelte";
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
label: string;
|
|
7
|
+
checked: boolean;
|
|
8
|
+
indeterminate?: boolean;
|
|
9
|
+
icon?: Snippet;
|
|
10
|
+
children: Snippet;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { label, checked = $bindable(), indeterminate = false, icon, children }: Props = $props();
|
|
14
|
+
|
|
15
|
+
// Children show only while the parent is (partly) on, as in the demo.
|
|
16
|
+
const expanded = $derived(checked || indeterminate);
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<CheckboxRow {label} {icon} {indeterminate} {expanded} bind:checked />
|
|
20
|
+
{#if expanded}
|
|
21
|
+
<div class="ml-5 border-l border-gray-200">{@render children()}</div>
|
|
22
|
+
{/if}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from "svelte";
|
|
2
|
+
interface Props {
|
|
3
|
+
label: string;
|
|
4
|
+
checked: boolean;
|
|
5
|
+
indeterminate?: boolean;
|
|
6
|
+
icon?: Snippet;
|
|
7
|
+
children: Snippet;
|
|
8
|
+
}
|
|
9
|
+
declare const SubmenuRow: import("svelte").Component<Props, {}, "checked">;
|
|
10
|
+
type SubmenuRow = ReturnType<typeof SubmenuRow>;
|
|
11
|
+
export default SubmenuRow;
|
|
@@ -111,19 +111,19 @@
|
|
|
111
111
|
|
|
112
112
|
<div
|
|
113
113
|
class={[
|
|
114
|
-
"flex flex-col overflow-hidden bg-white shadow
|
|
115
|
-
collapsed ? "h-
|
|
116
|
-
!collapsed && results.length ? "max-h-90" : "max-h-
|
|
114
|
+
"flex flex-col overflow-hidden bg-white shadow transition-all duration-300 select-none",
|
|
115
|
+
collapsed ? "h-10 w-10 rounded-md" : "w-[min(22.5rem,calc(100vw-5.5rem))] rounded-lg",
|
|
116
|
+
!collapsed && results.length ? "max-h-90" : "max-h-10"
|
|
117
117
|
]}
|
|
118
118
|
use:clickOutside
|
|
119
119
|
>
|
|
120
|
-
<div class="flex h-
|
|
120
|
+
<div class="flex h-10 w-full shrink-0 items-center">
|
|
121
121
|
<button
|
|
122
|
-
class="
|
|
122
|
+
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-md text-gray-700"
|
|
123
123
|
onclick={openSearch}
|
|
124
124
|
aria-label="Open search"
|
|
125
125
|
>
|
|
126
|
-
<SearchIcon size="
|
|
126
|
+
<SearchIcon size="20" />
|
|
127
127
|
</button>
|
|
128
128
|
<div class="flex h-full w-full items-center overflow-hidden">
|
|
129
129
|
<input
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sjvair/monitor-map",
|
|
3
3
|
"description": "SJVAir's interactive monitor map",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/SJVAir/monitor-map"
|
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
16
16
|
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
|
|
17
17
|
"format": "prettier --write .",
|
|
18
|
-
"lint": "prettier --check . && eslint ."
|
|
18
|
+
"lint": "prettier --check . && eslint .",
|
|
19
|
+
"test": "vitest run"
|
|
19
20
|
},
|
|
20
21
|
"type": "module",
|
|
21
22
|
"svelte": "./dist/lib/index.js",
|
|
@@ -65,13 +66,14 @@
|
|
|
65
66
|
"tw-animate-css": "^1.4.0",
|
|
66
67
|
"typescript": "^6.0.3",
|
|
67
68
|
"typescript-eslint": "^8.70.0",
|
|
68
|
-
"vite": "^8.3.0"
|
|
69
|
+
"vite": "^8.3.0",
|
|
70
|
+
"vitest": "^5.0.3"
|
|
69
71
|
},
|
|
70
72
|
"dependencies": {
|
|
71
73
|
"@lucide/svelte": "^1.46.0",
|
|
72
74
|
"@maptiler/sdk": "^4.1.0",
|
|
73
75
|
"@maptiler/weather": "^4.0.1",
|
|
74
|
-
"@sjvair/sdk": "npm:@jsr/sjvair__sdk@^4.
|
|
76
|
+
"@sjvair/sdk": "npm:@jsr/sjvair__sdk@^4.5.0",
|
|
75
77
|
"@tstk/builtin-extensions": "npm:@jsr/tstk__builtin-extensions@^1.0.8",
|
|
76
78
|
"@tstk/utils": "npm:@jsr/tstk__utils@^1.1.2",
|
|
77
79
|
"@turf/area": "^7.4.0",
|