@energie360/ui-library 0.1.26 → 0.1.27

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.
@@ -68,3 +68,5 @@ export { default as USlider } from './slider/u-slider.vue'
68
68
  export { default as USpriteAnimation } from './sprite-animation/u-sprite-animation.vue'
69
69
  export { default as USliderProgressAnimation } from './slider-progress-animation/u-slider-progress-animation.vue'
70
70
  export { default as UStickyCta } from './sticky-cta/u-sticky-cta.vue'
71
+ export { default as UNotificationItem } from './notification-item/u-notification-item.vue'
72
+ export { default as UNotificationList } from './notification-list/u-notification-list.vue'
@@ -0,0 +1,115 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .notification-item {
4
+ z-index: 1;
5
+ position: relative;
6
+ container-type: inline-size;
7
+ margin-bottom: -1px;
8
+ }
9
+
10
+ // Unread state
11
+ .notification-item__inner {
12
+ padding: var(--e-space-4);
13
+ border-top: 1px solid var(--e-c-secondary-05-100);
14
+ border-bottom: 1px solid var(--e-c-secondary-05-100);
15
+ background-color: var(--e-c-secondary-05-50);
16
+ display: flex;
17
+ align-items: center;
18
+ transition: background-color a.$trs-default;
19
+ cursor: pointer;
20
+
21
+ &:hover {
22
+ background-color: var(--e-c-secondary-05-100);
23
+ }
24
+
25
+ &:active {
26
+ background-color: var(--e-c-secondary-05-200);
27
+ }
28
+
29
+ @container (width < 740px) {
30
+ flex-wrap: wrap;
31
+ border-radius: var(--e-brd-radius-2);
32
+ border: 1px solid var(--e-c-secondary-05-100);
33
+ row-gap: var(--e-space-2);
34
+
35
+ .notification-item__text {
36
+ order: 1;
37
+ flex: 0 0 100%;
38
+ padding: 0;
39
+ margin-right: 0;
40
+ }
41
+
42
+ .notification-item__dot {
43
+ order: 2;
44
+ }
45
+
46
+ .notification-item__when {
47
+ padding: 3px 0;
48
+ order: 3;
49
+ margin-left: 0;
50
+ }
51
+
52
+ .notification-item__remove {
53
+ order: 4;
54
+ margin-left: auto;
55
+ }
56
+ }
57
+ }
58
+
59
+ // Read state
60
+ .notification-item.read {
61
+ z-index: 0;
62
+
63
+ .notification-item__inner {
64
+ background-color: var(--e-c-mono-00);
65
+ border-color: var(--e-c-mono-100);
66
+
67
+ &:hover {
68
+ background-color: var(--e-c-primary-01-50);
69
+ }
70
+
71
+ &:active {
72
+ background-color: var(--e-c-primary-01-100);
73
+ }
74
+ }
75
+ }
76
+
77
+ .notification-item__text {
78
+ @include a.type(100);
79
+
80
+ margin-right: var(--e-space-2);
81
+ min-height: 24px;
82
+ padding: 1px 0;
83
+ }
84
+
85
+ .notification-item__dot {
86
+ display: block;
87
+ width: 8px;
88
+ height: 8px;
89
+ border-radius: 100%;
90
+ margin-right: var(--e-space-2);
91
+ background-color: var(--e-c-secondary-05-500);
92
+ }
93
+
94
+ .notification-item__when {
95
+ @include a.type(50);
96
+
97
+ white-space: nowrap;
98
+ color: var(--e-c-mono-700);
99
+ margin-left: auto;
100
+ }
101
+
102
+ .notification-item__remove {
103
+ cursor: pointer;
104
+ z-index: 1;
105
+ color: var(--e-c-primary-01-700);
106
+ margin-left: var(--e-space-6);
107
+
108
+ &:hover {
109
+ color: var(--e-c-secondary-01-900);
110
+ }
111
+ }
112
+
113
+ .visually-hidden {
114
+ @include a.visually-hidden;
115
+ }
@@ -0,0 +1,46 @@
1
+ <script lang="ts" setup>
2
+ import { UIcon } from '../../elements'
3
+ import { getTranslation } from '../../utils/translations/translate'
4
+
5
+ interface Props {
6
+ read: boolean
7
+ when: string
8
+ text?: string
9
+ removable: boolean
10
+ }
11
+
12
+ defineProps<Props>()
13
+ const emits = defineEmits(['remove'])
14
+
15
+ const onRemove = () => {
16
+ emits('remove')
17
+ }
18
+ </script>
19
+
20
+ <template>
21
+ <div :class="['notification-item', { read, removable }]">
22
+ <div class="notification-item__inner">
23
+ <div v-if="!read" class="notification-item__dot"></div>
24
+
25
+ <div class="notification-item__text">
26
+ <slot><div v-html="text" /></slot>
27
+ </div>
28
+
29
+ <div class="notification-item__when">
30
+ {{ when }}
31
+ </div>
32
+
33
+ <div
34
+ v-if="removable"
35
+ class="notification-item__remove"
36
+ role="button"
37
+ @click.prevent.stop="onRemove"
38
+ >
39
+ <span class="visually-hidden">{{ getTranslation('removeNotification') }}</span>
40
+ <UIcon name="delete" />
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </template>
45
+
46
+ <style lang="scss" scoped src="./notification-item.scss"></style>
@@ -0,0 +1,37 @@
1
+ @use '../../base/abstracts' as a;
2
+
3
+ .notification-list {
4
+ container-type: inline-size;
5
+
6
+ &.is-empty {
7
+ // This vertical centered style only works in the portal-main layout.
8
+ // It's not really possible to do this "correctly" at the moment, because `portal-main__content` is `display: block`.
9
+ // With `display: flex` it would work, but this would need some refactoring.
10
+ position: relative;
11
+ top: 50%;
12
+ transform: translateY(-100%);
13
+ }
14
+ }
15
+
16
+ .notification-list__inner {
17
+ display: flex;
18
+ flex-direction: column;
19
+
20
+ @container (width < 740px) {
21
+ gap: var(--e-space-3);
22
+ }
23
+ }
24
+
25
+ .notification-list__empty-wrapper {
26
+ text-align: center;
27
+ }
28
+
29
+ .notification-list__empty_animation {
30
+ width: 120px;
31
+ height: 120px;
32
+ margin: 0 auto var(--e-space-6);
33
+ }
34
+
35
+ .notification-list__empty-text {
36
+ @include a.type(300, strong);
37
+ }
@@ -0,0 +1,51 @@
1
+ <script setup lang="ts">
2
+ import { DotLottieVue } from '@lottiefiles/dotlottie-vue'
3
+ import { ref, onMounted, useTemplateRef } from 'vue'
4
+
5
+ interface Props {
6
+ emptyText: string
7
+ }
8
+
9
+ defineProps<Props>()
10
+
11
+ const innerEl = useTemplateRef('inner')
12
+ const isEmpty = ref(false)
13
+ const checkItems = () => {
14
+ const itemCount = innerEl.value.children.length
15
+
16
+ isEmpty.value = itemCount === 0
17
+ }
18
+
19
+ onMounted(() => {
20
+ checkItems()
21
+
22
+ const observer = new window.MutationObserver(() => {
23
+ checkItems()
24
+ })
25
+
26
+ observer.observe(innerEl.value, { childList: true, subtree: true })
27
+ })
28
+ </script>
29
+
30
+ <template>
31
+ <div :class="['notification-list', { 'is-empty': isEmpty }]">
32
+ <div ref="inner" class="notification-list__inner">
33
+ <slot />
34
+ </div>
35
+
36
+ <div v-if="isEmpty" class="notification-list__empty-wrapper">
37
+ <div class="notification-list__empty_animation">
38
+ <DotLottieVue
39
+ autoplay
40
+ loop
41
+ src="/static/ui-assets/lottie/notification-empty.lottie"
42
+ style="height: 100%; width: 100%"
43
+ />
44
+ </div>
45
+
46
+ <p class="notification-list__empty-text">{{ emptyText }}</p>
47
+ </div>
48
+ </div>
49
+ </template>
50
+
51
+ <style lang="scss" scoped src="./notification-list.scss"></style>
package/i18n/i18n.ts CHANGED
@@ -23,6 +23,7 @@ const translations = {
23
23
  download: 'Herunterladen',
24
24
  like: 'Gefällt mir',
25
25
  dislike: 'Gefällt mir nicht',
26
+ removeNotification: 'Benachrichtigung entfernen',
26
27
  },
