@energie360/ui-library 1.0.0 → 1.1.0

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.
@@ -3,14 +3,14 @@ import { computed } from 'vue'
3
3
  import { UIcon } from '../../elements'
4
4
 
5
5
  interface Props {
6
- icon: string
6
+ icon?: string
7
7
  label?: string
8
8
  href?: string
9
9
  target?: string
10
10
  active?: boolean
11
11
  }
12
12
 
13
- const { label = '', href = '', target = '', active = false } = defineProps<Props>()
13
+ const { icon = null, label = '', href = '', target = '', active = false } = defineProps<Props>()
14
14
 
15
15
  const tag = computed(() => {
16
16
  return href ? 'a' : 'span'
@@ -19,7 +19,7 @@ const tag = computed(() => {
19
19
 
20
20
  <template>
21
21
  <component :is="tag" class="context-menu-link" :class="{ active }" :href :target>
22
- <UIcon :name="icon" />
22
+ <UIcon v-if="icon" :name="icon" />
23
23
  <slot>{{ label }}</slot>
24
24
  </component>
25
25
  </template>
@@ -18,6 +18,10 @@
18
18
  }
19
19
  }
20
20
 
21
+ .data-card__main {
22
+ position: relative;
23
+ }
24
+
21
25
  .data-card__aside-column {
22
26
  float: right;
23
27
  margin-left: var(--e-space-2);
@@ -1,5 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  // TODO: add possibility to add items via slot
3
+ import { hasSlotContent } from '../../utils/vue/helpers'
4
+
3
5
  interface dataItem {
4
6
  heading: string
5
7
  value: string
@@ -16,7 +18,7 @@ defineProps<Props>()
16
18
  <template>
17
19
  <div class="data-card">
18
20
  <div class="data-card__main">
19
- <div v-if="$slots.aside" class="data-card__aside-column">
21
+ <div v-if="hasSlotContent($slots.aside)" class="data-card__aside-column">
20
22
  <slot name="aside" />
21
23
  </div>
22
24
 
@@ -34,7 +36,7 @@ defineProps<Props>()
34
36
  </dl>
35
37
  </div>
36
38
 
37
- <div v-if="$slots.ctas" class="data-card__ctas">
39
+ <div v-if="hasSlotContent($slots.ctas)" class="data-card__ctas">
38
40
  <slot name="ctas" />
39
41
  </div>
40
42
  </div>
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
2
  import { hasSlotContent } from '../../utils/vue/helpers'
3
3
  import { Image } from '../../elements/types'
4
+ import { assetsPath } from '../../globals'
4
5
 
5
6
  interface Props {
6
7
  title?: string
@@ -8,7 +9,7 @@ interface Props {
8
9
  image?: Image
9
10
  }
10
11
 
11
- const { image = { src: '/static/ui-assets/images/search.svg', alt: '' } } = defineProps<Props>()
12
+ const { image = { src: `${assetsPath}images/search.svg`, alt: '' } } = defineProps<Props>()
12
13
  </script>
13
14
 
14
15
  <template>
@@ -6,6 +6,7 @@ import { getTranslation } from '../../utils/translations/translate'
6
6
  import { mimeTypes } from '../../utils/global/mime-types'
7
7
  import { intersect } from '../../utils/array/intersect'
8
8
  import { ref, computed, useTemplateRef, useId } from 'vue'
9
+ import { assetsPath } from '../../globals'
9
10
 
10
11
  interface Props {
11
12
  accept?: string[]
@@ -171,17 +172,17 @@ const onRemoveError = (filename: string, lastModified: number) => {
171
172
  />
172
173
 
173
174
  <div v-if="dragover" class="file-upload__drop-zone-inner-drag">
174
- <img src="/static/ui-assets/images/doc-upload-inverted.svg" alt="" />
175
+ <img :src="`${assetsPath}images/doc-upload-inverted.svg`" alt="" />
175
176
  </div>
176
177
 
177
178
  <div class="file-upload__drop-zone-inner">
178
179
  <img
179
180
  v-if="uploadDisabled"
180
181
  class="no-select"
181
- src="/static/ui-assets/images/doc-upload-disabled.svg"
182
+ :src="`${assetsPath}images/doc-upload-disabled.svg`"
182
183
  alt=""
183
184
  />
184
- <img v-else class="no-select" src="/static/ui-assets/images/doc-upload.svg" alt="" />
185
+ <img v-else class="no-select" :src="`${assetsPath}images/doc-upload.svg`" alt="" />
185
186
  <p class="no-select type-300-strong label">
186
187
  {{ getTranslation('dragFileHereOr') }}
187
188
  </p>
@@ -76,3 +76,4 @@ export { default as UCardStatistic } from './card-statistic/u-card-statistic.vue
76
76
  export { default as UEmpty } from './empty/u-empty.vue'
77
77
  export { default as UButtonGroup } from './button-group/u-button-group.vue'
78
78
  export { default as UPortalLogo } from './portal-logo/u-portal-logo.vue'
79
+ export { default as UTeaserCard } from './teaser-card/u-teaser-card.vue'
@@ -76,3 +76,4 @@ export { default as UCardStatistic } from './card-statistic/u-card-statistic.vue
76
76
  export { default as UEmpty } from './empty/u-empty.vue'
77
77
  export { default as UButtonGroup } from './button-group/u-button-group.vue'
78
78
  export { default as UPortalLogo } from './portal-logo/u-portal-logo.vue'
79
+ export { default as UTeaserCard } from './teaser-card/u-teaser-card.vue'
@@ -2,6 +2,7 @@
2
2
  import { DotLottieVue, setWasmUrl } from '@lottiefiles/dotlottie-vue'
3
3
  import wasmUrl from '@lottiefiles/dotlottie-web/dist/dotlottie-player.wasm?url'
4
4
  import { ref, onMounted, useTemplateRef } from 'vue'
5
+ import { assetsPath } from '../../globals'
5
6
 
6
7
  interface Props {
7
8
  emptyText: string
@@ -41,7 +42,7 @@ onMounted(() => {
41
42
  <DotLottieVue
42
43
  autoplay
43
44
  loop
44
- src="/static/ui-assets/lottie/notification-empty.lottie"
45
+ :src="`${assetsPath}lottie/notification-empty.lottie`"
45
46
  style="height: 100%; width: 100%"
46
47
  />
47
48
  </div>
@@ -1,5 +1,6 @@
1
1
  <script setup lang="ts">
2
2
  import { Image } from '../../elements/types'
3
+ import { assetsPath } from '../../globals'
3
4
 
4
5
  interface Props {
5
6
  logoImage?: Image
@@ -12,11 +13,11 @@ interface Props {
12
13
 
13
14
  const {
14
15
  logoImage = {
15
- src: '/static/ui-assets/images/logo-white.svg',
16
+ src: `${assetsPath}images/logo-white.svg`,
16
17
  alt: 'Logo Energie 360°',
17
18
  },
18
19
  logoMinifiedImage = {
19
- src: '/static/ui-assets/images/logo-short-inverted.svg',
20
+ src: `${assetsPath}images/logo-short-inverted.svg`,
20
21
  alt: 'Logo Energie 360°',
21
22
  },
22
23
  } = defineProps<Props>()
@@ -0,0 +1,34 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .teaser-card {
4
+ padding: var(--e-space-4);
5
+ background-color: var(--e-c-mono-50);
6
+ border-radius: var(--e-brd-radius-3);
7
+ }
8
+
9
+ .teaser-card__image {
10
+ width: 100%;
11
+ border-radius: var(--e-brd-radius-2);
12
+ overflow: hidden;
13
+ margin-bottom: var(--e-space-4);
14
+
15
+ > * {
16
+ object-fit: cover;
17
+ width: 100%;
18
+ }
19
+ }
20
+
21
+ .teaser-card__title {
22
+ @include a.type(300, strong);
23
+
24
+ margin-bottom: var(--e-space-3);
25
+ }
26
+
27
+ .teaser-card__text {
28
+ @include a.type(200);
29
+ }
30
+
31
+ .teaser-card__cta {
32
+ margin-top: var(--e-space-6);
33
+ display: grid;
34
+ }
@@ -0,0 +1,46 @@
1
+ <script setup lang="ts">
2
+ import { Cta, Image } from '../../elements/types'
3
+ import { hasSlotContent } from '../../utils/vue/helpers'
4
+ import { UButton } from '../../elements'
5
+
6
+ interface Props {
7
+ image?: Image
8
+ text?: string
9
+ title?: string
10
+ cta?: Cta
11
+ }
12
+
13
+ const { image = null, title = '', text = '', cta = null } = defineProps<Props>()
14
+ </script>
15
+
16
+ <template>
17
+ <div class="teaser-card">
18
+ <div v-if="hasSlotContent($slots.image) || image" class="teaser-card__image">
19
+ <slot name="image">
20
+ <img :src="image.src" :alt="image.alt" />
21
+ </slot>
22
+ </div>
23
+
24
+ <div v-if="hasSlotContent($slots.title) || title" class="teaser-card__title">
25
+ <slot name="title">
26
+ {{ title }}
27
+ </slot>
28
+ </div>
29
+
30
+ <div v-if="hasSlotContent($slots.text) || text" class="teaser-card__text">
31
+ <slot name="text">
32
+ {{ text }}
33
+ </slot>
34
+ </div>
35
+
36
+ <div v-if="hasSlotContent($slots.cta) || cta" class="teaser-card__cta">
37
+ <slot name="cta">
38
+ <UButton variant="outlined" :href="cta.href" :target="cta.target">
39
+ {{ cta.label }}
40
+ </UButton>
41
+ </slot>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <style scoped lang="scss" src="./teaser-card.scss"></style>
@@ -0,0 +1,32 @@
1
+ @use '../../base/abstracts' as a;
2
+ @use '../button/button-base' as b;
3
+
4
+ .button-tile {
5
+ display: flex;
6
+ justify-content: space-between;
7
+ column-gap: var(--e-space-2);
8
+ line-height: 0;
9
+ width: 100%;
10
+ padding: var(--e-space-4);
11
+ border-radius: var(--e-brd-radius-2);
12
+ border-width: 2px;
13
+ border-style: solid;
14
+ min-height: a.rem(60);
15
+
16
+ &.valign-center {
17
+ align-items: center;
18
+ }
19
+ }
20
+
21
+ .button-tile__label {
22
+ @include a.type(100, strong);
23
+ }
24
+
25
+ .button-tile__text {
26
+ @include a.type(100);
27
+ }
28
+
29
+ .button-tile__left {
30
+ display: flex;
31
+ flex-direction: column;
32
+ }
@@ -0,0 +1,58 @@
1
+ <script setup lang="ts">
2
+ import { hasSlotContent } from '../../utils/vue/helpers'
3
+ import { UIcon } from '../'
4
+
5
+ interface Props {
6
+ label?: string
7
+ text?: string
8
+ href?: string
9
+ target?: string
10
+ icon?: string
11
+ backgroundColor?: string
12
+ borderColor?: string
13
+ color?: string
14
+ vAlign?: 'top' | 'center'
15
+ }
16
+
17
+ const {
18
+ label = null,
19
+ text = '',
20
+ href = '',
21
+ target = '_blank',
22
+ icon = '',
23
+ backgroundColor = 'var(--e-c-mono-00)',
24
+ color = 'var(--e-c-mono-900)',
25
+ borderColor = 'var(--e-c-mono-500)',
26
+ vAlign = 'top',
27
+ } = defineProps<Props>()
28
+ </script>
29
+
30
+ <template>
31
+ <component
32
+ :is="href ? 'a' : 'button'"
33
+ :class="['button-tile', `valign-${vAlign}`]"
34
+ :style="{ color, backgroundColor, borderColor }"
35
+ :href
36
+ :target
37
+ >
38
+ <span class="button-tile__left">
39
+ <span v-if="hasSlotContent($slots.label) || label" class="button-tile__label">
40
+ <slot name="label">
41
+ {{ label }}
42
+ </slot>
43
+ </span>
44
+
45
+ <span v-if="hasSlotContent($slots.text) || label" class="button-tile__text">
46
+ <slot name="text">
47
+ {{ text }}
48
+ </slot>
49
+ </span>
50
+ </span>
51
+
52
+ <span v-if="icon" class="button-tile__right">
53
+ <UIcon :name="icon" />
54
+ </span>
55
+ </component>
56
+ </template>
57
+
58
+ <style scoped lang="scss" src="./button-tile.scss"></style>
@@ -0,0 +1,18 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .button-tiles {
4
+ container-type: inline-size;
5
+
6
+ @container (width > 342px) {
7
+ .button-tiles__inner {
8
+ grid-template-columns: 1fr 1fr;
9
+ }
10
+ }
11
+ }
12
+
13
+ .button-tiles__inner {
14
+ display: grid;
15
+ column-gap: var(--e-space-3);
16
+ row-gap: var(--e-space-4);
17
+ grid-template-columns: 1fr;
18
+ }
@@ -0,0 +1,11 @@
1
+ <script setup lang="ts"></script>
2
+
3
+ <template>
4
+ <div class="button-tiles">
5
+ <div class="button-tiles__inner">
6
+ <slot />
7
+ </div>
8
+ </div>
9
+ </template>
10
+
11
+ <style scoped lang="scss" src="./button-tiles.scss"></style>
package/elements/index.js CHANGED
@@ -22,3 +22,5 @@ export { default as UToggleSwitch } from './toggle-switch/u-toggle-switch.vue'
22
22
  export { default as UCheckbox } from './checkbox/u-checkbox.vue'
23
23
  export { default as USelectTile } from './select-tile/u-select-tile.vue'
24
24
  export { default as USelectTiles } from './select-tiles/u-select-tiles.vue'
25
+ export { default as UButtonTile } from './button-tile/u-button-tile.vue'
26
+ export { default as UButtonTiles } from './button-tiles/u-button-tiles.vue'
package/elements/index.ts CHANGED
@@ -22,3 +22,5 @@ export { default as UToggleSwitch } from './toggle-switch/u-toggle-switch.vue'
22
22
  export { default as UCheckbox } from './checkbox/u-checkbox.vue'
23
23
  export { default as USelectTile } from './select-tile/u-select-tile.vue'
24
24
  export { default as USelectTiles } from './select-tiles/u-select-tiles.vue'
25
+ export { default as UButtonTile } from './button-tile/u-button-tile.vue'
26
+ export { default as UButtonTiles } from './button-tiles/u-button-tiles.vue'
@@ -1,7 +1,11 @@
1
+ <script setup lang="ts">
2
+ import { assetsPath } from '../../globals'
3
+ </script>
4
+
1
5
  <template>
2
6
  <div class="spectro">
3
7
  <div class="inner">
4
- <img src="/static/ui-assets/images/spectro.svg" alt="" aria-hidden="true" />
8
+ <img :src="`${assetsPath}images/spectro.svg`" alt="" aria-hidden="true" />
5
9
  </div>
6
10
  </div>
7
11
  </template>
@@ -55,4 +55,77 @@
55
55
  top: 0;
56
56
  }
57
57
  }
58
+
59
+ // Modifiers
60
+
61
+ // This is currently a 'quick' solution for the sicherheit-webapp.
62
+ // Will probably need some refinement if we want to use this for general usage.
63
+ &.inverted {
64
+ .suffix-action,
65
+ .prefix-icon {
66
+ color: var(--e-c-mono-00);
67
+ }
68
+
69
+ .control {
70
+ input {
71
+ color: var(--e-c-mono-00);
72
+ background-color: var(--e-c-primary-01-900);
73
+
74
+ &::placeholder {
75
+ color: var(--e-c-mono-500);
76
+ }
77
+
78
+ &:disabled::placeholder {
79
+ color: var(--e-c-mono-500);
80
+ }
81
+ }
82
+ }
83
+
84
+ .label {
85
+ background-color: var(--e-c-primary-01-900);
86
+ color: var(--e-c-mono-00);
87
+ }
88
+
89
+ .help-text {
90
+ color: var(--e-c-mono-00);
91
+ }
92
+
93
+ &.focus.float-label .label {
94
+ color: var(--e-c-mono-00);
95
+ }
96
+
97
+ &.float-label .label {
98
+ background-color: transparent;
99
+ background-image: linear-gradient(
100
+ 0deg,
101
+ var(--e-c-primary-01-900) 55%,
102
+ rgb(255 255 255 / 0%) 45%
103
+ );
104
+ }
105
+
106
+ .cancel-search {
107
+ color: var(--e-c-mono-00);
108
+ }
109
+
110
+ .control-border {
111
+ border-color: var(--e-c-primary-01-900);
112
+ }
113
+
114
+ &.hover,
115
+ &.focus {
116
+ .control-border {
117
+ border-color: var(--e-c-mono-00);
118
+ }
119
+ }
120
+ }
121
+
122
+ // This is currently a 'quick' solution for the sicherheit-webapp.
123
+ // Will probably need some refinement if we want to use this for general usage.
124
+ &.larger {
125
+ .control {
126
+ input {
127
+ height: a.rem(64);
128
+ }
129
+ }
130
+ }
58
131
  }
@@ -12,6 +12,8 @@ interface Props extends FormFieldBase {
12
12
  placeholder?: string
13
13
  readonly?: boolean
14
14
  unit?: string
15
+ inverted?: boolean
16
+ larger?: boolean
15
17
  }
16
18
 
17
19
  const inputId = useId()
@@ -133,6 +135,8 @@ watch(model, () => {
133
135
  'has-error': error,
134
136
  'show-help-text': hasHelpText,
135
137
  'has-cta': hasSlotContent($slots.cta),
138
+ inverted,
139
+ larger,
136
140
  },
137
141
  type,
138
142
  ]"
package/globals.js CHANGED
@@ -5,4 +5,7 @@
5
5
  // The library shouldn't rely on any specific build tools, like vite. That's why we shouldn't use `import.meta.env.DEV`.
6
6
  // TODO: Find a more 'generic' way to set an environment variable when using/developing the library.
7
7
  // In the meantime we'll just use this fixed path for the ui-assets.
8
- export const assetsPath = '/static/ui-assets/'
8
+
9
+ const assetsPathPrefix = import.meta.env.VITE_ASSETS_PATH_PREFIX || ''
10
+
11
+ export const assetsPath = assetsPathPrefix + '/static/ui-assets/'
@@ -4,6 +4,7 @@ import { useTemplateRef, ref } from 'vue'
4
4
  import butterflySpritePositions from './butterfly-sprite.json'
5
5
  import butterflySprite from './butterfly-sprite.png'
6
6
  import { gsap } from 'gsap'
7
+ import { assetsPath } from '../../globals'
7
8
 
8
9
  const butterfly = useTemplateRef('butterfly')
9
10
  const butterflyWrapper = useTemplateRef('butterflyWrapper')
@@ -70,7 +71,7 @@ const onMousemove = (e: MouseEvent) => {
70
71
  @ready="onSpriteReady"
71
72
  />
72
73
  </div>
73
- <img src="/static/ui-assets/images/forest.png" alt="" />
74
+ <img :src="`${assetsPath}images/forest.png`" alt="" />
74
75
  </div>
75
76
  </div>
76
77
  </template>
@@ -4,6 +4,7 @@ import { UContextMenu } from '../../components'
4
4
  import { Image } from '../../elements/types'
5
5
  import { ref, watch, useTemplateRef } from 'vue'
6
6
  import { hasSlotContent } from '../../utils/vue/helpers'
7
+ import { assetsPath } from '../../globals'
7
8
 
8
9
  interface MenuButton {
9
10
  icon: string
@@ -24,11 +25,11 @@ interface Props {
24
25
  const {
25
26
  collapsed = false,
26
27
  logoImage = {
27
- src: '/static/ui-assets/images/logo-white.svg',
28
+ src: `${assetsPath}images/logo-white.svg`,
28
29
  alt: 'Logo Energie 360°',
29
30
  },
30
31
  logoMinifiedImage = {
31
- src: '/static/ui-assets/images/logo-short-inverted.svg',
32
+ src: `${assetsPath}images/logo-short-inverted.svg`,
32
33
  alt: 'Logo Energie 360°',
33
34
  },
34
35
  logoLink = {
@@ -5,10 +5,12 @@ import { UContextMenu } from '../../components'
5
5
  import { Image } from '../../elements/types'
6
6
  import { getTranslation } from '../../utils/translations/translate'
7
7
  import { ref, watch, useTemplateRef, onUnmounted } from 'vue'
8
+ import { assetsPath } from '../../globals'
8
9
 
9
10
  interface MenuButton {
10
11
  icon: string
11
12
  label: string
13
+ showLabel?: boolean
12
14
  }
13
15
 
14
16
  interface Props {
@@ -18,11 +20,12 @@ interface Props {
18
20
  }
19
21
  menuButton: MenuButton
20
22
  logoImage?: Image
23
+ hideBurger?: boolean
21
24
  }
22
25
 
23
26
  const {
24
27
  logoImage = {
25
- src: '/static/ui-assets/images/logo-short-inverted.svg',
28
+ src: `${assetsPath}images/logo-short-inverted.svg`,
26
29
  alt: 'Logo Energie 360°',
27
30
  },
28
31
  logoLink = {
@@ -115,15 +118,21 @@ onUnmounted(() => {
115
118
  </div>
116
119
 
117
120
  <div class="navigation-toolbar-top__top-bar-ctas">
118
- <UContextMenu placement="bottom-full">
121
+ <UContextMenu v-if="menuButton" placement="bottom-full">
119
122
  <template #trigger="{ isOpen }">
120
- <UNavigationToolbarLink v-bind="menuButton" collapsed label-hidden :active="isOpen" />
123
+ <UNavigationToolbarLink
124
+ v-bind="menuButton"
125
+ :collapsed="!menuButton.showLabel"
126
+ label-hidden
127
+ :active="isOpen"
128
+ />
121
129
  </template>
122
130
 
123
131
  <slot name="contextMenuLinks"></slot>
124
132
  </UContextMenu>
125
133
 
126
134
  <UNavigationToolbarLink
135
+ v-if="!hideBurger"
127
136
  icon="menu"
128
137
  :label="getTranslation('openMenu')"
129
138
  collapsed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energie360/ui-library",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -42,6 +42,7 @@
42
42
  "dependencies": {
43
43
  "@lottiefiles/dotlottie-vue": "^0.10.14",
44
44
  "@lottiefiles/dotlottie-web": "^0.62.0",
45
+ "@tsparticles/confetti": "^3.9.1",
45
46
  "gsap": "^3.14.2",
46
47
  "@energie360/design-tokens": "^1.3.0"
47
48
  },
@@ -1,23 +1,82 @@
1
1
  <script setup lang="ts">
2
2
  import { Image, Cta } from '../../elements/types'
3
3
  import { UButton } from '../../elements'
4
- import { computed, useSlots } from 'vue'
4
+ import { computed, onMounted, useSlots } from 'vue'
5
+ import { confetti as confettiFn } from '@tsparticles/confetti'
5
6
 
6
7
  interface Props {
7
8
  title?: string
8
9
  text?: string
9
10
  image?: Image
10
-
11
11
  cta?: Cta
12
+ confetti?: boolean
12
13
  }
13
14
 
14
- const { text = '', image = undefined, cta = undefined, title = '' } = defineProps<Props>()
15
+ const {
16
+ text = '',
17
+ image = undefined,
18
+ cta = undefined,
19
+ title = '',
20
+ confetti = false,
21
+ } = defineProps<Props>()
15
22
 
16
23
  const slots = useSlots()
17
24
 
18
25
  const hasCta = computed(() => !!slots.cta || cta)
19
26
 
20
27
  const hasText = computed(() => !!slots.text || text)
28
+
29
+ const randomInRange = (min, max) => {
30
+ return Math.random() * (max - min) + min
31
+ }
32
+
33
+ const makeConfetti = async () => {
34
+ const duration = 4 * 1000
35
+ const animationEnd = Date.now() + duration
36
+ const defaults = {
37
+ startVelocity: 30,
38
+ spread: 360,
39
+ ticks: 60,
40
+ zIndex: 100,
41
+ colors: ['#4BA528', '#B90F4B', '#FFD700', '#0096DC'],
42
+ }
43
+
44
+ const interval = setInterval(() => {
45
+ const timeLeft = animationEnd - Date.now()
46
+
47
+ if (timeLeft <= 0) {
48
+ return clearInterval(interval)
49
+ }
50
+
51
+ const particleCount = 50 * (timeLeft / duration)
52
+
53
+ // since particles fall down, start a bit higher than random
54
+ confettiFn(
55
+ Object.assign({}, defaults, {
56
+ particleCount,
57
+ origin: {
58
+ x: randomInRange(0.1, 0.3),
59
+ y: Math.random() - 0.2,
60
+ },
61
+ }),
62
+ )
63
+ confettiFn(
64
+ Object.assign({}, defaults, {
65
+ particleCount,
66
+ origin: {
67
+ x: randomInRange(0.7, 0.9),
68
+ y: Math.random() - 0.2,
69
+ },
70
+ }),
71
+ )
72
+ }, 250)
73
+ }
74
+
75
+ onMounted(() => {
76
+ if (confetti) {
77
+ makeConfetti()
78
+ }
79
+ })
21
80
  </script>
22
81
 
23
82
  <template>
@@ -1,10 +1,14 @@
1
+ <script setup lang="ts">
2
+ import { assetsPath } from '../../globals'
3
+ </script>
4
+
1
5
  <template>
2
6
  <div class="wizard-top-bar">
3
7
  <div class="container">
4
8
  <div class="wizard-top-bar__inner">
5
9
  <div class="wizard-top-bar__logo">
6
10
  <slot name="logo">
7
- <img src="/static/ui-assets/images/logo.svg" alt="logo" />
11
+ <img :src="`${assetsPath}images/logo.svg`" alt="logo" />
8
12
  </slot>
9
13
  </div>
10
14