@dative-gpi/foundation-shared-components 1.0.194-dynamic-v-node → 1.0.194-playlists-02

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.
@@ -28,10 +28,18 @@ export default defineComponent({
28
28
  type: Boolean,
29
29
  required: false,
30
30
  default: true
31
+ },
32
+ variant: {
33
+ type: String as () => "fill" | "outline",
34
+ required: false,
35
+ default: "outline"
31
36
  }
32
37
  },
33
38
  setup(props) {
34
39
  const icon = computed((): string => {
40
+ if (props.variant === "fill") {
41
+ return props.value ? "mdi-check-circle" : "mdi-close-circle";
42
+ }
35
43
  return props.value ? "mdi-check-circle-outline" : "mdi-close-circle-outline";
36
44
  });
37
45
 
@@ -2,12 +2,21 @@
2
2
  <FSCol
3
3
  gap="12px"
4
4
  >
5
- <FSSearchField
6
- v-if="$props.searchable"
7
- :hideHeader="true"
8
- :modelValue="actualSearch"
9
- @update:modelValue="onSearch"
10
- />
5
+ <FSRow
6
+ v-if="$props.searchable || $slots.action"
7
+ :wrap="false"
8
+ align="center-left"
9
+ >
10
+ <FSSearchField
11
+ v-if="$props.searchable"
12
+ :hideHeader="true"
13
+ :modelValue="actualSearch"
14
+ @update:modelValue="onSearch"
15
+ />
16
+ <slot
17
+ name="action"
18
+ />
19
+ </FSRow>
11
20
  <FSFadeOut
12
21
  v-if="$props.direction == ListDirections.Column"
13
22
  :maxHeight="$props.maxHeight"
@@ -109,11 +118,13 @@ import FSFadeOut from "../FSFadeOut.vue";
109
118
  import FSSlideGroup from "../FSSlideGroup.vue"
110
119
  import FSSearchField from "../fields/FSSearchField.vue";
111
120
  import FSSimpleTileUI from "../tiles/FSSimpleTileUI.vue";
121
+ import FSRow from "../FSRow.vue";
112
122
 
113
123
  export default defineComponent({
114
124
  name: "FSTileList",
115
125
  components: {
116
126
  FSCol,
127
+ FSRow,
117
128
  FSFadeOut,
118
129
  FSLoader,
119
130
  FSSlideGroup,
@@ -223,6 +234,12 @@ export default defineComponent({
223
234
  actualSearch.value = value;
224
235
  });
225
236
 
237
+ watch(() => props.singleSelect, () => {
238
+ if(props.singleSelect && props.modelValue.length > 1) {
239
+ emit("update:modelValue", []);
240
+ }
241
+ });
242
+
226
243
  return {
227
244
  actualSearch,
228
245
  filteredItems,
@@ -47,30 +47,26 @@ export default {
47
47
  to: {
48
48
  type: Object as PropType<RouteLocation | null>,
49
49
  required: false
50
- },
51
- html: {
52
- type: String,
53
- required: false
54
50
  }
55
51
  },
56
52
  emits: ['click', 'auxclick'],
57
53
  setup(props, { emit }) {
58
54
  const map = inject<Ref<Map | null>>(MAP);
59
55
  const markerClusterGroup = inject<Ref<MarkerClusterGroup | null>>(MARKERCLUSTERGROUP, ref(null));
60
-
56
+
61
57
  const { getColors } = useColors();
62
58
  const { handleRoutingEvent } = useRouting();
63
59
 
64
- if (!map) {
60
+ if(!map) {
65
61
  throw new Error('FSMapTileLayer must be used inside a FSMap component');
66
62
  }
67
63
 
68
- if (!map.value) {
64
+ if(!map.value) {
69
65
  throw new Error('FSMapTileLayer must be used inside a FSMap component with a map');
70
66
  }
71
-
67
+
72
68
  const getMarkerIcon = () => {
73
- if (props.variant === 'gps') {
69
+ if(props.variant === 'gps') {
74
70
  const size = 16;
75
71
  return divIcon({
76
72
  html: gpsMarkerHtml(),
@@ -80,7 +76,7 @@ export default {
80
76
  });
81
77
  }
82
78
 
83
- if (props.variant === 'location') {
79
+ if(props.variant === 'location') {
84
80
  const size = 36;
85
81
  return divIcon({
86
82
  html: locationMarkerHtml(props.icon ?? "mdi-map-marker", getColors(props.color).base, props.label),
@@ -92,7 +88,7 @@ export default {
92
88
 
93
89
  const size = 16;
94
90
  return divIcon({
95
- html: props.html ?? pinMarkerHtml(getColors(props.color).base, props.label),
91
+ html: pinMarkerHtml(getColors(props.color).base, props.label),
96
92
  iconSize: [size, size],
97
93
  className: props.selected ? 'fs-map-marker fs-map-pin fs-map-pin-selected' : 'fs-map-marker fs-map-pin',
98
94
  iconAnchor: [size / 2, size / 2],
@@ -106,11 +102,11 @@ export default {
106
102
  });
107
103
 
108
104
  const onClick = (event: MouseEvent) => {
109
- if (props.to) {
105
+ if(props.to) {
110
106
  handleRoutingEvent(event, props.to, true);
111
107
  return;
112
108
  }
113
-
109
+
114
110
  emit('click', {
115
111
  ...event,
116
112
  latlng: props.latlng
@@ -118,7 +114,7 @@ export default {
118
114
  }
119
115
 
120
116
  const onAuxClick = (event: MouseEvent) => {
121
- if (props.to) {
117
+ if(props.to) {
122
118
  handleRoutingEvent(event, props.to);
123
119
  return;
124
120
  }
@@ -130,11 +126,11 @@ export default {
130
126
  }
131
127
 
132
128
  watch(map, () => {
133
- if (!map.value) {
129
+ if(!map.value) {
134
130
  return;
135
131
  }
136
132
 
137
- if (markerClusterGroup && markerClusterGroup.value) {
133
+ if(markerClusterGroup && markerClusterGroup.value) {
138
134
  actualMarker.value.addTo(markerClusterGroup.value);
139
135
  } else {
140
136
  actualMarker.value.addTo(map.value);
@@ -142,7 +138,7 @@ export default {
142
138
  }, { immediate: true });
143
139
 
144
140
  watch([() => props.variant, () => props.color, () => props.selected], () => {
145
- if (!actualMarker.value || !map.value) {
141
+ if(!actualMarker.value || !map.value) {
146
142
  return;
147
143
  }
148
144
 
@@ -151,7 +147,7 @@ export default {
151
147
  });
152
148
 
153
149
  watch([() => props.latlng?.lat, () => props.latlng?.lng], () => {
154
- if (!actualMarker.value || !map.value || !props.latlng) {
150
+ if(!actualMarker.value || !map.value || !props.latlng) {
155
151
  return;
156
152
  }
157
153
 
@@ -159,7 +155,7 @@ export default {
159
155
  });
160
156
 
161
157
  watch(markerElement, (newMarkerElement) => {
162
- if (!newMarkerElement) {
158
+ if(!newMarkerElement) {
163
159
  return;
164
160
  }
165
161
 
@@ -168,8 +164,8 @@ export default {
168
164
  }, { immediate: true });
169
165
 
170
166
  onUnmounted(() => {
171
- if (actualMarker.value && map.value) {
172
- if (markerClusterGroup && markerClusterGroup.value) {
167
+ if(actualMarker.value && map.value) {
168
+ if(markerClusterGroup && markerClusterGroup.value) {
173
169
  markerClusterGroup.value.removeLayer(actualMarker.value as Marker);
174
170
  } else {
175
171
  map.value.removeLayer(actualMarker.value as Marker);
@@ -0,0 +1,145 @@
1
+ <template>
2
+ <FSTile
3
+ :activeColor="ColorEnum.Primary"
4
+ :modelValue="$props.modelValue"
5
+ :width="$props.width"
6
+ :height="$props.height"
7
+ padding="16px 24px"
8
+ v-bind="$attrs"
9
+ >
10
+ <FSRow
11
+ :wrap="false"
12
+ >
13
+ <FSCol
14
+ gap="16px"
15
+ width="fill"
16
+ >
17
+ <FSText
18
+ font="text-button"
19
+ >
20
+ {{ $props.label }}
21
+ </FSText>
22
+ <FSRow
23
+ :wrap="false"
24
+ align="center-left"
25
+ >
26
+ <FSIcon>
27
+ mdi-view-dashboard-outline
28
+ </FSIcon>
29
+ <FSText
30
+ font="text-overline"
31
+ >
32
+ {{ $tr('ui.dashboards.dynamic', '{0} dashboard(s)', $props.dashboardsCount) }}
33
+ </FSText>
34
+ </FSRow>
35
+ <FSRow
36
+ :wrap="false"
37
+ align="center-left"
38
+ >
39
+ <FSIconCheck
40
+ variant="fill"
41
+ :value="automaticTransition"
42
+ />
43
+ <FSText
44
+ font="text-overline"
45
+ >
46
+ {{ automaticTransition
47
+ ? $tr('ui.playlist.transition-delay.dynamic', 'Transition : {0}', getTimeBestString($props.delay ?? 0))
48
+ : $tr('ui.playlist.automatic-transition', 'Automatic transition')
49
+ }}
50
+ </FSText>
51
+ </FSRow>
52
+ <FSRow
53
+ :wrap="false"
54
+ align="center-left"
55
+ >
56
+ <FSIconCheck
57
+ variant="fill"
58
+ :value="$props.looped"
59
+ />
60
+ <FSText
61
+ font="text-overline"
62
+ >
63
+ {{ $tr('entity.playlist.looped', 'Looped') }}
64
+ </FSText>
65
+ </FSRow>
66
+ </FSCol>
67
+ <slot
68
+ name="actions"
69
+ />
70
+ </FSRow>
71
+ </FSTile>
72
+ </template>
73
+
74
+ <script lang="ts">
75
+ import { computed, defineComponent, type PropType } from "vue";
76
+
77
+ import { ColorEnum } from "@dative-gpi/foundation-shared-components/models";
78
+
79
+ import { getTimeBestString } from "@dative-gpi/foundation-shared-components/utils";
80
+
81
+ import FSIconCheck from "../FSIconCheck.vue";
82
+ import FSTile from "../tiles/FSTile.vue";
83
+ import FSIcon from "../FSIcon.vue";
84
+ import FSText from "../FSText.vue";
85
+ import FSRow from "../FSRow.vue";
86
+ import FSCol from "../FSCol.vue";
87
+
88
+ export default defineComponent({
89
+ name: "FSPlaylistTileUI",
90
+ components: {
91
+ FSIconCheck,
92
+ FSIcon,
93
+ FSTile,
94
+ FSText,
95
+ FSRow,
96
+ FSCol
97
+ },
98
+ inheritAttrs: false,
99
+ props: {
100
+ width: {
101
+ type: [Array, String, Number] as PropType<string[] | number[] | string | number | null>,
102
+ required: false,
103
+ default: () => [352, 336]
104
+ },
105
+ height: {
106
+ type: [Array, String, Number] as PropType<string[] | number[] | string | number | null>,
107
+ required: false,
108
+ default: () => 'hug'
109
+ },
110
+ label: {
111
+ type: String as PropType<string>,
112
+ required: true
113
+ },
114
+ dashboardsCount: {
115
+ type: Number,
116
+ required: true
117
+ },
118
+ delay: {
119
+ type: Number ,
120
+ required: false
121
+ },
122
+ looped: {
123
+ type: Boolean,
124
+ required: true
125
+ },
126
+ modelValue: {
127
+ type: Boolean,
128
+ required: false,
129
+ default: false
130
+ }
131
+ },
132
+ setup(props) {
133
+
134
+ const automaticTransition = computed((): boolean => {
135
+ return props.delay ? props.delay > 0 : false;
136
+ });
137
+
138
+ return {
139
+ getTimeBestString,
140
+ automaticTransition,
141
+ ColorEnum
142
+ };
143
+ }
144
+ });
145
+ </script>
@@ -5,7 +5,6 @@ export * from "./useBreakpoints";
5
5
  export * from "./useColors";
6
6
  export * from "./useCountUp";
7
7
  export * from "./useDebounce";
8
- export * from "./useDynamicVNode";
9
8
  export * from "./useElementVisibility";
10
9
  export * from "./useMapLayers";
11
10
  export * from "./useRules";
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "url": "https://github.com/Dative-GPI/foundation-shared-ui.git"
5
5
  },
6
6
  "sideEffects": false,
7
- "version": "1.0.194-dynamic-v-node",
7
+ "version": "1.0.194-playlists-02",
8
8
  "description": "",
9
9
  "publishConfig": {
10
10
  "access": "public"
@@ -13,8 +13,8 @@
13
13
  "author": "",
14
14
  "license": "ISC",
15
15
  "dependencies": {
16
- "@dative-gpi/foundation-shared-domain": "1.0.194-dynamic-v-node",
17
- "@dative-gpi/foundation-shared-services": "1.0.194-dynamic-v-node"
16
+ "@dative-gpi/foundation-shared-domain": "1.0.194-playlists-02",
17
+ "@dative-gpi/foundation-shared-services": "1.0.194-playlists-02"
18
18
  },
19
19
  "peerDependencies": {
20
20
  "@dative-gpi/bones-ui": "^1.0.0",
@@ -38,5 +38,5 @@
38
38
  "sass": "1.71.1",
39
39
  "sass-loader": "13.3.2"
40
40
  },
41
- "gitHead": "bae28f289de25e748becbaf3e7d5f6c9bdc12934"
41
+ "gitHead": "aadd89bd31e3423781f48a258c89ababbbcb00cb"
42
42
  }
@@ -1,60 +0,0 @@
1
- import { uuidv4 } from "@dative-gpi/bones-ui";
2
- import { h, render, nextTick, getCurrentInstance, onBeforeUnmount, type Component, type VNode } from "vue";
3
-
4
- export function useDynamicVNode<TProps extends Record<string, any>>(component: Component) {
5
- const id = uuidv4();
6
-
7
- let vnode: VNode | null = null;
8
- let container: HTMLElement | null = null;
9
-
10
- const instance = getCurrentInstance();
11
- if (!instance) {
12
- throw new Error("useDynamicVNode must be used inside setup()");
13
- }
14
-
15
- const appContext = instance.appContext;
16
-
17
- const mount = async (props: TProps) => {
18
- await nextTick();
19
-
20
- const mountPoint = document.getElementById(id);
21
- if (!mountPoint) {
22
- return;
23
- }
24
-
25
- unmount();
26
-
27
- container = mountPoint;
28
-
29
- vnode = h(component, props);
30
- vnode.appContext = appContext;
31
-
32
- render(vnode, container);
33
- };
34
-
35
- const unmount = () => {
36
- if (container) {
37
- render(null, container);
38
- }
39
- vnode = null;
40
- container = null;
41
- };
42
-
43
- const sanitizeStyle = (style?: string): string =>
44
- style
45
- ? style.replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
46
- : "";
47
-
48
- const getHtml = (style?: string) => {
49
- const safeStyle = sanitizeStyle(style);
50
- return `<div id="${id}"${safeStyle ? ` style="${safeStyle}"` : ""}></div>`;
51
- };
52
-
53
- onBeforeUnmount(unmount);
54
-
55
- return {
56
- mount,
57
- unmount,
58
- getHtml
59
- };
60
- }