27
28
  FR: {
28
29
  yes: 'Ja',
@@ -48,6 +49,7 @@ const translations = {
48
49
  download: 'Télécharger',
49
50
  like: "J'aime ça",
50
51
  dislike: "je ne l'aime pas",
52
+ removeNotification: 'supprimer la notification',
51
53
  },
52
54
  IT: {
53
55
  yes: 'Ja',
@@ -73,6 +75,7 @@ const translations = {
73
75
  download: 'scaricamento',
74
76
  like: 'Mi piace',
75
77
  dislike: 'Non mi piace',
78
+ removeNotification: 'rimuovere la notifica',
76
79
  },
77
80
  EN: {
78
81
  yes: 'Ja',
@@ -98,6 +101,7 @@ const translations = {
98
101
  download: 'Download',
99
102
  like: 'I like it',
100
103
  dislike: 'I do not like it',
104
+ removeNotification: 'remove notification',
101
105
  },
102
106
  }
103
107
 
package/layout/index.js CHANGED
@@ -4,3 +4,4 @@ export { default as UPortalContentAside } from './portal-content-aside/u-portal-
4
4
  export { default as UTileGrid } from './tile-grid/u-tile-grid.vue'
5
5
  export { default as UTileItem } from './tile-grid/u-tile-item.vue'
6
6
  export { default as UResponsiveContainer } from './responsive-container/u-responsive-container.vue'
7
+ export { default as UPortalBlock } from './portal-block/u-portal-block.vue'
@@ -0,0 +1,8 @@
1
+ .portal-block {
2
+ // default 'small'
3
+ margin-bottom: var(--e-space-6);
4
+
5
+ &.big {
6
+ margin-bottom: var(--e-space-10);
7
+ }
8
+ }
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ big?: boolean
4
+ space?: 'small' | 'big'
5
+ }
6
+
7
+ const { space = 'small' } = defineProps<Props>()
8
+ </script>
9
+
10
+ <template>
11
+ <div :class="['portal-block', space]">
12
+ <slot />
13
+ </div>
14
+ </template>
15
+
16
+ <style scoped lang="scss" src="./portal-block.scss"></style>
@@ -81,6 +81,7 @@
81
81
  .portal-main__content {
82
82
  padding-top: var(--e-space-10);
83
83
  padding-bottom: var(--e-space-10);
84
+ flex: 1 1 100%;
84
85
 
85
86
  @include c.portal-content-container;
86
87
 
@@ -15,7 +15,13 @@
15
15
  width: a.rem(88);
16
16
 
17
17
  .navigation-toolbar-side__logo {
18
- width: a.rem(40);
18
+ .mini {
19
+ opacity: 1;
20
+ }
21
+
22
+ .large {
23
+ opacity: 0;
24
+ }
19
25
  }
20
26
 
21
27
  .navigation-toolbar-side__nav-links,
@@ -29,6 +35,11 @@
29
35
  width: a.rem(196);
30
36
  height: a.rem(40);
31
37
  margin-bottom: var(--e-space-12);
38
+
39
+ .mini {
40
+ position: absolute;
41
+ opacity: 0;
42
+ }
32
43
  }
33
44
 
34
45
  .navigation-toolbar-side__nav-links {
@@ -49,12 +60,6 @@
49
60
  width: 100%;
50
61
  }
51
62
 
52
- .navigation-toolbar-side__top-bar-logo {
53
- img {
54
- height: a.rem(24);
55
- }
56
- }
57
-
58
63
  .navigation-toolbar-side__top-bar-ctas {
59
64
  display: flex;
60
65
  column-gap: var(--e-space-4);
@@ -62,28 +67,54 @@
62
67
 
63
68
  // Animation
64
69
  .navigation-toolbar-side {
70
+ --duration: var(--e-trs-duration-faster);
71
+
65
72
  &.is-collapsing {
66
73
  will-change: width;
67
- transition: width var(--e-trs-duration-faster) var(--transition-ease-out);
74
+ transition: width var(--duration) var(--transition-ease-out);
68
75
  width: a.rem(88);
69
76
  overflow: hidden;
70
77
 
71
78
  .navigation-toolbar-side__nav-links,
72
79
  .navigation-toolbar-side__menu-ctas {
73
- transition: padding var(--e-trs-duration-faster) var(--transition-ease-out);
80
+ transition: padding var(--duration) var(--transition-ease-out);
74
81
  padding: 0 var(--e-space-0_5);
75
82
  }
83
+
84
+ .navigation-toolbar-side__logo {
85
+ .mini {
86
+ opacity: 1;
87
+ transition: opacity var(--duration) var(--transition-ease-out);
88
+ }
89
+
90
+ .large {
91
+ opacity: 0;
92
+ transition: opacity var(--duration) var(--transition-ease-out);
93
+ }
94
+ }
76
95
  }
77
96
 
78
97
  &.is-expanding {
79
98
  will-change: width;
80
- transition: all var(--e-trs-duration-faster) var(--transition-ease-out);
99
+ transition: all var(--duration) var(--transition-ease-out);
81
100
  width: var(--nav-width-expanded);
82
101
 
83
102
  .navigation-toolbar-side__nav-links,
84
103
  .navigation-toolbar-side__menu-ctas {
85
- transition: padding var(--e-trs-duration-faster) var(--transition-ease-out);
104
+ transition: padding var(--duration) var(--transition-ease-out);
86
105
  padding: 0;
87
106
  }
107
+
108
+ .navigation-toolbar-side__logo {
109
+ .mini {
110
+ opacity: 0;
111
+ transition: opacity var(--duration) var(--transition-ease-out);
112
+ }
113
+
114
+ .large {
115
+ opacity: 1;
116
+ transition: opacity var(--duration) var(--transition-ease-out);
117
+ }
118
+ }
88
119
  }
89
120
  }
@@ -61,13 +61,16 @@ watch(
61
61
  },
62
62
  ]"
63
63
  >
64
- <a class="navigation-toolbar-side__logo" :href="logoLink.href" :target="logoLink.target">
65
- <img
66
- v-if="isCollapsed || isExpanding"
67
- :src="logoMinifiedImage.src"
68
- :alt="logoMinifiedImage.alt"
69
- />
70
- <img v-else :src="logoImage.src" :alt="logoImage.alt" />
64
+ <a
65
+ :class="[
66
+ 'navigation-toolbar-side__logo',
67
+ { 'is-collapsing': isCollapsing, 'is-expanding': isExpanding },
68
+ ]"
69
+ :href="logoLink.href"
70
+ :target="logoLink.target"
71
+ >
72
+ <img class="mini" :src="logoMinifiedImage.src" :alt="logoMinifiedImage.alt" />
73
+ <img class="large" :src="logoImage.src" :alt="logoImage.alt" />
71
74
  </a>
72
75
 
73
76
  <nav ref="mobile-panel" class="navigation-toolbar-side__nav-panel">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@energie360/ui-library",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -25,17 +25,17 @@
25
25
  "license": "MIT",
26
26
  "devDependencies": {
27
27
  "@tsconfig/node22": "^22.0.2",
28
- "@types/node": "^22.18.8",
28
+ "@types/node": "^22.19.0",
29
29
  "@vue/tsconfig": "^0.7.0",
30
- "autoprefixer": "^10.4.21",
30
+ "autoprefixer": "^10.4.22",
31
31
  "chokidar": "^4.0.3",
32
32
  "postcss": "^8.5.6",
33
- "sass": "^1.93.2",
33
+ "sass": "^1.94.0",
34
34
  "typescript": "^5.9.3"
35
35
  },
36
36
  "dependencies": {
37
+ "@lottiefiles/dotlottie-vue": "^0.10.7",
37
38
  "@lottiefiles/lottie-player": "^2.0.12",
38
- "swiper": "^11.2.10",
39
39
  "@energie360/design-tokens": "^1.3.0"
40
40
  },
41
41
  "peerDependencies": {