@smartnet360/svelte-components 0.0.84 → 0.0.86

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 (122) hide show
  1. package/dist/apps/antenna-pattern/components/AntennaControls.svelte +1 -106
  2. package/dist/apps/antenna-pattern/components/AntennaDiagrams.svelte +0 -36
  3. package/dist/apps/antenna-pattern/components/AntennaSettingsModal.svelte +0 -2
  4. package/dist/apps/antenna-pattern/components/PlotlyRadarChart.svelte +0 -22
  5. package/dist/apps/antenna-pattern/components/chart-engines/PolarAreaChart.svelte +0 -2
  6. package/dist/apps/antenna-pattern/components/chart-engines/PolarBarChart.svelte +0 -2
  7. package/dist/apps/antenna-pattern/components/chart-engines/PolarLineChart.svelte +0 -2
  8. package/dist/apps/site-check/SiteCheck.svelte +60 -80
  9. package/dist/apps/site-check/data-loader.d.ts +9 -6
  10. package/dist/apps/site-check/data-loader.js +2 -11
  11. package/dist/apps/site-check/helper.d.ts +3 -2
  12. package/dist/apps/site-check/helper.js +7 -5
  13. package/dist/apps/site-check/index.d.ts +1 -1
  14. package/dist/apps/site-check/transforms.d.ts +4 -2
  15. package/dist/apps/site-check/transforms.js +49 -10
  16. package/dist/core/Charts/GlobalControls.svelte +0 -4
  17. package/dist/core/Desktop/Grid/ResizeHandle.svelte +0 -7
  18. package/dist/core/Desktop/Grid/resizeStore.js +0 -1
  19. package/dist/index.d.ts +1 -0
  20. package/dist/index.js +2 -0
  21. package/dist/map-v2/demo/DemoMap.svelte +0 -2
  22. package/dist/map-v2/demo/demo-cells.js +0 -1
  23. package/dist/map-v2/features/cells/layers/CellsLayer.svelte +7 -26
  24. package/dist/map-v2/features/cells/utils/cellTree.js +0 -29
  25. package/dist/map-v2/features/repeaters/layers/RepeaterLabelsLayer.svelte +3 -27
  26. package/dist/map-v2/features/repeaters/layers/RepeatersLayer.svelte +8 -25
  27. package/dist/map-v2/features/repeaters/utils/repeaterTree.js +0 -6
  28. package/dist/map-v2/features/sites/controls/SiteFilterControl.svelte +0 -8
  29. package/dist/map-v2/features/sites/utils/siteTreeUtils.js +0 -6
  30. package/dist/map-v3/core/components/Map.svelte +89 -0
  31. package/dist/map-v3/core/components/Map.svelte.d.ts +13 -0
  32. package/dist/map-v3/core/controls/FeatureSettingsControl.svelte +103 -0
  33. package/dist/map-v3/core/controls/FeatureSettingsControl.svelte.d.ts +15 -0
  34. package/dist/map-v3/core/controls/MapStyleControl.svelte +271 -0
  35. package/dist/map-v3/core/controls/MapStyleControl.svelte.d.ts +28 -0
  36. package/dist/map-v3/core/index.d.ts +3 -0
  37. package/dist/map-v3/core/index.js +3 -0
  38. package/dist/map-v3/core/stores/map.store.svelte.d.ts +8 -0
  39. package/dist/map-v3/core/stores/map.store.svelte.js +29 -0
  40. package/dist/map-v3/core/stores/viewport.store.svelte.d.ts +38 -0
  41. package/dist/map-v3/core/stores/viewport.store.svelte.js +107 -0
  42. package/dist/map-v3/demo/DemoMap.svelte +104 -0
  43. package/dist/map-v3/demo/DemoMap.svelte.d.ts +6 -0
  44. package/dist/map-v3/demo/demo-cells.d.ts +13 -0
  45. package/dist/map-v3/demo/demo-cells.js +130 -0
  46. package/dist/map-v3/demo/demo-data.d.ts +8 -0
  47. package/dist/map-v3/demo/demo-data.js +104 -0
  48. package/dist/map-v3/demo/demo-repeaters.d.ts +13 -0
  49. package/dist/map-v3/demo/demo-repeaters.js +73 -0
  50. package/dist/map-v3/features/cells/components/CellFilterControl.svelte +208 -0
  51. package/dist/map-v3/features/cells/components/CellFilterControl.svelte.d.ts +12 -0
  52. package/dist/map-v3/features/cells/components/CellSettingsPanel.svelte +229 -0
  53. package/dist/map-v3/features/cells/components/CellSettingsPanel.svelte.d.ts +7 -0
  54. package/dist/map-v3/features/cells/constants.d.ts +18 -0
  55. package/dist/map-v3/features/cells/constants.js +37 -0
  56. package/dist/map-v3/features/cells/layers/CellLabelsLayer.svelte +230 -0
  57. package/dist/map-v3/features/cells/layers/CellLabelsLayer.svelte.d.ts +11 -0
  58. package/dist/map-v3/features/cells/layers/CellsLayer.svelte +194 -0
  59. package/dist/map-v3/features/cells/layers/CellsLayer.svelte.d.ts +11 -0
  60. package/dist/map-v3/features/cells/layers/index.d.ts +2 -0
  61. package/dist/map-v3/features/cells/layers/index.js +2 -0
  62. package/dist/map-v3/features/cells/logic/geometry.d.ts +12 -0
  63. package/dist/map-v3/features/cells/logic/geometry.js +35 -0
  64. package/dist/map-v3/features/cells/logic/grouping.d.ts +18 -0
  65. package/dist/map-v3/features/cells/logic/grouping.js +30 -0
  66. package/dist/map-v3/features/cells/logic/tree-adapter.d.ts +11 -0
  67. package/dist/map-v3/features/cells/logic/tree-adapter.js +53 -0
  68. package/dist/map-v3/features/cells/stores/cell.data.svelte.d.ts +9 -0
  69. package/dist/map-v3/features/cells/stores/cell.data.svelte.js +16 -0
  70. package/dist/map-v3/features/cells/stores/cell.display.svelte.d.ts +25 -0
  71. package/dist/map-v3/features/cells/stores/cell.display.svelte.js +67 -0
  72. package/dist/map-v3/features/cells/stores/cell.registry.svelte.d.ts +23 -0
  73. package/dist/map-v3/features/cells/stores/cell.registry.svelte.js +68 -0
  74. package/dist/map-v3/features/cells/types.d.ts +62 -0
  75. package/dist/map-v3/features/cells/types.js +6 -0
  76. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte +148 -0
  77. package/dist/map-v3/features/repeaters/components/RepeaterFilterControl.svelte.d.ts +12 -0
  78. package/dist/map-v3/features/repeaters/components/RepeaterSettingsPanel.svelte +209 -0
  79. package/dist/map-v3/features/repeaters/components/RepeaterSettingsPanel.svelte.d.ts +7 -0
  80. package/dist/map-v3/features/repeaters/layers/RepeaterLabelsLayer.svelte +177 -0
  81. package/dist/map-v3/features/repeaters/layers/RepeaterLabelsLayer.svelte.d.ts +11 -0
  82. package/dist/map-v3/features/repeaters/layers/RepeatersLayer.svelte +163 -0
  83. package/dist/map-v3/features/repeaters/layers/RepeatersLayer.svelte.d.ts +11 -0
  84. package/dist/map-v3/features/repeaters/logic/geometry.d.ts +3 -0
  85. package/dist/map-v3/features/repeaters/logic/geometry.js +23 -0
  86. package/dist/map-v3/features/repeaters/logic/grouping.d.ts +8 -0
  87. package/dist/map-v3/features/repeaters/logic/grouping.js +20 -0
  88. package/dist/map-v3/features/repeaters/logic/tree-adapter.d.ts +8 -0
  89. package/dist/map-v3/features/repeaters/logic/tree-adapter.js +43 -0
  90. package/dist/map-v3/features/repeaters/stores/repeater.data.svelte.d.ts +8 -0
  91. package/dist/map-v3/features/repeaters/stores/repeater.data.svelte.js +13 -0
  92. package/dist/map-v3/features/repeaters/stores/repeater.display.svelte.d.ts +21 -0
  93. package/dist/map-v3/features/repeaters/stores/repeater.display.svelte.js +64 -0
  94. package/dist/map-v3/features/repeaters/stores/repeater.registry.svelte.d.ts +23 -0
  95. package/dist/map-v3/features/repeaters/stores/repeater.registry.svelte.js +68 -0
  96. package/dist/map-v3/features/repeaters/types.d.ts +18 -0
  97. package/dist/map-v3/features/repeaters/types.js +1 -0
  98. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte +119 -0
  99. package/dist/map-v3/features/sites/components/SiteFilterControl.svelte.d.ts +12 -0
  100. package/dist/map-v3/features/sites/components/SiteSettingsPanel.svelte +241 -0
  101. package/dist/map-v3/features/sites/components/SiteSettingsPanel.svelte.d.ts +7 -0
  102. package/dist/map-v3/features/sites/layers/SiteLabelsLayer.svelte +152 -0
  103. package/dist/map-v3/features/sites/layers/SiteLabelsLayer.svelte.d.ts +11 -0
  104. package/dist/map-v3/features/sites/layers/SitesLayer.svelte +132 -0
  105. package/dist/map-v3/features/sites/layers/SitesLayer.svelte.d.ts +11 -0
  106. package/dist/map-v3/features/sites/logic/tree-adapter.d.ts +9 -0
  107. package/dist/map-v3/features/sites/logic/tree-adapter.js +75 -0
  108. package/dist/map-v3/features/sites/stores/site.data.svelte.d.ts +8 -0
  109. package/dist/map-v3/features/sites/stores/site.data.svelte.js +40 -0
  110. package/dist/map-v3/features/sites/stores/site.display.svelte.d.ts +20 -0
  111. package/dist/map-v3/features/sites/stores/site.display.svelte.js +63 -0
  112. package/dist/map-v3/features/sites/stores/site.registry.svelte.d.ts +13 -0
  113. package/dist/map-v3/features/sites/stores/site.registry.svelte.js +83 -0
  114. package/dist/map-v3/features/sites/types.d.ts +12 -0
  115. package/dist/map-v3/features/sites/types.js +1 -0
  116. package/dist/map-v3/index.d.ts +26 -0
  117. package/dist/map-v3/index.js +31 -0
  118. package/dist/map-v3/shared/controls/MapControl.svelte +242 -0
  119. package/dist/map-v3/shared/controls/MapControl.svelte.d.ts +27 -0
  120. package/dist/map-v3/shared/index.d.ts +1 -0
  121. package/dist/map-v3/shared/index.js +1 -0
  122. package/package.json +1 -1
