@ozdao/prometheus-framework 0.2.104 → 0.2.105

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/dist/main.css +1 -1
  2. package/dist/prometheus-framework/src/components/Block/Block.vue.cjs +1 -1
  3. package/dist/prometheus-framework/src/components/Block/Block.vue.js +1 -1
  4. package/dist/prometheus-framework/src/components/Tooltip/Tooltip.vue.cjs +1 -1
  5. package/dist/prometheus-framework/src/components/Tooltip/Tooltip.vue.js +1 -45
  6. package/dist/prometheus-framework/src/components/Tooltip/Tooltip.vue2.cjs +1 -1
  7. package/dist/prometheus-framework/src/components/Tooltip/Tooltip.vue2.js +45 -1
  8. package/dist/prometheus-framework/src/modules/backoffice/components/pages/Dashboard.vue.cjs +1 -1
  9. package/dist/prometheus-framework/src/modules/backoffice/components/pages/Dashboard.vue.js +1 -1
  10. package/dist/prometheus-framework/src/modules/community/components/sections/JoinUs.vue.cjs +1 -1
  11. package/dist/prometheus-framework/src/modules/community/components/sections/JoinUs.vue.js +43 -42
  12. package/dist/prometheus-framework/src/modules/globals/components/blocks/CardHeader.vue.cjs +1 -1
  13. package/dist/prometheus-framework/src/modules/globals/components/blocks/CardHeader.vue.js +1 -1
  14. package/dist/prometheus-framework/src/modules/landing/components/elements/FloatingImages.vue.cjs +21 -0
  15. package/dist/prometheus-framework/src/modules/landing/components/elements/FloatingImages.vue.js +81 -0
  16. package/dist/prometheus-framework/src/modules/landing/landing.client.cjs +1 -1
  17. package/dist/prometheus-framework/src/modules/landing/landing.client.js +4 -2
  18. package/dist/prometheus-framework/src/modules/legal/components/pages/Legal.vue.cjs +1 -1
  19. package/dist/prometheus-framework/src/modules/legal/components/pages/Legal.vue.js +1 -1
  20. package/dist/prometheus-framework/src/modules/mobile/components/Menu/Menu.vue.cjs +1 -1
  21. package/dist/prometheus-framework/src/modules/mobile/components/Menu/Menu.vue.js +13 -1
  22. package/dist/prometheus-framework/src/modules/mobile/components/Menu/Menu.vue2.cjs +1 -1
  23. package/dist/prometheus-framework/src/modules/mobile/components/Menu/Menu.vue2.js +1 -13
  24. package/dist/prometheus-framework/src/modules/organizations/components/pages/Members.vue.cjs +1 -1
  25. package/dist/prometheus-framework/src/modules/organizations/components/pages/Members.vue.js +2 -2
  26. package/dist/prometheus-framework/src/modules/organizations/components/pages/Organization.vue.cjs +1 -1
  27. package/dist/prometheus-framework/src/modules/organizations/components/pages/Organization.vue.js +1 -1
  28. package/dist/prometheus-framework/src/modules/users/components/pages/Profile.vue.cjs +1 -1
  29. package/dist/prometheus-framework/src/modules/users/components/pages/Profile.vue.js +1 -1
  30. package/dist/prometheus-framework/src/modules/wallet/views/components/pages/Wallet.vue.cjs +1 -1
  31. package/dist/prometheus-framework/src/modules/wallet/views/components/pages/Wallet.vue.js +1 -1
  32. package/dist/prometheus-framework.cjs.js +1 -1
  33. package/dist/prometheus-framework.es.js +36 -35
  34. package/dist/style.css +1 -1
  35. package/package.json +1 -1
  36. package/src/components/Marquee/Marquee.vue +356 -0
  37. package/src/components/index.js +2 -0
  38. package/src/modules/community/components/sections/JoinUs.vue +60 -105
  39. package/src/modules/landing/components/elements/FloatingImages.vue +124 -0
  40. package/src/modules/landing/landing.client.js +3 -0
