@versatiles/svelte 1.0.1 → 1.0.2

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 (78) hide show
  1. package/dist/components/BBoxMap/AutoComplete.svelte +116 -89
  2. package/dist/components/BBoxMap/BBoxMap.svelte +50 -40
  3. package/dist/components/BasicMap/BasicMap.svelte +59 -34
  4. package/dist/components/LocatorMap/LocatorMap.svelte +67 -60
  5. package/dist/components/MapEditor/MapEditor.svelte +35 -80
  6. package/dist/components/MapEditor/components/Editor.svelte +53 -0
  7. package/dist/components/MapEditor/{Editor.svelte.d.ts → components/Editor.svelte.d.ts} +1 -1
  8. package/dist/components/MapEditor/components/EditorFill.svelte +28 -0
  9. package/dist/components/MapEditor/components/EditorFill.svelte.d.ts +7 -0
  10. package/dist/components/MapEditor/components/EditorStroke.svelte +28 -0
  11. package/dist/components/MapEditor/components/EditorStroke.svelte.d.ts +7 -0
  12. package/dist/components/MapEditor/components/EditorSymbol.svelte +43 -0
  13. package/dist/components/MapEditor/components/EditorSymbol.svelte.d.ts +7 -0
  14. package/dist/components/MapEditor/components/Sidebar.svelte +179 -0
  15. package/dist/components/MapEditor/components/Sidebar.svelte.d.ts +8 -0
  16. package/dist/components/MapEditor/components/SymbolSelector.svelte +118 -0
  17. package/dist/components/MapEditor/components/SymbolSelector.svelte.d.ts +8 -0
  18. package/dist/components/MapEditor/lib/__mocks__/cursor.d.ts +5 -0
  19. package/dist/components/MapEditor/lib/__mocks__/cursor.js +6 -0
  20. package/dist/components/MapEditor/lib/__mocks__/geometry_manager.d.ts +22 -0
  21. package/dist/components/MapEditor/lib/__mocks__/geometry_manager.js +21 -0
  22. package/dist/components/MapEditor/lib/__mocks__/map.d.ts +36 -0
  23. package/dist/components/MapEditor/lib/__mocks__/map.js +26 -0
  24. package/dist/components/MapEditor/lib/cursor.d.ts +9 -0
  25. package/dist/components/MapEditor/lib/cursor.js +31 -0
  26. package/dist/components/MapEditor/lib/element/abstract.d.ts +21 -0
  27. package/dist/components/MapEditor/lib/element/abstract.js +39 -0
  28. package/dist/components/MapEditor/lib/element/abstract_path.d.ts +11 -0
  29. package/dist/components/MapEditor/lib/element/abstract_path.js +79 -0
  30. package/dist/components/MapEditor/lib/element/line.d.ts +16 -0
  31. package/dist/components/MapEditor/lib/element/line.js +53 -0
  32. package/dist/components/MapEditor/lib/element/marker.d.ts +18 -0
  33. package/dist/components/MapEditor/lib/element/marker.js +62 -0
  34. package/dist/components/MapEditor/lib/element/polygon.d.ts +17 -0
  35. package/dist/components/MapEditor/lib/element/polygon.js +63 -0
  36. package/dist/components/MapEditor/lib/element/types.d.ts +11 -0
  37. package/dist/components/MapEditor/lib/geometry_manager.d.ts +20 -10
  38. package/dist/components/MapEditor/lib/geometry_manager.js +158 -57
  39. package/dist/components/MapEditor/lib/map_layer/abstract.d.ts +30 -0
  40. package/dist/components/MapEditor/lib/map_layer/abstract.js +90 -0
  41. package/dist/components/MapEditor/lib/map_layer/fill.d.ts +24 -0
  42. package/dist/components/MapEditor/lib/map_layer/fill.js +104 -0
  43. package/dist/components/MapEditor/lib/map_layer/line.d.ts +20 -0
  44. package/dist/components/MapEditor/lib/map_layer/line.js +90 -0
  45. package/dist/components/MapEditor/lib/map_layer/symbol.d.ts +19 -0
  46. package/dist/components/MapEditor/lib/map_layer/symbol.js +123 -0
  47. package/dist/components/MapEditor/lib/{types.d.ts → map_layer/types.d.ts} +7 -15
  48. package/dist/components/MapEditor/lib/map_layer/types.js +1 -0
  49. package/dist/components/MapEditor/lib/state/reader.d.ts +17 -0
  50. package/dist/components/MapEditor/lib/state/reader.js +161 -0
  51. package/dist/components/MapEditor/lib/state/types.d.ts +20 -0
  52. package/dist/components/MapEditor/lib/state/types.js +1 -0
  53. package/dist/components/MapEditor/lib/state/writer.d.ts +17 -0
  54. package/dist/components/MapEditor/lib/state/writer.js +178 -0
  55. package/dist/components/MapEditor/lib/symbols.d.ts +16 -0
  56. package/dist/components/MapEditor/lib/symbols.js +173 -0
  57. package/dist/components/MapEditor/lib/utils.d.ts +8 -1
  58. package/dist/components/MapEditor/lib/utils.js +33 -2
  59. package/dist/utils/draw/bbox.d.ts +1 -0
  60. package/dist/utils/draw/bbox.js +1 -1
  61. package/package.json +17 -17
  62. package/dist/components/MapEditor/Editor.svelte +0 -25
  63. package/dist/components/MapEditor/EditorLine.svelte +0 -27
  64. package/dist/components/MapEditor/EditorLine.svelte.d.ts +0 -7
  65. package/dist/components/MapEditor/EditorMarker.svelte +0 -42
  66. package/dist/components/MapEditor/EditorMarker.svelte.d.ts +0 -7
  67. package/dist/components/MapEditor/editor.scss +0 -16
  68. package/dist/components/MapEditor/lib/element_abstract.d.ts +0 -20
  69. package/dist/components/MapEditor/lib/element_abstract.js +0 -58
  70. package/dist/components/MapEditor/lib/element_line.d.ts +0 -14
  71. package/dist/components/MapEditor/lib/element_line.js +0 -76
  72. package/dist/components/MapEditor/lib/element_marker.d.ts +0 -20
  73. package/dist/components/MapEditor/lib/element_marker.js +0 -191
  74. package/dist/components/MapEditor/lib/map_layer.d.ts +0 -14
  75. package/dist/components/MapEditor/lib/map_layer.js +0 -61
  76. package/dist/utils/sprite_library.d.ts +0 -19
  77. package/dist/utils/sprite_library.js +0 -30
  78. /package/dist/components/MapEditor/lib/{types.js → element/types.js} +0 -0