@@ -0,0 +1,67 @@
1
+ import { browser } from '$app/environment';
2
+ export class CellDisplayStore {
3
+ key = 'map-v3-cell-display';
4
+ // State
5
+ targetPixelSize = $state(50);
6
+ fillOpacity = $state(0.6);
7
+ lineWidth = $state(1);
8
+ showLabels = $state(false);
9
+ // Grouping
10
+ level1 = $state('tech');
11
+ level2 = $state('fband');
12
+ // Label Settings
13
+ labelPixelDistance = $state(60);
14
+ labelFontSize = $state(12);
15
+ labelAzimuthTolerance = $state(10);
16
+ labelColor = $state('#333333');
17
+ labelHaloColor = $state('#ffffff');
18
+ labelHaloWidth = $state(1);
19
+ // Tech-specific label config
20
+ labels2G = $state({ primary: 'cellID', secondary: 'none' });
21
+ labels4G = $state({ primary: 'cellID', secondary: 'dlEarfn' });
22
+ constructor() {
23
+ if (browser) {
24
+ const saved = localStorage.getItem(this.key);
25
+ if (saved) {
26
+ try {
27
+ const parsed = JSON.parse(saved);
28
+ this.targetPixelSize = parsed.targetPixelSize ?? 50;
29
+ this.fillOpacity = parsed.fillOpacity ?? 0.6;
30
+ this.lineWidth = parsed.lineWidth ?? 1;
31
+ this.showLabels = parsed.showLabels ?? false;
32
+ this.level1 = parsed.level1 ?? 'tech';
33
+ this.level2 = parsed.level2 ?? 'fband';
34
+ this.labelPixelDistance = parsed.labelPixelDistance ?? 60;
35
+ this.labelFontSize = parsed.labelFontSize ?? 12;
36
+ this.labelAzimuthTolerance = parsed.labelAzimuthTolerance ?? 10;
37
+ this.labelColor = parsed.labelColor ?? '#333333';
38
+ this.labelHaloColor = parsed.labelHaloColor ?? '#ffffff';
39
+ this.labelHaloWidth = parsed.labelHaloWidth ?? 1;
40
+ this.labels2G = parsed.labels2G ?? { primary: 'cellID', secondary: 'none' };
41
+ this.labels4G = parsed.labels4G ?? { primary: 'cellID', secondary: 'dlEarfn' };
42
+ }
43
+ catch (e) {
44
+ console.error('Failed to load cell display settings', e);
45
+ }
46
+ }
47
+ $effect(() => {
48
+ localStorage.setItem(this.key, JSON.stringify({
49
+ targetPixelSize: this.targetPixelSize,
50
+ fillOpacity: this.fillOpacity,
51
+ lineWidth: this.lineWidth,
52
+ showLabels: this.showLabels,
53
+ level1: this.level1,
54
+ level2: this.level2,
55
+ labelPixelDistance: this.labelPixelDistance,
56
+ labelFontSize: this.labelFontSize,
57
+ labelAzimuthTolerance: this.labelAzimuthTolerance,
58
+ labelColor: this.labelColor,
59
+ labelHaloColor: this.labelHaloColor,
60
+ labelHaloWidth: this.labelHaloWidth,
61
+ labels2G: this.labels2G,
62
+ labels4G: this.labels4G
63
+ }));
64
+ });
65
+ }
66
+ }
67
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Persistent store for cell styling (colors, visibility)
3
+ * Key: Stable Group ID (e.g. "4G__LTE700")
4
+ * Value: { color: string, visible: boolean }
5
+ */
6
+ export declare class CellRegistry {
7
+ state: Record<string, {
8
+ color: string;
9
+ visible: boolean;
10
+ }>;
11
+ version: number;
12
+ namespace: string;
13
+ constructor(namespace?: string);
14
+ load(): void;
15
+ save(): void;
16
+ getStyle(id: string, defaultColor: string): {
17
+ color: string;
18
+ visible: boolean;
19
+ };
20
+ toggleVisibility(id: string): void;
21
+ setColor(id: string, color: string): void;
22
+ }
23
+ export declare function createCellRegistry(namespace: string): CellRegistry;
@@ -0,0 +1,68 @@
1
+ import { writable } from 'svelte/store';
2
+ /**
3
+ * Persistent store for cell styling (colors, visibility)
4
+ * Key: Stable Group ID (e.g. "4G__LTE700")
5
+ * Value: { color: string, visible: boolean }
6
+ */
7
+ export class CellRegistry {
8
+ state = $state({});
9
+ version = $state(0); // Signal for reactivity
10
+ namespace;
11
+ constructor(namespace = 'default') {
12
+ this.namespace = namespace;
13
+ this.load();
14
+ $effect(() => {
15
+ this.save();
16
+ });
17
+ }
18
+ load() {
19
+ if (typeof window === 'undefined')
20
+ return;
21
+ try {
22
+ const stored = localStorage.getItem(`${this.namespace}:cell-registry`);
23
+ if (stored) {
24
+ this.state = JSON.parse(stored);
25
+ this.version++;
26
+ }
27
+ }
28
+ catch (e) {
29
+ console.warn('Failed to load cell registry', e);
30
+ }
31
+ }
32
+ save() {
33
+ if (typeof window === 'undefined')
34
+ return;
35
+ try {
36
+ localStorage.setItem(`${this.namespace}:cell-registry`, JSON.stringify(this.state));
37
+ }
38
+ catch (e) {
39
+ console.warn('Failed to save cell registry', e);
40
+ }
41
+ }
42
+ getStyle(id, defaultColor) {
43
+ if (!this.state[id]) {
44
+ // Initialize if missing
45
+ this.state[id] = { color: defaultColor, visible: true };
46
+ // No version bump here to avoid loops during render
47
+ }
48
+ return this.state[id];
49
+ }
50
+ toggleVisibility(id) {
51
+ if (this.state[id]) {
52
+ this.state[id].visible = !this.state[id].visible;
53
+ this.version++;
54
+ }
55
+ else {
56
+ console.warn(`[CellRegistry] Tried to toggle missing ID: ${id}`);
57
+ }
58
+ }
59
+ setColor(id, color) {
60
+ if (this.state[id]) {
61
+ this.state[id].color = color;
62
+ this.version++;
63
+ }
64
+ }
65
+ }
66
+ export function createCellRegistry(namespace) {
67
+ return new CellRegistry(namespace);
68
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Cell Feature - Type Definitions
3
+ *
4
+ * Core interfaces and types for cellular network visualization
5
+ */
6
+ /**
7
+ * Cell data model - represents a radio cell/sector
8
+ */
9
+ export interface Cell {
10
+ id: string;
11
+ txId: string;
12
+ cellID: string;
13
+ cellID2G: string;
14
+ cellName: string;
15
+ siteId: string;
16
+ tech: string;
17
+ fband: string;
18
+ frq: string;
19
+ type: string;
20
+ status: string;
21
+ onAirDate: string;
22
+ bcch: number;
23
+ ctrlid: string;
24
+ dlEarfn: number;
25
+ antenna: string;
26
+ azimuth: number;
27
+ height: number;
28
+ electricalTilt: string;
29
+ beamwidth: number;
30
+ latitude: number;
31
+ longitude: number;
32
+ dx: number;
33
+ dy: number;
34
+ siteLatitude: number;
35
+ siteLongitude: number;
36
+ comment: string;
37
+ planner: string;
38
+ atollETP: number;
39
+ atollPW: number;
40
+ atollRS: number;
41
+ atollBW: number;
42
+ cellId3: string;
43
+ nwtP1: number;
44
+ nwtP2: number;
45
+ pci1: number;
46
+ nwtRS: number;
47
+ nwtBW: number;
48
+ other?: Record<string, any>;
49
+ customSubgroup: string;
50
+ }
51
+ /**
52
+ * Supported cell sector status values
53
+ */
54
+ export type CellStatus = 'On_Air' | 'On_Air_UNDER_CONSTRUCTION' | 'On_Air_Locked' | 'RF_Plan_Ready' | 'Re-Planned_RF_Plan_Ready' | 'Tavlati_RF_Plan_Ready';
55
+ /**
56
+ * Technology-Band combination key
57
+ */
58
+ export type TechnologyBandKey = string;
59
+ /**
60
+ * Grouping fields for Tree View
61
+ */
62
+ export type CellGroupingField = 'tech' | 'fband' | 'frq' | 'status' | 'siteId' | 'none';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Cell Feature - Type Definitions
3
+ *
4
+ * Core interfaces and types for cellular network visualization
5
+ */
6
+ export {};
@@ -0,0 +1,148 @@
1
+ <script lang="ts">
2
+ import { onDestroy, untrack } from 'svelte';
3
+ import { MapControl } from '../../../shared';
4
+ import { createTreeStore } from '../../../../core/TreeView/tree.store';
5
+ import TreeView from '../../../../core/TreeView/TreeView.svelte';
6
+ import type { RepeaterDataStore } from '../stores/repeater.data.svelte';
7
+ import type { RepeaterRegistry } from '../stores/repeater.registry.svelte';
8
+ import type { RepeaterDisplayStore } from '../stores/repeater.display.svelte';
9
+ import type { RepeaterGroupingField } from '../types';
10
+ import { buildRepeaterTree } from '../logic/tree-adapter';
11
+
12
+ interface Props {
13
+ dataStore: RepeaterDataStore;
14
+ registry: RepeaterRegistry;
15
+ displayStore: RepeaterDisplayStore;
16
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
17
+ }
18
+
19
+ let { dataStore, registry, displayStore, position = 'top-left' }: Props = $props();
20
+
21
+ const level1Options: RepeaterGroupingField[] = ['tech', 'provider', 'featureGroup'];
22
+ const level2Options: RepeaterGroupingField[] = ['fband', 'provider', 'featureGroup', 'none'];
23
+
24
+ let treeStore = $derived.by(() => {
25
+ const _repeaters = dataStore.filteredRepeaters;
26
+ const _l1 = displayStore.level1;
27
+ const _l2 = displayStore.level2;
28
+
29
+ return untrack(() => {
30
+ const nodes = buildRepeaterTree(_repeaters, registry, _l1, _l2);
31
+ return createTreeStore({
32
+ nodes,
33
+ namespace: `${registry.namespace}:repeater-tree:${_l1}:${_l2}`,
34
+ persistState: true,
35
+ defaultExpandAll: true
36
+ });
37
+ });
38
+ });
39
+
40
+ $effect(() => {
41
+ const unsubscribe = treeStore.subscribe((val) => {
42
+ let changes = 0;
43
+ val.state.nodes.forEach((nodeState) => {
44
+ if (nodeState.node.children && nodeState.node.children.length > 0) return;
45
+
46
+ const groupId = nodeState.node.id;
47
+ const isVisible = val.state.checkedPaths.has(nodeState.path);
48
+
49
+ const currentStyle = registry.getStyle(groupId, '#000');
50
+ if (currentStyle.visible !== isVisible) {
51
+ registry.toggleVisibility(groupId);
52
+ changes++;
53
+ }
54
+ });
55
+ });
56
+
57
+ return () => {
58
+ unsubscribe();
59
+ };
60
+ });
61
+
62
+ function handleColorChange(groupId: string, event: Event) {
63
+ const input = event.target as HTMLInputElement;
64
+ registry.setColor(groupId, input.value);
65
+ }
66
+
67
+ function getFieldLabel(field: string): string {
68
+ const labels: Record<string, string> = {
69
+ tech: 'Technology',
70
+ fband: 'Tech + Band',
71
+ provider: 'Provider',
72
+ featureGroup: 'Feature Group',
73
+ none: 'None'
74
+ };
75
+ return labels[field] || field;
76
+ }
77
+ </script>
78
+
79
+ <MapControl {position} title="Repeaters" icon="router" controlWidth="320px">
80
+ <div class="card shadow-sm border-0">
81
+ <!-- <div class="card-header bg-white py-2 d-flex justify-content-between align-items-center">
82
+ <h6 class="mb-0 fw-bold text-primary">
83
+ <i class="bi bi-broadcast me-2"></i>Repeaters
84
+ </h6>
85
+ <span class="badge bg-light text-dark border">
86
+ {dataStore.filteredRepeaters.length}
87
+ </span>
88
+ </div> -->
89
+
90
+ <div class="card-body p-2 bg-light border-bottom">
91
+ <div class="row g-2">
92
+ <div class="col-6">
93
+ <label class="form-label x-small text-muted text-uppercase mb-1">Group By</label>
94
+ <select class="form-select form-select-sm" bind:value={displayStore.level1}>
95
+ {#each level1Options as opt}
96
+ <option value={opt}>{getFieldLabel(opt)}</option>
97
+ {/each}
98
+ </select>
99
+ </div>
100
+ <div class="col-6">
101
+ <label class="form-label x-small text-muted text-uppercase mb-1">Then By</label>
102
+ <select class="form-select form-select-sm" bind:value={displayStore.level2}>
103
+ {#each level2Options as opt}
104
+ <option value={opt}>{getFieldLabel(opt)}</option>
105
+ {/each}
106
+ </select>
107
+ </div>
108
+ </div>
109
+ </div>
110
+
111
+ <div class="card-body p-0 overflow-auto" style="max-height: 400px;">
112
+ <div class="p-2">
113
+ <TreeView showControls={false} store={$treeStore}>
114
+ {#snippet children({ node })}
115
+ <div class="d-flex align-items-center justify-content-between w-100">
116
+
117
+
118
+ {#if !node.children || node.children.length === 0}
119
+ <div
120
+ class="d-flex align-items-center"
121
+ role="group"
122
+ onclick={(e) => e.stopPropagation()}
123
+ onkeydown={(e) => e.stopPropagation()}
124
+ >
125
+ <input
126
+ type="color"
127
+ class="form-control form-control-color form-control-sm border-0 p-0"
128
+ style="width: 16px; height: 16px; min-height: 0;"
129
+ value={node.metadata?.color}
130
+ oninput={(e) => handleColorChange(node.id, e)}
131
+ title="Change color"
132
+ />
133
+ </div>
134
+ {/if}
135
+ </div>
136
+ {/snippet}
137
+ </TreeView>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ </MapControl>
142
+
143
+ <style>
144
+ .x-small {
145
+ font-size: 0.7rem;
146
+ letter-spacing: 0.5px;
147
+ }
148
+ </style>
@@ -0,0 +1,12 @@
1
+ import type { RepeaterDataStore } from '../stores/repeater.data.svelte';
2
+ import type { RepeaterRegistry } from '../stores/repeater.registry.svelte';
3
+ import type { RepeaterDisplayStore } from '../stores/repeater.display.svelte';
4
+ interface Props {
5
+ dataStore: RepeaterDataStore;
6
+ registry: RepeaterRegistry;
7
+ displayStore: RepeaterDisplayStore;
8
+ position?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
9
+ }
10
+ declare const RepeaterFilterControl: import("svelte").Component<Props, {}, "">;
11
+ type RepeaterFilterControl = ReturnType<typeof RepeaterFilterControl>;
12
+ export default RepeaterFilterControl;
@@ -0,0 +1,209 @@
1
+ <script lang="ts">
2
+ import type { RepeaterDisplayStore } from '../stores/repeater.display.svelte';
3
+
4
+ interface Props {
5
+ displayStore: RepeaterDisplayStore;
6
+ }
7
+
8
+ let { displayStore }: Props = $props();
9
+ </script>
10
+
11
+ <div class="card border-0 shadow-sm rounded-2">
12
+ <div class="card-body bg-light p-3">
13
+ <!-- Target Pixel Size (Radius) -->
14
+ <div class="row align-items-center g-2 mb-3">
15
+ <div class="col-4 text-secondary fw-semibold small text-uppercase">Pixel Size</div>
16
+ <div class="col-3 text-end">
17
+ <span class="badge bg-white text-muted border">{displayStore.targetPixelSize}px</span>
18
+ </div>
19
+ <div class="col-5">
20
+ <input
21
+ id="repeater-radius-slider"
22
+ type="range"
23
+ class="form-range w-100"
24
+ min="10"
25
+ max="200"
26
+ step="5"
27
+ bind:value={displayStore.targetPixelSize}
28
+ />
29
+ </div>
30
+ </div>
31
+
32
+ <!-- Line Width -->
33
+ <div class="row align-items-center g-2 mb-3">
34
+ <div class="col-4 text-secondary fw-semibold small text-uppercase">Line Width</div>
35
+ <div class="col-3 text-end">
36
+ <span class="badge bg-white text-muted border">{displayStore.lineWidth}px</span>
37
+ </div>
38
+ <div class="col-5">
39
+ <input
40
+ id="repeater-line-width-slider"
41
+ type="range"
42
+ class="form-range w-100"
43
+ min="0.5"
44
+ max="5"
45
+ step="0.5"
46
+ bind:value={displayStore.lineWidth}
47
+ />
48
+ </div>
49
+ </div>
50
+
51
+ <!-- Fill Opacity -->
52
+ <div class="row align-items-center g-2 mb-3">
53
+ <div class="col-4 text-secondary fw-semibold small text-uppercase">Fill Opacity</div>
54
+ <div class="col-3 text-end">
55
+ <span class="badge bg-white text-muted border">{Math.round(displayStore.fillOpacity * 100)}%</span>
56
+ </div>
57
+ <div class="col-5">
58
+ <input
59
+ id="repeater-opacity-slider"
60
+ type="range"
61
+ class="form-range w-100"
62
+ min="0"
63
+ max="1"
64
+ step="0.1"
65
+ bind:value={displayStore.fillOpacity}
66
+ />
67
+ </div>
68
+ </div>
69
+
70
+ <div class="border-top my-3"></div>
71
+
72
+ <!-- Show Labels -->
73
+ <div class="row align-items-center g-2 mb-3">
74
+ <div class="col-4 text-secondary fw-semibold small text-uppercase">Show Labels</div>
75
+ <div class="col-3"></div>
76
+ <div class="col-5">
77
+ <div class="form-check form-switch m-0 d-flex align-items-center justify-content-end">
78
+ <input
79
+ id="repeater-labels-toggle"
80
+ type="checkbox"
81
+ class="form-check-input"
82
+ role="switch"
83
+ bind:checked={displayStore.showLabels}
84
+ />
85
+ </div>
86
+ </div>
87
+ </div>
88
+
89
+ {#if displayStore.showLabels}
90
+ <div class="ps-3 border-start border-2 mb-3">
91
+ <!-- Labels Config -->
92
+ <div class="mb-2">
93
+ <div class="text-secondary fw-semibold small text-uppercase mb-1">Label Fields</div>
94
+ <div class="row g-1">
95
+ <div class="col-6">
96
+ <select class="form-select form-select-sm" bind:value={displayStore.labels.primary}>
97
+ <option value="repeaterId">ID</option>
98
+ <option value="tech">Tech</option>
99
+ <option value="fband">Band</option>
100
+ <option value="provider">Provider</option>
101
+ </select>
102
+ </div>
103
+ <div class="col-6">
104
+ <select class="form-select form-select-sm" bind:value={displayStore.labels.secondary}>
105
+ <option value="none">None</option>
106
+ <option value="repeaterId">ID</option>
107
+ <option value="tech">Tech</option>
108
+ <option value="fband">Band</option>
109
+ <option value="provider">Provider</option>
110
+ </select>
111
+ </div>
112
+ </div>
113
+ </div>
114
+
115
+ <!-- Label Settings -->
116
+ <div class="mt-3">
117
+ <!-- Label Distance -->
118
+ <div class="row align-items-center g-2 mb-2">
119
+ <div class="col-4 text-secondary small">Distance</div>
120
+ <div class="col-3 text-end">
121
+ <span class="badge bg-white text-muted border">{displayStore.labelPixelDistance}px</span>
122
+ </div>
123
+ <div class="col-5">
124
+ <input
125
+ type="range"
126
+ class="form-range w-100"
127
+ min="20"
128
+ max="150"
129
+ step="5"
130
+ bind:value={displayStore.labelPixelDistance}
131
+ />
132
+ </div>
133
+ </div>
134
+
135
+ <!-- Font Size -->
136
+ <div class="row align-items-center g-2 mb-3">
137
+ <div class="col-4 text-secondary small">Font Size</div>
138
+ <div class="col-3 text-end">
139
+ <span class="badge bg-white text-muted border">{displayStore.labelFontSize}px</span>
140
+ </div>
141
+ <div class="col-5">
142
+ <input
143
+ type="range"
144
+ class="form-range w-100"
145
+ min="8"
146
+ max="24"
147
+ step="1"
148
+ bind:value={displayStore.labelFontSize}
149
+ />
150
+ </div>
151
+ </div>
152
+
153
+ <!-- Label Colors -->
154
+ <div class="row align-items-center g-2 mb-2">
155
+ <div class="col-4 text-secondary small">Color</div>
156
+ <div class="col-8">
157
+ <div class="input-group input-group-sm">
158
+ <input
159
+ type="color"
160
+ class="form-control form-control-color"
161
+ bind:value={displayStore.labelColor}
162
+ title="Label Color"
163
+ />
164
+ <span class="input-group-text bg-white text-muted small flex-grow-1 font-monospace">
165
+ {displayStore.labelColor}
166
+ </span>
167
+ </div>
168
+ </div>
169
+ </div>
170
+
171
+ <!-- Halo Settings -->
172
+ <div class="row align-items-center g-2 mb-2">
173
+ <div class="col-4 text-secondary small">Halo</div>
174
+ <div class="col-8">
175
+ <div class="input-group input-group-sm">
176
+ <input
177
+ type="color"
178
+ class="form-control form-control-color"
179
+ bind:value={displayStore.labelHaloColor}
180
+ title="Halo Color"
181
+ />
182
+ <span class="input-group-text bg-white text-muted small flex-grow-1 font-monospace">
183
+ {displayStore.labelHaloColor}
184
+ </span>
185
+ </div>
186
+ </div>
187
+ </div>
188
+
189
+ <div class="row align-items-center g-2 mb-3">
190
+ <div class="col-4 text-secondary small">Halo Width</div>
191
+ <div class="col-3 text-end">
192
+ <span class="badge bg-white text-muted border">{displayStore.labelHaloWidth}px</span>
193
+ </div>
194
+ <div class="col-5">
195
+ <input
196
+ type="range"
197
+ class="form-range w-100"
198
+ min="0"
199
+ max="5"
200
+ step="0.5"
201
+ bind:value={displayStore.labelHaloWidth}
202
+ />
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ {/if}
208
+ </div>
209
+ </div>
@@ -0,0 +1,7 @@
1
+ import type { RepeaterDisplayStore } from '../stores/repeater.display.svelte';
2
+ interface Props {
3
+ displayStore: RepeaterDisplayStore;
4
+ }
5
+ declare const RepeaterSettingsPanel: import("svelte").Component<Props, {}, "">;
6
+ type RepeaterSettingsPanel = ReturnType<typeof RepeaterSettingsPanel>;
7
+ export default RepeaterSettingsPanel;