@@ -0,0 +1,356 @@
1
+ <template>
2
+ <div
3
+ v-if="ready"
4
+ class="vue3-marquee"
5
+ :class="{ vertical: vertical, horizontal: !vertical }"
6
+ :style="getCurrentStyle"
7
+ :key="componentKey"
8
+ @mouseenter="hoverStarted"
9
+ @mouseleave="hoverEnded"
10
+ @mousedown="mouseDown"
11
+ @mouseup="mouseUp"
12
+ >
13
+ <div
14
+ class="transparent-overlay"
15
+ ref="marqueeOverlayContainer"
16
+ :aria-hidden="true"
17
+ :class="{ vertical: vertical, horizontal: !vertical, overlay: gradient }"
18
+ />
19
+
20
+ <div
21
+ class="marquee"
22
+ ref="marqueeContent">
23
+ <slot></slot>
24
+ </div>
25
+
26
+ <div
27
+ class="marquee"
28
+ :aria-hidden="true"
29
+ >
30
+ <slot></slot>
31
+ </div>
32
+
33
+ <div
34
+ v-for="num in cloneAmount"
35
+ :key="num"
36
+ :aria-hidden="true"
37
+ class="marquee cloned"
38
+ >
39
+ <slot></slot>
40
+ </div
41
+ >
42
+ </div>
43
+ </template>
44
+
45
+ <script setup>
46
+ import { ref, onMounted, onBeforeUnmount, computed, watch } from 'vue'
47
+
48
+ const props = defineProps({
49
+ vertical: { type: Boolean, default: false },
50
+ direction: { type: String, default: 'normal' },
51
+ duration: { type: Number, default: 20 },
52
+ delay: { type: Number, default: 0 },
53
+ loop: { type: Number, default: 0 },
54
+ clone: { type: Boolean, default: false },
55
+ gradient: { type: Boolean, default: false },
56
+ gradientColor: { type: Array, default: () => [255, 255, 255] },
57
+ gradientLength: { type: String },
58
+ pauseOnHover: { type: Boolean, default: false },
59
+ pauseOnClick: { type: Boolean, default: false },
60
+ pause: { type: Boolean, default: false }
61
+ })
62
+
63
+ const emits = defineEmits(['onComplete', 'onLoopComplete', 'onPause', 'onResume'])
64
+
65
+ const ready = ref(false)
66
+
67
+ const componentKey = ref(0)
68
+ const cloneAmount = ref(0)
69
+ const loopCounter = ref(0)
70
+ const loopInterval = ref(null)
71
+
72
+ const widthMin = ref('100%')
73
+ const widthContainer = ref(0)
74
+ const widthContent = ref(0)
75
+ const heightMin = ref('100%')
76
+ const heightContainer = ref(0)
77
+ const heightContent = ref(0)
78
+
79
+ const gradientLength = ref('200px')
80
+
81
+ const verticalAnimationPause = ref(false)
82
+ const marqueeContent = ref(null)
83
+ const marqueeOverlayContainer = ref(null)
84
+
85
+ const ForcesUpdate = async () => {
86
+ await checkForClone()
87
+ componentKey.value++
88
+ }
89
+
90
+ const checkForClone = async () => {
91
+ if (props.vertical) {
92
+ verticalAnimationPause.value = true
93
+ }
94
+
95
+ setInterval(() => {
96
+ widthMin.value = '0%'
97
+ heightMin.value = '0%'
98
+
99
+ if (marqueeContent.value !== null && marqueeOverlayContainer.value !== null) {
100
+ if (marqueeContent.value && marqueeOverlayContainer.value) {
101
+ if (
102
+ props.vertical &&
103
+ 'clientHeight' in marqueeContent.value &&
104
+ 'clientHeight' in marqueeOverlayContainer.value
105
+ ) {
106
+ heightContent.value = marqueeContent.value.clientHeight
107
+ heightContainer.value = marqueeOverlayContainer.value.clientHeight
108
+
109
+ const localCloneAmount = Math.ceil(heightContainer.value / heightContent.value)
110
+
111
+ cloneAmount.value = isFinite(localCloneAmount) ? localCloneAmount : 0
112
+
113
+ verticalAnimationPause.value = false
114
+
115
+ return cloneAmount.value
116
+ } else if (
117
+ !props.vertical &&
118
+ 'clientWidth' in marqueeContent.value &&
119
+ 'clientWidth' in marqueeOverlayContainer.value
120
+ ) {
121
+ widthContent.value = marqueeContent.value.clientWidth
122
+ widthContainer.value = marqueeOverlayContainer.value.clientWidth
123
+
124
+ const localCloneAmount = Math.ceil(widthContainer.value / widthContent.value)
125
+
126
+ cloneAmount.value = isFinite(localCloneAmount) ? localCloneAmount : 0
127
+
128
+ return cloneAmount.value
129
+ } else {
130
+ widthMin.value = '100%'
131
+ heightMin.value = '100%'
132
+ return 0
133
+ }
134
+ } else {
135
+ widthMin.value = '100%'
136
+ heightMin.value = '100%'
137
+ return 0
138
+ }
139
+ } else {
140
+ widthMin.value = '100%'
141
+ heightMin.value = '100%'
142
+ return 0
143
+ }
144
+ }, 100)
145
+ }
146
+
147
+ const hoverStarted = () => { if (props.pauseOnHover) emits('onPause') }
148
+ const hoverEnded = () => { if (props.pauseOnHover) emits('onResume') }
149
+ const mouseDown = () => { if (props.pauseOnClick) emits('onPause') }
150
+ const mouseUp = () => { if (props.pauseOnClick) emits('onResume') }
151
+
152
+ const getCurrentStyle = computed(() => {
153
+ return {
154
+ '--loops': `${props.loop === 0 ? 'infinite' : props.loop}`,
155
+ '--duration': `${props.duration}s`,
156
+ '--delay': `${props.delay}s`,
157
+ '--direction': `${props.direction}`,
158
+ '--pauseOnHover': `${props.pauseOnHover ? 'paused' : 'running'}`,
159
+ '--pauseOnClick': `${props.pauseOnClick ? 'paused' : 'running'}`,
160
+ '--pauseAnimation': `${(props.vertical && verticalAnimationPause.value) || props.pause ? 'paused' : 'running'}`,
161
+ '--gradient-color': `rgba(${props.gradientColor}, 1), rgba(${props.gradientColor}, 0)`,
162
+ '--gradient-length': `${gradientLength.value}`,
163
+ '--min-width': `${widthMin.value}`,
164
+ '--min-height': `${heightMin.value}`,
165
+ '--orientation': props.vertical ? 'scrollY' : 'scrollX'
166
+ }
167
+ })
168
+
169
+ const setupMarquee = async () => {
170
+ if (props.vertical) {
171
+ heightMin.value = '100%'
172
+ widthMin.value = 'auto'
173
+ } else {
174
+ heightMin.value = 'auto'
175
+ widthMin.value = '100%'
176
+ }
177
+
178
+ if (props.gradient && props.gradientLength) {
179
+ gradientLength.value = props.gradientLength
180
+ }
181
+
182
+ if (props.clone) {
183
+ await checkForClone()
184
+ ForcesUpdate()
185
+ ready.value = true
186
+ } else {
187
+ ready.value = true
188
+ }
189
+ }
190
+
191
+ onMounted(async () => {
192
+ setupMarquee()
193
+
194
+ loopInterval.value = setInterval(() => {
195
+ loopCounter.value++
196
+
197
+ if (props.loop !== 0 && loopCounter.value === props.loop) {
198
+ emits('onComplete')
199
+ clearInterval(loopInterval.value)
200
+ }
201
+
202
+ emits('onLoopComplete')
203
+ }, props.duration * 1000)
204
+ })
205
+
206
+ onBeforeUnmount(() => {
207
+ clearInterval(loopInterval.value)
208
+ })
209
+
210
+ watch(widthContent, async () => {
211
+ if (props.clone) {
212
+ ForcesUpdate()
213
+ }
214
+ })
215
+
216
+ watch(widthContainer, async () => {
217
+ if (props.clone) {
218
+ ForcesUpdate()
219
+ }
220
+ })
221
+
222
+ watch(
223
+ () => props.pause,
224
+ (newVal, oldVal) => {
225
+ if (newVal !== oldVal) {
226
+ if (newVal) {
227
+ emits('onResume')
228
+ } else {
229
+ emits('onPause')
230
+ }
231
+ }
232
+ }
233
+ )
234
+ </script>
235
+
236
+ <style lang="scss">
237
+ .vue3-marquee {
238
+ display: flex !important;
239
+ position: relative;
240
+
241
+ .marquee {
242
+ flex: 0 0 auto;
243
+ min-width: var(--min-width);
244
+ min-height: var(--min-height);
245
+ z-index: 1;
246
+
247
+ animation: var(--orientation) var(--duration) linear var(--delay) var(--loops);
248
+ animation-play-state: var(--pauseAnimation);
249
+ animation-direction: var(--direction);
250
+ }
251
+
252
+ .overlay {
253
+ position: absolute;
254
+ width: 100%;
255
+ height: 100%;
256
+
257
+ &:before {
258
+ left: 0;
259
+ top: 0;
260
+ }
261
+
262
+ &:before, &:after {
263
+ content: '';
264
+ position: absolute;
265
+ z-index: 2;
266
+ }
267
+ }
268
+
269
+ .transparent-overlay {
270
+ position: absolute;
271
+ width: 100.5%;
272
+ height: 100.5%;
273
+ }
274
+
275
+
276
+ &.horizontal {
277
+ overflow-x: hidden !important;
278
+ flex-direction: row !important;
279
+ width: 100%;
280
+ height: max-content;
281
+
282
+ .marquee {
283
+ display: flex;
284
+ flex-direction: row;
285
+ align-items: center;
286
+ }
287
+
288
+ .overlay::before,.overlay::after {
289
+ background: linear-gradient(to right, var(--gradient-color));
290
+ height: 100%;
291
+ width: var(--gradient-length);
292
+ }
293
+
294
+ .overlay::after {
295
+ transform: rotateZ(180deg);
296
+ right: 0;
297
+ top: 0;
298
+ }
299
+ }
300
+
301
+ &.vertical {
302
+ overflow-y: hidden !important;
303
+ flex-direction: column !important;
304
+ height: 100%;
305
+ width: max-content;
306
+
307
+ .marquee {
308
+ display: flex;
309
+ flex-direction: column;
310
+ align-items: center;
311
+ }
312
+
313
+ .overlay::before, .overlay::after {
314
+ background: linear-gradient(to bottom, var(--gradient-color));
315
+ height: var(--gradient-length);
316
+ width: 100%;
317
+ }
318
+
319
+ .overlay::after {
320
+ transform: rotateZ(-180deg);
321
+ left: 0;
322
+ bottom: 0;
323
+ }
324
+ }
325
+
326
+ &:hover {
327
+ div {
328
+ animation-play-state: var(--pauseOnHover);
329
+ }
330
+ }
331
+
332
+ &:active {
333
+ div {
334
+ animation-play-state: var(--pauseOnClick);
335
+ }
336
+ }
337
+ }
338
+
339
+ @keyframes scrollX {
340
+ 0% {
341
+ transform: translateX(0%);
342
+ }
343
+ 100% {
344
+ transform: translateX(-100%);
345
+ }
346
+ }
347
+
348
+ @keyframes scrollY {
349
+ 0% {
350
+ transform: translateY(0%);
351
+ }
352
+ 100% {
353
+ transform: translateY(-100%);
354
+ }
355
+ }
356
+ </style>
@@ -38,3 +38,5 @@ export { default as Shader } from './Shader/Shader.vue';
38
38
  export { default as Sidebar } from './Sidebar/Sidebar.vue';