@@ -1,27 +1,28 @@
1
- <script lang="ts">import 'maplibre-gl/dist/maplibre-gl.css';
2
- import BasicMap from '../BasicMap/BasicMap.svelte';
3
- import Editor from './Editor.svelte';
4
- import { GeometryManager } from './lib/geometry_manager.js';
5
- import { onMount } from 'svelte';
6
- let showSidebar = $state(false);
7
- onMount(() => {
8
- const inIframe = window.self !== window.top;
9
- if (!inIframe)
10
- showSidebar = true;
11
- });
12
- let map = $state();
13
- let geometryManager = $state();
14
- let elements = $state([]);
15
- let activeElement = $state(undefined);
16
- function onMapInit(_map) {
17
- map = _map;
18
- map.on('load', async () => {
19
- geometryManager = new GeometryManager(map);
20
- geometryManager.elements.subscribe((value) => (elements = value));
21
- geometryManager.activeElement.subscribe((value) => (activeElement = value));
22
- });
23
- }
24
- $effect(() => geometryManager?.setActiveElement(activeElement));
1
+ <script lang="ts">
2
+ import type { Map as MaplibreMapType } from 'maplibre-gl';
3
+ import 'maplibre-gl/dist/maplibre-gl.css';
4
+ import BasicMap from '../BasicMap/BasicMap.svelte';
5
+ import { onMount } from 'svelte';
6
+ import Sidebar from './components/Sidebar.svelte';
7
+ import type { GeometryManager } from './lib/geometry_manager.js';
8
+
9
+ let showSidebar = $state(false);
10
+
11
+ onMount(() => {
12
+ const inIframe = window.self !== window.top;
13
+ if (!inIframe) showSidebar = true;
14
+ });
15
+
16
+ let map: MaplibreMapType | undefined = $state();
17
+ let geometryManager: GeometryManager | undefined = $state();
18
+
19
+ function onMapInit(_map: MaplibreMapType) {
20
+ map = _map;
21
+ map.on('load', async () => {
22
+ const { GeometryManager } = await import('./lib/geometry_manager.js');
23
+ geometryManager = new GeometryManager(map!);
24
+ });
25
+ }
25
26
  </script>
