@community-release/nx-ui 0.0.32 → 0.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.d.mts CHANGED
@@ -101,12 +101,15 @@ var defaultComponentsStyle = {
101
101
  },
102
102
  button: {
103
103
  "border-radius": "var(--ui-input-height-large)"
104
+ },
105
+ map: {
106
+ "user-position-color": "var(--ui-color-primary)"
104
107
  }
105
108
  };
106
109
 
107
110
  var generateComponentsDefaults = (options) => {
108
111
  let result = "";
109
- const components = options?.components ? options.components : {};
112
+ const components = options?.componentsStyle ? options.componentsStyle : {};
110
113
  for (let name in defaultComponentsStyle) {
111
114
  const style = Object.assign(defaultComponentsStyle[name], components[name] ? components[name] : {});
112
115
  for (let prop in style) {
@@ -114,6 +117,7 @@ var generateComponentsDefaults = (options) => {
114
117
  `;
115
118
  }
116
119
  }
120
+ console.log("componentsStyle", result);
117
121
  return result;
118
122
  };
119
123
 
package/dist/module.d.ts CHANGED
@@ -101,12 +101,15 @@ var defaultComponentsStyle = {
101
101
  },
102
102
  button: {
103
103
  "border-radius": "var(--ui-input-height-large)"
104
+ },
105
+ map: {
106
+ "user-position-color": "var(--ui-color-primary)"
104
107
  }
105
108
  };
106
109
 
107
110
  var generateComponentsDefaults = (options) => {
108
111
  let result = "";
109
- const components = options?.components ? options.components : {};
112
+ const components = options?.componentsStyle ? options.componentsStyle : {};
110
113
  for (let name in defaultComponentsStyle) {
111
114
  const style = Object.assign(defaultComponentsStyle[name], components[name] ? components[name] : {});
112
115
  for (let prop in style) {
@@ -114,6 +117,7 @@ var generateComponentsDefaults = (options) => {
114
117
  `;
115
118
  }
116
119
  }
120
+ console.log("componentsStyle", result);
117
121
  return result;
118
122
  };
119
123
 
package/dist/module.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "ui",
3
3
  "configKey": "ui",
4
- "version": "0.0.32"
4
+ "version": "0.0.33"
5
5
  }
package/dist/module.mjs CHANGED
@@ -101,12 +101,15 @@ const defaultComponentsStyle = {
101
101
  },
102
102
  button: {
103
103
  "border-radius": "var(--ui-input-height-large)"
104
+ },
105
+ map: {
106
+ "user-position-color": "var(--ui-color-primary)"
104
107
  }
105
108
  };
106
109
 