39
39
  export { default as Slider } from './Slider/Slider.vue';
40
40
  export { default as Status } from './Status/Status.vue';
41
+
42
+ export { default as Marquee } from './Marquee/Marquee.vue';
@@ -1,121 +1,76 @@
1
1
  <template>
2
- <div class="pd-extra o-hidden w-100 container container-joinus">
3
- <div class="content">
4
- <span class="h0 mn-b-big">
5
- {{ userCount.toLocaleString() }}
6
- </span>
7
- <p class="w-m-33r t-center mn-b-small p-big">
8
- Together, we're shaping the future of the globals cannabis community.
9
- </p>
10
- <router-link :to="{name: 'Sign In'}" class="bg-black t-medium t-white button">
11
- Join Now
12
- </router-link>
13
- </div>
2
+ <div class="pd-extra o-hidden w-100 container container-joinus">
3
+ <div class="content">
4
+ <span class="h0 mn-b-big">
5
+ {{ userCount.toLocaleString() }}
6
+ </span>
7
+ <p class="w-m-33r t-center mn-b-small p-big">
8
+ Together, we're shaping the future of the globals cannabis community.
9
+ </p>
10
+ <router-link :to="{ name: 'Sign In' }" class="bg-black t-medium t-white button">
11
+ Join Now
12
+ </router-link>
14
13
  </div>