26
27
 
27
28
  <div class="page">
@@ -29,62 +30,16 @@ $effect(() => geometryManager?.setActiveElement(activeElement));
29
30
  <BasicMap {onMapInit} styleOptions={{ disableDarkMode: true }}></BasicMap>
30
31
  </div>
31
32
  {#if showSidebar && geometryManager}
32
- <div class="sidebar" style="--gap: 10px;">
33
- <div class="label">Add new:</div>
34
- <div class="row" style="display: flex; column-gap: var(--gap);">
35
- <input
36
- type="button"
37
- value="Marker"
38
- onclick={() => (activeElement = geometryManager?.getNewMarker())}
39
- />
40
- <input
41
- type="button"
42
- value="Line"
43
- onclick={() => (activeElement = geometryManager?.getNewLine())}
44
- />
45
- </div>
46
- <hr />
47
- <div class="row">
48
- <select
49
- size="5"
50
- bind:value={
51
- () => elements.indexOf(activeElement!), (index) => (activeElement = elements[index])
52
- }
53
- >
54
- {#each elements as element, index}
55
- <option value={index}>{element.name}</option>
56
- {/each}
57
- </select>
58
- </div>
59
- {#if activeElement != null}
60
- <hr />
61
- <div class="editor">
62
- <Editor element={activeElement} />
63
- </div>
64
- {/if}
65
- </div>
66
- <style>.page .sidebar {
67
- width: 300px;
68
- height: 100%;
69
- position: absolute;
70
- top: 0;
71
- right: 0;
72
- min-height: 6em;
73
- background-color: #eee;
74
- overflow-y: scroll;
75
- box-sizing: border-box;
76
- padding: var(--gap);
77
- }
78
- .page .row {
79
- margin-bottom: var(--gap);
80
- }
81
- .page .container {
82
- width: calc(100% - 300px);
83
- height: 100%;
84
- position: absolute;
85
- top: 0;
86
- left: 0;
87
- }</style>
33
+ <Sidebar {geometryManager} width={200} />
34
+
35
+ <style>
36
+ .page .container {
37
+ width: calc(100% - 200px);
38
+ position: absolute;
39
+ top: 0;
40
+ left: 0;
41
+ }
42
+ </style>
88
43
  {/if}
89
44
  </div>
90
45
 
@@ -0,0 +1,53 @@
1
+ <script lang="ts">
2
+ import type { AbstractElement } from '../lib/element/abstract.js';
3
+ import EditorFill from './EditorFill.svelte';
4
+ import EditorStroke from './EditorStroke.svelte';
5
+ import EditorSymbol from './EditorSymbol.svelte';
6
+ import { LineElement } from '../lib/element/line.js';
7
+ import { MarkerElement } from '../lib/element/marker.js';
8
+ import { PolygonElement } from '../lib/element/polygon.js';
9
+
10
+ const { element }: { element: AbstractElement } = $props();
11
+ let strokeVisible = $state(false);
12
+
13
+ if (element instanceof PolygonElement) {
14
+ element.strokeLayer.visible.subscribe((value) => (strokeVisible = value));
15
+ }
16
+ </script>
17
+
18
+ {#if element instanceof MarkerElement}
19
+ <h2>Marker</h2>
20
+ <EditorSymbol layer={element.layer} />
21
+ {/if}
22
+ {#if element instanceof LineElement}
23
+ <h2>Line Stroke</h2>
24
+ <EditorStroke layer={element.layer} />
25
+ {/if}
26
+ {#if element instanceof PolygonElement}
27
+ <h2>Polygon Fill</h2>
28
+ <EditorFill layer={element.fillLayer} />
29
+ <h2>Polygon Stroke</h2>
30
+
31
+ <div class="row-input">
32
+ <label for="showStroke">Outline:</label>
33
+ <input
34
+ id="showStroke"
35
+ type="checkbox"
36
+ bind:checked={
37
+ () => strokeVisible, (v) => (element as PolygonElement).strokeLayer.visible.set(v)
38
+ }
39
+ />
40
+ </div>
41
+
42
+ {#if strokeVisible}
43
+ <EditorStroke layer={element.strokeLayer} />
44
+ {/if}
45
+ {/if}
46
+ {#if element instanceof PolygonElement || element instanceof LineElement}
47
+ <h2>Shape</h2>
48
+ <p>
49
+ Drag points to move.<br />Drag a midpoint to add.<br />Shift-click to delete a point.
50
+ </p>
51
+ {/if}
52
+ <h2>Actions</h2>
53
+ <input type="button" value="Delete" onclick={() => element!.delete()} />
@@ -1,4 +1,4 @@
1
- import type { AbstractElement } from './lib/element_abstract.js';
1
+ import type { AbstractElement } from '../lib/element/abstract.js';
2
2
  type $$ComponentProps = {
3
3
  element: AbstractElement;
4
4
  };
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ import { fillPatterns, type MapLayerFill } from '../lib/map_layer/fill.js';
3
+
4
+ const { layer }: { layer: MapLayerFill } = $props();
5
+
6
+ let color = $state(layer.color);
7
+ let pattern = $state(layer.pattern);
8
+ let opacity = $state(layer.opacity);
9
+ </script>
10
+
11
+ <div class="row-input">
12
+ <label for="color">Color:</label>
13
+ <input id="color" type="color" bind:value={$color} />
14
+ </div>
15
+
16
+ <div class="row-input">
17
+ <label for="pattern">Pattern:</label>
18
+ <select id="pattern" bind:value={$pattern}>
19
+ {#each fillPatterns as [index, fill]}
20
+ <option value={index}>{fill.name}</option>
21
+ {/each}
22
+ </select>
23
+ </div>
24
+
25
+ <div class="row-input">
26
+ <label for="opacity">Opacity:</label>
27
+ <input id="opacity" type="range" min="0" max="1" step="0.02" bind:value={$opacity} />
28
+ </div>
@@ -0,0 +1,7 @@
1
+ import { type MapLayerFill } from '../lib/map_layer/fill.js';
2
+ type $$ComponentProps = {
3
+ layer: MapLayerFill;
4
+ };
5
+ declare const EditorFill: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EditorFill = ReturnType<typeof EditorFill>;
7
+ export default EditorFill;
@@ -0,0 +1,28 @@
1
+ <script lang="ts">
2
+ import { dashArrays, MapLayerLine } from '../lib/map_layer/line.js';
3
+
4
+ const { layer }: { layer: MapLayerLine } = $props();
5
+
6
+ let color = $state(layer.color);
7
+ let width = $state(layer.width);
8
+ let dashed = $state(layer.dashed);
9
+ </script>
10
+
11
+ <div class="row-input">
12
+ <label for="dashed">Dashed:</label>
13
+ <select id="dashed" bind:value={$dashed}>
14
+ {#each dashArrays as [index, dash]}
15
+ <option value={index}>{dash.name}</option>
16
+ {/each}
17
+ </select>
18
+ </div>
19
+
20
+ <div class="row-input">
21
+ <label for="color">Color:</label>
22
+ <input id="color" type="color" bind:value={$color} />
23
+ </div>
24
+
25
+ <div class="row-input">
26
+ <label for="width">Width:</label>
27
+ <input id="width" type="range" min="0.5" max="5" step="0.5" bind:value={$width} />
28
+ </div>
@@ -0,0 +1,7 @@
1
+ import { MapLayerLine } from '../lib/map_layer/line.js';
2
+ type $$ComponentProps = {
3
+ layer: MapLayerLine;
4
+ };
5
+ declare const EditorStroke: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EditorStroke = ReturnType<typeof EditorStroke>;
7
+ export default EditorStroke;
@@ -0,0 +1,43 @@
1
+ <script lang="ts">
2
+ import { MapLayerSymbol } from '../lib/map_layer/symbol.js';
3
+ import SymbolSelector from './SymbolSelector.svelte';
4
+
5
+ const { layer }: { layer: MapLayerSymbol } = $props();
6
+
7
+ let symbolIndex = $state(layer.symbolIndex);
8
+ let color = $state(layer.color);
9
+ let rotate = $state(layer.rotate);
10
+ let halo = $state(layer.halo);
11
+ let label = $state(layer.label);
12
+ let size = $state(layer.size);
13
+ </script>
14
+
15
+ <div class="row-input">
16
+ <div class="label">Symbol:</div>
17
+ <SymbolSelector bind:symbolIndex={$symbolIndex} symbolLibrary={layer.manager.symbolLibrary} />
18
+ </div>
19
+
20
+ <div class="row-input">
21
+ <label for="color">Color:</label>
22
+ <input id="color" type="color" bind:value={$color} />
23
+ </div>
24
+
25
+ <div class="row-input">
26
+ <label for="size">Size:</label>
27
+ <input id="size" type="range" min="0.5" max="3" step="0.1" bind:value={$size} />
28
+ </div>
29
+
30
+ <div class="row-input">
31
+ <label for="rotate">Rotation:</label>
32
+ <input id="rotate" type="range" min="-180" max="180" step="15" bind:value={$rotate} />
33
+ </div>
34
+
35
+ <div class="row-input">
36
+ <label for="halo">Halo:</label>
37
+ <input id="halo" type="range" min="0" max="3" step="0.5" bind:value={$halo} />
38
+ </div>
39
+
40
+ <div class="row-input">
41
+ <label for="label">Label:</label>
42
+ <input id="label" type="label" bind:value={$label} />
43
+ </div>
@@ -0,0 +1,7 @@
1
+ import { MapLayerSymbol } from '../lib/map_layer/symbol.js';
2
+ type $$ComponentProps = {
3
+ layer: MapLayerSymbol;
4
+ };
5
+ declare const EditorSymbol: import("svelte").Component<$$ComponentProps, {}, "">;
6
+ type EditorSymbol = ReturnType<typeof EditorSymbol>;
7
+ export default EditorSymbol;
@@ -0,0 +1,179 @@
1
+ <script lang="ts">
2
+ import type { AbstractElement } from '../lib/element/abstract.js';
3
+ import Editor from './Editor.svelte';
4
+ import type { GeometryManager } from '../lib/geometry_manager.js';
5
+
6
+ const { geometryManager, width }: { geometryManager: GeometryManager; width: number } = $props();
7
+
8
+ let activeElement: AbstractElement | undefined = $state(undefined);
9
+ $effect(() => geometryManager.selectElement(activeElement));
10
+
11
+ geometryManager.selectedElement.subscribe((value) => (activeElement = value));
12
+
13
+ function importGeoJSON() {
14
+ const input = document.createElement('input');
15
+ input.type = 'file';
16
+ input.onchange = (_) => {
17
+ if (!input.files) return alert('No file selected.');
18
+ const file = input.files[0];
19
+ const reader = new FileReader();
20
+ reader.onload = (evt) => {
21
+ try {
22
+ if (!evt.target) return alert('Failed to read file.');
23
+ const json = JSON.parse(evt.target.result as string);
24
+ geometryManager.addGeoJSON(json);
25
+ } catch (error) {
26
+ console.error(error);
27
+ return alert('Failed to import GeoJSON. Please check the file format.');
28
+ }
29
+ };
30
+
31
+ reader.onerror = () => alert('Failed to read file. Please try again.');
32
+
33
+ reader.readAsText(file);
34
+ };
35
+ input.click();
36
+ }
37
+
38
+ function exportGeoJSON() {
39
+ const geoJSON = geometryManager.getGeoJSON();
40
+ const blob = new Blob([JSON.stringify(geoJSON)], { type: 'application/geo+json' });
41
+ const url = URL.createObjectURL(blob);
42
+ const a = document.createElement('a');
43
+ a.setAttribute('href', url);
44
+ a.setAttribute('download', 'map.geojson');
45
+ a.click();
46
+ URL.revokeObjectURL(url);
47
+ }
48
+ </script>
49
+
50
+ <div class="sidebar" style="--gap: 10px;width: {width}px;">
51
+ <div style="min-height: calc(100vh - 2em);">
52
+ <div class="label">GeoJSON:</div>
53
+ <div class="row-flex">
54
+ <input type="button" value="Import" onclick={importGeoJSON} />
55
+ <input type="button" value="Export" onclick={exportGeoJSON} />
56
+ </div>
57
+ <hr />
58
+ <div class="label">Add new:</div>
59
+ <div class="row-flex">
60
+ <input
61
+ type="button"
62
+ value="Marker"
63
+ onclick={() => (activeElement = geometryManager.addNewMarker())}
64
+ />
65
+ <input
66
+ type="button"
67
+ value="Line"
68
+ onclick={() => (activeElement = geometryManager.addNewLine())}
69
+ />
70
+ <input
71
+ type="button"
72
+ value="Polygon"
73
+ onclick={() => (activeElement = geometryManager.addNewPolygon())}
74
+ />
75
+ </div>
76
+ {#if activeElement != null}
77
+ <hr />
78
+ <Editor element={activeElement} />
79
+ {/if}
80
+ </div>
81
+ <div class="footer">
82
+ <a href="https://github.com/versatiles-org/node-versatiles-svelte/issues" target="_blank">
83
+ Add a GitHub issue.</a
84
+ >
85
+ </div>
86
+ </div>
87
+
88
+ <style>
89
+ .sidebar {
90
+ width: 200px;
91
+ height: 100%;
92
+ position: absolute;
93
+ top: 0;
94
+ right: 0;
95
+ background-color: #eee;
96
+ overflow-y: scroll;
97
+ box-sizing: border-box;
98
+ padding: 0.5em var(--gap) 0;
99
+ border-left: 0.5px solid rgba(0, 0, 0, 0.5);
100
+
101
+ hr {
102
+ border: none;
103
+ border-top: 0.5px solid rgba(0, 0, 0, 1);
104
+ margin: var(--gap) 0 var(--gap);
105
+ }
106
+
107
+ :global(h2) {
108
+ font-size: 0.9em;
109
+ font-weight: normal;
110
+ opacity: 0.5;
111
+ padding-top: var(--gap);
112
+ border-top: 0.5px solid rgba(0, 0, 0, 1);
113
+ margin: var(--gap) 0 var(--gap);
114
+ text-align: center;
115
+ }
116
+
117
+ :global(.row-flex) {
118
+ margin-bottom: var(--gap);
119
+ display: flex;
120
+ justify-content: space-between;
121
+ column-gap: var(--gap);
122
+ :global(input) {
123
+ flex-grow: 0;
124
+ }
125
+ }
126
+
127
+ :global(.row-input) {
128
+ margin: var(--gap) 0 var(--gap);
129
+ display: flex;
130
+ justify-content: space-between;
131
+ align-items: center;
132
+ & > :global(label) {
133
+ flex-grow: 0;
134
+ }
135
+ & > :global(button),
136
+ & > :global(input),
137
+ & > :global(select) {
138
+ width: 60%;
139
+ flex-grow: 0;
140
+ }
141
+ & > :global(input[type='checkbox']) {
142
+ width: auto;
143
+ }
144
+ }
145
+
146
+ :global(label),
147
+ :global(.label) {
148
+ opacity: 0.7;
149
+ font-size: 0.8em;
150
+ }
151
+
152
+ :global(button),
153
+ :global(input),
154
+ :global(select) {
155
+ width: 100%;
156
+ box-sizing: border-box;
157
+ margin: 0;
158
+ }
159
+
160
+ :global(p) {
161
+ font-size: 0.8em;
162
+ opacity: 0.5;
163
+ margin: 0.5em 0 1em;
164
+ }
165
+
166
+ .footer {
167
+ text-align: right;
168
+ font-size: 0.8em;
169
+ a {
170
+ color: #000;
171
+ text-decoration: none;
172
+ opacity: 0.3;
173
+ &:hover {
174
+ opacity: 1;
175
+ }
176
+ }
177
+ }
178
+ }
179
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { GeometryManager } from '../lib/geometry_manager.js';
2
+ type $$ComponentProps = {
3
+ geometryManager: GeometryManager;
4
+ width: number;
5
+ };
6
+ declare const Sidebar: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Sidebar = ReturnType<typeof Sidebar>;
8
+ export default Sidebar;
@@ -0,0 +1,118 @@
1
+ <script lang="ts">
2
+ import type { Action } from 'svelte/action';
3
+ import type { SymbolLibrary } from '../lib/symbols.js';
4
+
5
+ let {
6
+ symbolIndex = $bindable(),
7
+ symbolLibrary
8
+ }: { symbolIndex: number; symbolLibrary: SymbolLibrary } = $props();
9
+
10
+ let open = $state(false);
11
+
12
+ const drawIconHalo: Action<HTMLCanvasElement, number> = (canvas, index) =>
13
+ symbolLibrary.drawSymbol(canvas, index, true);
14
+
15
+ const drawIcon: Action<HTMLCanvasElement, number> = (canvas, index) =>
16
+ symbolLibrary.drawSymbol(canvas, index);
17
+ </script>
18
+
19
+ <button
20
+ onclick={() => (open = !open)}
21
+ style="text-align: left; white-space: nowrap; overflow: hidden; padding: 1px"
22
+ >
23
+ {#key symbolIndex}
24
+ <canvas
25
+ width="40"
26
+ height="40"
27
+ use:drawIcon={symbolIndex}
28
+ style="width:20px;height:20px;vertical-align:middle"
29
+ ></canvas>
30
+ {/key}
31
+ {#if symbolIndex !== undefined}
32
+ {symbolLibrary.getSymbol(symbolIndex)?.name}
33
+ {:else}
34
+ Select Symbol
35
+ {/if}
36
+ </button>
37
+
38
+ <div class="modal" style="display: {open ? 'block' : 'none'};">
39
+ <button class="close" onclick={() => (open = false)}>&#x2715;</button>
40
+ <div class="inner">
41
+ {#each symbolLibrary.asList() as symbol}
42
+ <button
43
+ class="icon"
44
+ onclick={() => {
45
+ symbolIndex = symbol.index;
46
+ open = false;
47
+ }}
48
+ ><canvas width="64" height="64" use:drawIconHalo={symbol.index}></canvas><br
49
+ />{symbol.name}</button
50
+ >
51
+ {/each}
52
+ </div>
53
+ </div>
54
+
55
+ <style>
56
+ .modal {
57
+ position: fixed;
58
+ top: max(calc(50vh - 250px), 0px);
59
+ left: max(calc(50vw - 250px), 0px);
60
+ width: min(500px, 100vw);
61
+ height: min(500px, 100vh);
62
+ background-color: rgba(255, 255, 255, 0.5);
63
+ backdrop-filter: blur(20px) brightness(0.85);
64
+ box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.2);
65
+ z-index: 10000;
66
+ border: 0.5px solid rgba(0, 0, 0, 0.5);
67
+ border-radius: 10px;
68
+ box-sizing: border-box;
69
+ padding: 20px;
70
+
71
+ .inner {
72
+ width: 100%;
73
+ height: 100%;
74
+ overflow-y: scroll;
75
+ display: grid;
76
+ grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
77
+ row-gap: 10px;
78
+ column-gap: 0px;
79
+ justify-items: center;
80
+
81
+ .icon {
82
+ width: 48px;
83
+ height: 48px;
84
+ cursor: pointer;
85
+ border: none;
86
+ font-size: 0.6em;
87
+ background: none;
88
+ line-height: 1em;
89
+ text-align: center;
90
+ padding: 0;
91
+
92
+ &:hover {
93
+ background-color: rgba(0, 0, 0, 0.1);
94
+ }
95
+
96
+ canvas {
97
+ display: inline-block;
98
+ width: 32px;
99
+ height: 32px;
100
+ }
101
+ }
102
+ }
103
+
104
+ .close {
105
+ position: absolute;
106
+ top: 0px;
107
+ right: 0px;
108
+ font-size: 20px;
109
+ cursor: pointer;
110
+ background: none;
111
+ border: none;
112
+ width: 25px;
113
+ height: 25px;
114
+ text-align: center;
115
+ padding: 0;
116
+ }
117
+ }
118
+ </style>
@@ -0,0 +1,8 @@
1
+ import type { SymbolLibrary } from '../lib/symbols.js';
2
+ type $$ComponentProps = {
3
+ symbolIndex: number;
4
+ symbolLibrary: SymbolLibrary;
5
+ };
6
+ declare const SymbolSelector: import("svelte").Component<$$ComponentProps, {}, "symbolIndex">;
7
+ type SymbolSelector = ReturnType<typeof SymbolSelector>;
8
+ export default SymbolSelector;
@@ -0,0 +1,5 @@
1
+ export declare class MockCursor {
2
+ grab: import("vitest").Mock<(...args: any[]) => any>;
3
+ hover: import("vitest").Mock<(...args: any[]) => any>;
4
+ precise: import("vitest").Mock<(...args: any[]) => any>;
5
+ }
@@ -0,0 +1,6 @@
1
+ import { vi } from 'vitest';
2
+ export class MockCursor {
3
+ grab = vi.fn();
4
+ hover = vi.fn();
5
+ precise = vi.fn();
6
+ }
@@ -0,0 +1,22 @@
1
+ import { type Writable } from 'svelte/store';
2
+ import type { AbstractElement } from '../element/abstract.js';
3
+ import type { StateObject } from '../state/types.js';
4
+ import { MockMap } from './map.js';
5
+ import { MockCursor } from './cursor.js';
6
+ export declare class MockGeometryManager {
7
+ readonly elements: Writable<AbstractElement[]>;
8
+ readonly activeElement: Writable<AbstractElement | undefined>;
9
+ readonly map: MockMap;
10
+ readonly cursor: MockCursor;
11
+ constructor();
12
+ setActiveElement: import("vitest").Mock<(...args: any[]) => any>;
13
+ getState: import("vitest").Mock<() => StateObject>;
14
+ saveState: import("vitest").Mock<(...args: any[]) => any>;
15
+ loadState: import("vitest").Mock<(...args: any[]) => any>;
16
+ getElement: import("vitest").Mock<(index: number) => AbstractElement>;
17
+ addNewMarker: import("vitest").Mock<() => AbstractElement>;
18
+ addNewLine: import("vitest").Mock<() => AbstractElement>;
19
+ addNewPolygon: import("vitest").Mock<() => AbstractElement>;
20
+ deleteElement: import("vitest").Mock<(...args: any[]) => any>;
21
+ drawSelectionNodes: import("vitest").Mock<(...args: any[]) => any>;
22
+ }