107
110
  const generateComponentsDefaults = (options) => {
108
111
  let result = "";
109
- const components = options?.components ? options.components : {};
112
+ const components = options?.componentsStyle ? options.componentsStyle : {};
110
113
  for (let name in defaultComponentsStyle) {
111
114
  const style = Object.assign(defaultComponentsStyle[name], components[name] ? components[name] : {});
112
115
  for (let prop in style) {
@@ -114,6 +117,7 @@ const generateComponentsDefaults = (options) => {
114
117
  `;
115
118
  }
116
119
  }
120
+ console.log("componentsStyle", result);
117
121
  return result;
118
122
  };
119
123
 
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <section class="component-ui-loading2" :class="{'tag-active': active}">
2
+ <section class="component-ui-loading" :class="{'tag-active': active}">
3
3
  <svg width="32" height="32">
4
4
  <circle cx="16" cy="16" r="10" ref="progress" />
5
5
  </svg>
@@ -51,7 +51,7 @@ const props = defineProps({
51
51
  }
52
52
  }
53
53
 
54
- .component-ui-loading2 {
54
+ .component-ui-loading {
55
55
  transition: visibility @com-ani-time @com-ani-ease, opacity @com-ani-time @com-ani-ease;
56
56
 
57
57
  opacity: 0;
@@ -15,7 +15,7 @@ const props = defineProps({
15
15
  },
16
16
  label: {
17
17
  default: '',
18
- }
18
+ },
19
19
  });
20
20
  const store = useMapStore();
21
21
 
@@ -1,37 +1,100 @@
1
1
  <template>
2
2
  <section class="component-ui-map-location-nearest" @click="handleClick">
3
- <i v-if="icon" class="icon" :class="icon"></i>
3
+ <i v-if="icon" class="icon" :class="[icon, loading ? 'tag-loading' : '']">
4
+ <ui-loading :active="loading" />
5
+ </i>
4
6
  <span class="label"><span>{{ label }}</span></span>
5
7
  </section>
6
8
  </template>
7
9
 
8
10
  <script setup>
9
- const props = defineProps({
10
- label: {
11
- required: true,
12
- type: String
13
- },
14
- icon: {
15
- required: true,
16
- type: String
17
- },
18
- });
19
-
20
- function getPosition() {
21
- return new Promise((res, rej) => {
22
- navigator.geolocation.getCurrentPosition(res, rej);
23
- });
24
- }
11
+ // Import
12
+ import { ref } from 'vue';
13
+ import UiLoading from '../../loading.vue';
14
+ import { useMapStore } from '../store';
15
+
16
+ // Data
17
+ const props = defineProps({
18
+ label: {
19
+ required: true,
20
+ type: String
21
+ },
22
+ icon: {
23
+ required: true,
24
+ type: String
25
+ },
26
+ locations: {
27
+ required: true,
28
+ type: Array
29
+ },
30
+ });
31
+ const store = useMapStore();
32
+ const loading = ref(false);
33
+ let cachedPosition = null;
34
+ let cachedTime = 0;
25
35
 
26
- async function handleClick() {
27
- let pos = null;
36
+ // Methods
37
+ // Get distance between points
38
+ function getDistance(p1, p2) {
39
+ const dx = p1.coord[0] - p2.coord[0];
40
+ const dy = p1.coord[1] - p2.coord[1];
28
41
 
29
- try {
30
- pos = await getPosition();
31
- } catch (err) {
32
- console.log('handleClick err', err);
42
+ return Math.sqrt(dx * dx + dy * dy);
43
+ }
44
+
45
+ // Find nearest points
46
+ function findNearestPoint(points, target) {
47
+ if (points.length === 0) return [];
48
+
49
+ // Calculate distances
50
+ const pointsWithDistance = points.map(point => ({
51
+ data: point,
52
+ distance: getDistance(point, target)
53
+ }));
54
+
55
+ // Sort by distance
56
+ pointsWithDistance.sort((a, b) => a.distance - b.distance);
57
+
58
+ // Select the first n points
59
+ return pointsWithDistance[0].data;
60
+ }
61
+
62
+ function getPosition() {
63
+ return new Promise((res, rej) => {
64
+ navigator.geolocation.getCurrentPosition(res, rej);
65
+ });
66
+ }
67
+
68
+ async function handleClick() {
69
+ try {
70
+ // If cache not exist or it's older than 1 minute
71
+ if (!cachedPosition || Date.now() - cachedTime > 60000) {
72
+ loading.value = true;
73
+
74
+ const pos = await getPosition();
75
+
76
+ cachedPosition = [pos.coords.longitude, pos.coords.latitude];
77
+ cachedTime = Date.now();
78
+
79
+ store.setUserCoord(cachedPosition);
80
+ }
81
+
82
+ // Find nearest point
83
+ const nearest = findNearestPoint(
84
+ props.locations,
85
+ { coord: cachedPosition }
86
+ );
87
+
88
+ // Set coord and zoom
89
+ store.setCoord(nearest.coord, 2);
90
+ store.setZoom(nearest?.zoom ? nearest.zoom : 14);
91
+ } catch (err) {
92
+ console.log('handleClick err', err);
93
+ }
94
+
95
+ store.setSelectedMarker(null);
96
+ loading.value = false;
33
97
  }
34
- }
35
98
  </script>
36
99
 
37
100
  <style lang="less">
@@ -50,19 +113,42 @@ async function handleClick() {
50
113
  @com-color-bg: var(--ui-color-bg);
51
114
  @com-color-primary: var(--ui-color-primary);
52
115
 
116
+ @com-ani-time: var(--ui-ani-time);
117
+ @com-ani-ease: var(--ui-ani-ease);
118
+
53
119
  .component-ui-map-location-nearest {
54
120
  height: @com-height;
55
121
  background: @com-color-bg;
56
122
  border-radius: @com-border-radius-default;
57
123
 
124
+ position: relative;
58
125
  display: flex;
59
126
  cursor: pointer;
60
127
 
61
128
  .icon {
129
+ position: relative;
62
130
  flex: 0 0 38px;
63
131
  line-height: @com-height;
64
132
  font-size: @com-text-medium;
65
133
  color: @com-color-primary;
134
+
135
+ .component-ui-loading {
136
+ transform: translate3d(-50%, -50%, 0);
137
+ position: absolute;
138
+ top: 50%;
139
+ left: 50%;
140
+ }
141
+
142
+ &:before {
143
+ transition: opacity @com-ani-time @com-ani-ease;
144
+ }
145
+
146
+ &.tag-loading {
147
+ &:before {
148
+ opacity: 0;
149
+ }
150
+ }
151
+
66
152
  }
67
153
 
68
154
  .label {
@@ -73,16 +159,8 @@ async function handleClick() {
73
159
  font-size: @com-text-small;
74
160
 
75
161
  span {
76
- .mix-miltiline-text-overflow(2);
162
+ .mix-multiline-text-overflow(2);
77
163
  }
78
164
  }
79
165
  }
80
-
81
- // @media only screen and (max-width: 390px) {
82
- // .component-ui-map-location-nearest {
83
- // .icon {
84
- // flex-basis: 32px;
85
- // }
86
- // }
87
- // }
88
166
  </style>
@@ -1,6 +1,9 @@
1
1
  <template>
2
2
  <div class="component-ui-map-openlayer component-ui-map-engine">
3
3
  <div class="map" ref="refMap"></div>
4
+ <div style="display:none">
5
+ <div id="user-position-marker"></div>
6
+ </div>
4
7
  <slot />
5
8
  </div>
6
9
  </template>
@@ -29,6 +32,7 @@
29
32
  import { Cluster, OSM, Vector as VectorSource } from 'ol/source.js';
30
33
  import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer.js';
31
34
  import { boundingExtent } from 'ol/extent.js';
35
+ import Overlay from 'ol/Overlay.js';
32
36
 
33
37
  import Map from 'ol/Map.js';
34
38
  import View from 'ol/View.js';
@@ -52,10 +56,12 @@
52
56
  let initialized = false;
53
57
  let features = [];
54
58
  let cluster = null;
59
+ let userPositionMarker = null;
55
60
 
56
61
  // Store
57
62
  const store = useMapStore();
58
63
  const {
64
+ requestCoordChange,
59
65
  coord,
60
66
  zoom,
61
67
  zoomMin,
@@ -66,7 +72,8 @@
66
72
  markerImage,
67
73
  markerActiveImage,
68
74
  markerDisabledImage,
69
- selectedMarker
75
+ selectedMarker,
76
+ userCoord
70
77
  } = storeToRefs(store);
71
78
 
72
79
  watch(() => selectedMarker.value, (v) => {
@@ -78,7 +85,23 @@
78
85
  });
79
86
 
80
87
  // Watch coord
81
- watch(coord, (v) => { view.setCenter(fromLonLat(v)); });
88
+ watch([requestCoordChange, coord], (v) => {
89
+ if (!v[0]) return;
90
+
91
+ const coord = fromLonLat(v[1]);
92
+
93
+ if (v[0] === 1)
94
+ view.setCenter(coord);
95
+ else
96
+ view.animate({center: coord, duration: 300});
97
+
98
+ requestCoordChange.value = 0;
99
+ });
100
+
101
+ // Watch user coord
102
+ watch(userCoord, (v) => {
103
+ userPositionMarker.setPosition(fromLonLat(v));
104
+ });
82
105
 
83
106
  // Watch zoom
84
107
  watch(zoom, (v) => {
@@ -290,6 +313,15 @@
290
313
  controls: []
291
314
  });
292
315
 
316
+ // Add user position marker
317
+ userPositionMarker = new Overlay({
318
+ position: fromLonLat(coord.value),
319
+ positioning: 'center-center',
320
+ element: document.getElementById('user-position-marker'),
321
+ stopEvent: false,
322
+ });
323
+ map.addOverlay(userPositionMarker);
324
+
293
325
  // Add mouse wheel interaction
294
326
  mouseWheelInt = new mouseWheelZoomInteraction({
295
327
  condition(e) {
@@ -345,6 +377,86 @@
345
377
  </script>
346
378
 
347
379
  <style lang="less">
380
+ @import (less) '../../styles/components.less';
381
+ @com-user-position-color: @ui-map-user-position-color;
382
+
383
+ @keyframes pulsar {
384
+ from {
385
+ transform: scale(1);
386
+ opacity: 0;
387
+ }
388
+
389
+ 50% { opacity: 0.7; }
390
+
391
+ to {
392
+ transform: scale(2);
393
+ opacity: 0;
394
+ }
395
+ }
396
+
397
+ @keyframes pulsar-base {
398
+ from { transform: scale(1); }
399
+ 50% { transform: scale(0.95); }
400
+ to { transform: scale(1); }
401
+ }
402
+
403
+ .mix-pulsar(@com-pulsar-size: 18px, @com-pulsar-color: @com-user-position-color) {
404
+ @com-pulsar-duration: 2s;
405
+
406
+ pointer-events: none;
407
+ width: @com-pulsar-size;
408
+ height: @com-pulsar-size;
409
+
410
+ &:before {
411
+ content: '';
412
+
413
+ transform-origin: 50% 50%;
414
+
415
+ opacity: 0;
416
+ position: absolute;
417
+ top: 0;
418
+ left: 0;
419
+ width: 100%;
420
+ height: 100%;
421
+
422
+ border-radius: 50%;
423
+
424
+ background: @com-pulsar-color;
425
+
426
+ animation-name: pulsar;
427
+ animation-duration: @com-pulsar-duration;
428
+ animation-iteration-count: infinite;
429
+ animation-timing-function: linear;
430
+ animation-fill-mode: forwards;
431
+ animation-delay: 0.7s;
432
+ }
433
+
434
+ &:after {
435
+ content: '';
436
+
437
+ transform-origin: 50% 50%;
438
+ opacity: 0.9;
439
+
440
+ box-sizing: border-box;
441
+ position: absolute;
442
+ top: 0;
443
+ left: 0;
444
+ width: 100%;
445
+ height: 100%;
446
+
447
+ border-radius: 50%;
448
+ border: 2px solid #fff;
449
+ background: @com-pulsar-color;
450
+
451
+ animation-name: pulsar-base;
452
+ animation-duration: @com-pulsar-duration;
453
+ animation-iteration-count: infinite;
454
+ animation-timing-function: linear;
455
+ animation-fill-mode: forwards;
456
+ animation-delay: 0.7s;
457
+ }
458
+ }
459
+
348
460
  .component-ui-map-openlayer {
349
461
  position: relative;
350
462
 
@@ -353,5 +465,9 @@
353
465
  inset: 0;
354
466
  background: #add19e;
355
467
  }
468
+
469
+ #user-position-marker {
470
+ .mix-pulsar;
471
+ }
356
472
  }
357
473
  </style>
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "zoom": 8,
3
3
  "zoomMin": 7,
4
- "zoomMax": 18
4
+ "zoomMax": 18,
5
+ "userMarkerColor": "var(--ui-color-primary)"
5
6
  }
@@ -1,4 +1,5 @@
1
1
  export const useMapStore: import("pinia").StoreDefinition<"map", {
2
+ requestCoordChange: number;
2
3
  coord: never[];
3
4
  zoom: number;
4
5
  zoomMin: number;
@@ -10,6 +11,7 @@ export const useMapStore: import("pinia").StoreDefinition<"map", {
10
11
  markers: never[];
11
12
  selectedMarker: null;
12
13
  disabledMarkers: never[];
14
+ userCoord: never[];
13
15
  }, {
14
16
  /**
15
17
  * Get marker by id
@@ -40,8 +42,14 @@ export const useMapStore: import("pinia").StoreDefinition<"map", {
40
42
  /**
41
43
  * Set map coord
42
44
  * @param {MapCoord} v
45
+ * @param {number} requestCoordChange - 1 default, 2 animated
43
46
  */
44
- setCoord(v: MapCoord): void;
47
+ setCoord(v: MapCoord, requestCoordChange?: number): void;
48
+ /**
49
+ * Set user coord
50
+ * @param {MapCoord} v
51
+ */
52
+ setUserCoord(v: MapCoord): void;
45
53
  /**
46
54
  * Enable/disable device zoom, if call withour params then toggle current state
47
55
  * @param {boolean=} v
@@ -18,6 +18,7 @@ import { defineStore } from 'pinia';
18
18
  export const useMapStore = defineStore('map', {
19
19
  state: () => {
20
20
  return {
21
+ requestCoordChange: 0,
21
22
  coord: [],
22
23
 
23
24
  zoom: 8,
@@ -31,7 +32,9 @@ export const useMapStore = defineStore('map', {
31
32
  markerDisabledImage: '',
32
33
  markers: [],
33
34
  selectedMarker: null,
34
- disabledMarkers: []
35
+ disabledMarkers: [],
36
+
37
+ userCoord: []
35
38
  }
36
39
  },
37
40
 
@@ -85,11 +88,21 @@ export const useMapStore = defineStore('map', {
85
88
  /**
86
89
  * Set map coord
87
90
  * @param {MapCoord} v
91
+ * @param {number} requestCoordChange - 1 default, 2 animated
88
92
  */
89
- setCoord(v) {
93
+ setCoord(v, requestCoordChange = 1) {
94
+ this.requestCoordChange = requestCoordChange;
90
95
  this.coord = v;
91
96
  },
92
97
 
98
+ /**
99
+ * Set user coord
100
+ * @param {MapCoord} v
101
+ */
102
+ setUserCoord(v) {
103
+ this.userCoord = v;
104
+ },
105
+
93
106
  /**
94
107
  * Enable/disable device zoom, if call withour params then toggle current state
95
108
  * @param {boolean=} v
@@ -1,3 +1,4 @@
1
1
  @ui-accordion-title-font-size: var(--ui-text-medium);
2
2
  @ui-accordion-text-font-size: var(--ui-text-default);
3
3
  @ui-button-border-radius: var(--ui-input-height-large);
4
+ @ui-map-user-position-color: var(--color-primary);
@@ -1,4 +1,4 @@
1
- .mix-miltiline-text-overflow(@line-numbers: 2) {
1
+ .mix-multiline-text-overflow(@line-numbers: 2) {
2
2
  overflow: hidden;
3
3
  display: -webkit-box;
4
4
  -webkit-line-clamp: @line-numbers;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@community-release/nx-ui",
3
- "version": "0.0.32",
3
+ "version": "0.0.33",
4
4
  "description": "nx-ui - Nuxt UI library",
5
5
  "repository": {
6
6
  "type": "git",
@@ -52,7 +52,7 @@
52
52
  },
53
53
  "scripts": {
54
54
  "prepack": "nuxt-module-build build",
55
- "dev": "nuxi dev docs --host",
55
+ "dev": "nuxi dev docs --host --port 7012",
56
56
  "build": "nuxi build docs",
57
57
  "prepare": "nuxt-module-build build && nuxt-module-build prepare && nuxi prepare docs",
58
58
  "release": "npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",