14
+ <FloatingImages
15
+ :container="'.container-joinus'"
16
+ :images="[
17
+ '/avatars/01.png',
18
+ '/avatars/02.png',
19
+ '/avatars/03.png',
20
+ '/avatars/04.png',
21
+ '/avatars/05.png',
22
+ '/avatars/06.png'
23
+ ]"
24
+ :config="{
25
+ size: '5rem',
26
+ square: true,
27
+ minDuration: 5,
28
+ maxDuration: 15,
29
+ spawnPoints: [10, 90],
30
+ animation: {
31
+ startOpacity: 0.1,
32
+ midOpacity: 1,
33
+ endOpacity: 0.0,
34
+ translateY: '-33vh'
35
+ },
36
+ class: 'my-custom-class'
37
+ }"
38
+
39
+ />
40
+ </div>
15
41
  </template>
16
42
 
17
- <style lang="scss">
18
- .container-joinus {
19
- display: flex;
20
- align-items: center;
21
- justify-content: center;
22
- height: 66%;
23
- position: relative;
24
-
25
- .content {
26
- display: flex;
27
- flex-direction: column;
28
- align-items: center;
29
- z-index: 2;
30
- }
31
- }
32
-
33
- .floating-image {
34
- position: absolute;
35
- bottom: 0;
36
- width: 5rem;
37
- height: 5rem;
38
- opacity: 1;
39
- animation: floatUp linear infinite;
40
- }
41
-
42
- @keyframes floatUp {
43
- 0% {
44
- transform: translateY(0);
45
- opacity: 0.1; // плавное появление
46
- }
47
- 10% {
48
- opacity: 1;
49
- }
50
- 50% {
51
- opacity: 1;
52
- }
53
- 90% {
54
- opacity: 1;
55
- }
56
- 100% {
57
- transform: translateY(-33vh); // движение вверх на высоту экрана
58
- opacity: 0.0
59
- }
60
- }
61
-
62
- </style>
63
-
64
43
  <script setup>
65
- import { ref, onMounted, nextTick } from 'vue';
44
+ import { ref, onMounted } from 'vue';
66
45
 
67
- const userCount = ref(1230); // начальное значение
68
-
69
- const images = ref([
70
- '/avatars/01.png',
71
- '/avatars/02.png',
72
- '/avatars/03.png',
73
- '/avatars/04.png',
74
- '/avatars/05.png',
75
- '/avatars/06.png'
76
- ]);
46
+ import FloatingImages from '@pf/src/modules/landing/components/elements/FloatingImages.vue';
77
47
 
48
+ const userCount = ref(1230);
78
49
 
79
50
  const increaseUserCount = () => {
80
- setInterval(() => {
81
- userCount.value += Math.floor(Math.random() * 2) + 1; // случайное увеличение от 1 до 5
82
- }, 1330); // каждые 0.33 секунды,95
83
- };
84
-
85
-
86
- const config = {
87
- minSize: '6rem',
88
- maxSize: '10rem',
89
- minDuration: 5,
90
- maxDuration: 15,
91
- spawnPoints: [10, 90]
51
+ setInterval(() => {
52
+ userCount.value += Math.floor(Math.random() * 2) + 1;
53
+ }, 1330);
92
54
  };
93
55
 
94
56
  onMounted(() => {
95
- createFloatingImages();
96
- increaseUserCount();
57
+ increaseUserCount();
97
58
  });
59
+ </script>
98
60
 
99
- const createFloatingImages = () => {
100
- images.value.forEach((imageSrc, index) => {
101
- let imgElement = document.createElement('img');
102
- imgElement.src = imageSrc;
103
- imgElement.classList.add('floating-image');
104
- // imgElement.style.width = `${Math.random() * (parseFloat(config.maxSize) - parseFloat(config.minSize)) + parseFloat(config.minSize)}rem`;
105
-
106
- let spawnPoint = config.spawnPoints[Math.floor(Math.random() * config.spawnPoints.length)];
107
- let deviation = (Math.random() - 0.5) * 2 * 10; // случайное отклонение от -10% до 10%
108
- imgElement.style.left = `${spawnPoint + deviation}%`;
109
-
110
- imgElement.style.animationDuration = `${Math.random() * (config.maxDuration - config.minDuration) + config.minDuration}s`;
111
-
112
- document.querySelector('.container').appendChild(imgElement);
61
+ <style lang="scss">
62
+ .container-joinus {
63
+ display: flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ height: 66%;
67
+ position: relative;
113
68
 
114
- imgElement.addEventListener("animationiteration", () => {
115
- const newSpawnPoint = config.spawnPoints[Math.floor(Math.random() * config.spawnPoints.length)];
116
- const newDeviation = (Math.random() - 0.5) * 2 * 10; // новое случайное отклонение от -10% до 10%
117
- imgElement.style.left = `${newSpawnPoint + newDeviation}%`;
118
- });
119
- });
69
+ .content {
70
+ display: flex;
71
+ flex-direction: column;
72
+ align-items: center;
73
+ z-index: 2;
74
+ }
120
75
  }
121
- </script>
76
+ </style>
@@ -0,0 +1,124 @@
1
+ <template>
2
+ </template>
3
+
4
+ <script setup>
5
+ import { ref, onMounted, nextTick } from 'vue';
6
+
7
+ const props = defineProps({
8
+ container: {
9
+ type: String,
10
+ required: true
11
+ },
12
+ images: {
13
+ type: Array,
14
+ required: true
15
+ },
16
+ config: {
17
+ type: Object,
18
+ required: true,
19
+ default: () => ({
20
+ sizeMin: null,
21
+ sizeMax: null,
22
+ size: '5rem',
23
+ minDuration: 5,
24
+ maxDuration: 15,
25
+ spawnPoints: [10, 90],
26
+ maintainAspectRatio: true,
27
+ animation: {
28
+ startOpacity: 0.1,
29
+ midOpacity: 1,
30
+ endOpacity: 0.0,
31
+ translateY: '-33vh'
32
+ },
33
+ class: ''
34
+ })
35
+ },
36
+ });
37
+
38
+ const getRandomSize = (sizeMin, sizeMax) => {
39
+ const units = sizeMin.replace(/[0-9.]/g, '');
40
+ const min = parseFloat(sizeMin);
41
+ const max = parseFloat(sizeMax);
42
+ const randomSize = Math.random() * (max - min) + min;
43
+ return `${randomSize}${units}`;
44
+ };
45
+
46
+ const createKeyframes = (animation) => {
47
+ const styleSheet = document.styleSheets[0];
48
+ const keyframes = `
49
+ @keyframes floatUp {
50
+ 0% {
51
+ transform: translateY(0);
52
+ opacity: ${animation.startOpacity};
53
+ }
54
+ 10% {
55
+ opacity: ${animation.midOpacity};
56
+ }
57
+ 50% {
58
+ opacity: ${animation.midOpacity};
59
+ }
60
+ 90% {
61
+ opacity: ${animation.midOpacity};
62
+ }
63
+ 100% {
64
+ transform: translateY(${animation.translateY});
65
+ opacity: ${animation.endOpacity};
66
+ }
67
+ }
68
+ `;
69
+ styleSheet.insertRule(keyframes, styleSheet.cssRules.length);
70
+ };
71
+
72
+ const createFloatingImages = () => {
73
+ createKeyframes(props.config.animation);
74
+
75
+ props.images.forEach((imageSrc) => {
76
+ let imgElement = document.createElement('img');
77
+
78
+ imgElement.src = imageSrc;
79
+ imgElement.classList.add('floating-image');
80
+ if (props.config.class) {
81
+ imgElement.classList.add(props.config.class);
82
+ }
83
+
84
+ let spawnPoint = props.config.spawnPoints[Math.floor(Math.random() * props.config.spawnPoints.length)];
85
+ let deviation = (Math.random() - 0.5) * 2 * 10;
86
+
87
+ imgElement.style.left = `${spawnPoint + deviation}%`;
88
+
89
+ let width, height;
90
+
91
+ if (props.config.sizeMin && props.config.sizeMax) {
92
+ width = getRandomSize(props.config.sizeMin, props.config.sizeMax);
93
+ } else {
94
+ width = props.config.size;
95
+ }
96
+
97
+ if (props.config.square) {
98
+ height = width;
99
+ } else {
100
+ height = 'auto';
101
+ }
102
+
103
+ imgElement.style.width = width;
104
+ imgElement.style.height = height;
105
+ imgElement.style.position = 'absolute';
106
+ imgElement.style.bottom = '0';
107
+ imgElement.style.opacity = '1';
108
+ imgElement.style.animation = `floatUp linear infinite`;
109
+ imgElement.style.animationDuration = `${Math.random() * (props.config.maxDuration - props.config.minDuration) + props.config.minDuration}s`;
110
+
111
+ document.querySelector(props.container).appendChild(imgElement);
112
+
113
+ imgElement.addEventListener("animationiteration", () => {
114
+ const newSpawnPoint = props.config.spawnPoints[Math.floor(Math.random() * props.config.spawnPoints.length)];
115
+ const newDeviation = (Math.random() - 0.5) * 2 * 10;
116
+ imgElement.style.left = `${newSpawnPoint + newDeviation}%`;
117
+ });
118
+ });
119
+ };
120
+
121
+ onMounted(() => {
122
+ createFloatingImages();
123
+ });
124
+ </script>
@@ -2,7 +2,10 @@
2
2
  import MobileApp from './components/sections/MobileApp.vue';
3
3
  import SectionFeatures from './components/sections/SectionFeatures.vue';
4
4
 
5
+ import FloatingImages from './components/elements/FloatingImages.vue';
6
+
5
7
  export {
6
8
  MobileApp,
9
+ FloatingImages,
7
10
  SectionFeatures
8
11
  };