@awes-io/ui 2.75.0 → 2.77.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/assets/css/components/_index.css +4 -0
  3. package/assets/css/components/avatar.css +8 -1
  4. package/assets/css/components/button-nav.css +58 -10
  5. package/assets/css/components/button.css +8 -7
  6. package/assets/css/components/cropper.css +8 -0
  7. package/assets/css/components/empty-container.css +8 -0
  8. package/assets/css/components/icon-menu-item.css +5 -3
  9. package/assets/css/components/layout-menu.css +3 -1
  10. package/assets/css/components/main.css +3 -3
  11. package/assets/css/components/nav.css +1 -1
  12. package/assets/css/components/page-header.css +61 -0
  13. package/assets/css/components/page-single.css +186 -0
  14. package/assets/css/components/progress.css +23 -0
  15. package/assets/css/components/user-menu.css +27 -2
  16. package/assets/js/constants.js +6 -20
  17. package/components/1_atoms/AwAvatar.vue +39 -8
  18. package/components/1_atoms/AwProgress.vue +68 -0
  19. package/components/2_molecules/AwEmptyContainer.vue +104 -0
  20. package/components/3_organisms/AwCropper.vue +6 -1
  21. package/components/3_organisms/AwIslandAvatar.vue +15 -2
  22. package/components/3_organisms/AwPagination.vue +10 -6
  23. package/components/3_organisms/AwTags.vue +1 -1
  24. package/components/4_pages/AwPage.vue +3 -41
  25. package/components/4_pages/AwPageSingle.vue +219 -0
  26. package/components/4_pages/_AwPageHeader.vue +64 -0
  27. package/components/5_layouts/_AwMenuItemIcon.vue +8 -2
  28. package/components/5_layouts/_AwUserMenu.vue +29 -2
  29. package/mixins/page.js +58 -0
  30. package/nuxt/awes.config.js +2 -2
  31. package/package.json +3 -2
  32. package/tailwind/container.js +1 -1
  33. package/tailwind.config.js +4 -1
@@ -1,3 +1,5 @@
1
+ import { CUSTOM_COLORS, toColor, toOnColor } from './styles'
2
+
1
3
  export const TABLE_INDEX_ATTR = 'data-row-index'
2
4
 
3
5
  export const TABLE_ROW_CLICK_EVENT = 'click:row'
@@ -10,26 +12,10 @@ export const TABLE_DATA_FETCHED = 'data-fetched'
10
12
 
11
13
  export const FORM_ENTER_SKIP_ATTR = 'data-enter-skip'
12
14
 
13
- export const COLORS = [
14
- '#E0AB61',
15
- '#E29D5D',
16
- '#E68262',
17
- '#E45284',
18
- '#DF54BD',
19
- '#DA61D9',
20
- '#BF55CF',
21
- '#AF57DB',
22
- '#9C55D3',
23
- '#834EE3',
24
- '#634EE3',
25
- '#594FCF',
26
- '#6086E3',
27
- '#66B9E4',
28
- '#66C3D1',
29
- '#66C7B9',
30
- '#5CBC98',
31
- '#9A6F66'
32
- ]
15
+ export const COLORS = Object.keys(CUSTOM_COLORS).map((color) => ({
16
+ color: toColor(color),
17
+ onColor: toOnColor(color)
18
+ }))
33
19
 
34
20
  export const TEST_ID_ATTR = 'data-testid'
35
21
 
@@ -1,7 +1,21 @@
1
1
  <template>
2
- <Component :is="tag" :style="sizeVariables" class="aw-avatar">
2
+ <Component
3
+ :is="tag"
4
+ :style="sizeVariables"
5
+ class="aw-avatar"
6
+ :class="{ 'aw-avatar--square': square }"
7
+ >
3
8
  <!-- image -->
4
- <slot v-bind="{ src, name, initials, color, imageError }">
9
+ <slot
10
+ v-bind="{
11
+ src,
12
+ name,
13
+ initials,
14
+ color: color.background,
15
+ onColor: color.text,
16
+ imageError
17
+ }"
18
+ >
5
19
  <img
6
20
  v-if="src && !imageError"
7
21
  :src="src"
@@ -15,7 +29,8 @@
15
29
  (type === 'initials' || type === 'empty')
16
30
  "
17
31
  :style="{
18
- backgroundColor: color
32
+ backgroundColor: color.background,
33
+ color: color.text
19
34
  }"
20
35
  >
21
36
  {{ type === 'initials' ? initials : '' }}
@@ -23,7 +38,12 @@
23
38
  </slot>
24
39
 
25
40
  <!-- no image placeholder -->
26
- <slot name="no-img" :initials="initials" :color="color">
41
+ <slot
42
+ name="no-img"
43
+ :initials="initials"
44
+ :color="color.background"
45
+ :onColor="color.text"
46
+ >
27
47
  <svg
28
48
  v-if="(imageError || !src) && type === 'no-img'"
29
49
  xmlns="http://www.w3.org/2000/svg"
@@ -31,7 +51,7 @@
31
51
  class="aw-avatar__no-img-icon"
32
52
  >
33
53
  <path
34
- :fill="color"
54
+ :fill="color.background"
35
55
  d="M248 8a248 248 0 100 496 248 248 0 000-496zm0 96a88 88 0 110 176 88 88 0 010-176zm0 344c-59 0-111-27-146-68 18-36 55-60 98-60l7 1c13 4 27 7 41 7s28-3 41-7l7-1c43 0 80 24 99 60-36 41-88 68-147 68z"
36
56
  />
37
57
  </svg>
@@ -49,6 +69,7 @@ import { memoize } from 'rambdax'
49
69
  import { hashStringToIndex } from '@AwUtils/string'
50
70
  import { conf } from '@AwUtils/component'
51
71
  import { AwAvatar as _config } from '@AwConfig'
72
+ import { toColor, toOnColor } from '../../assets/js/styles'
52
73
 
53
74
  const memoizedHasher = memoize(hashStringToIndex)
54
75
 
@@ -109,7 +130,9 @@ export default {
109
130
  default() {
110
131
  return conf(this, 'colors')
111
132
  }
112
- }
133
+ },
134
+
135
+ square: Boolean
113
136
  },
114
137
 
115
138
  data() {
@@ -150,11 +173,19 @@ export default {
150
173
 
151
174
  // Get random color from the preset list
152
175
  color() {
153
- if (!this.isColored) return null
176
+ if (!this.isColored) {
177
+ return {
178
+ background: toColor('mono-400'),
179
+ text: toOnColor('mono-400')
180
+ }
181
+ }
154
182
 
155
183
  const index = memoizedHasher(this.name.trim(), this.colors.length)
156
184
 
157
- return this.colors[index]
185
+ return {
186
+ background: this.colors[index]?.onColor,
187
+ text: this.colors[index]?.color
188
+ }
158
189
  },
159
190
 
160
191
  isLoading() {
@@ -0,0 +1,68 @@
1
+ <template>
2
+ <div
3
+ class="aw-progress"
4
+ :style="{ '--progress': progressRatio, '--color': fgColor }"
5
+ ></div>
6
+ </template>
7
+
8
+ <script>
9
+ import anime from 'animejs'
10
+ import { clamp } from 'rambdax'
11
+ import { toColor } from '@AwUtils/styles'
12
+
13
+ export default {
14
+ name: 'AwProgress',
15
+
16
+ props: {
17
+ progress: {
18
+ type: Number,
19
+ default: 0
20
+ },
21
+
22
+ prevValueParam: {
23
+ type: String,
24
+ default: 'prev_progress'
25
+ },
26
+
27
+ color: {
28
+ type: String,
29
+ default: 'accent'
30
+ }
31
+ },
32
+
33
+ data() {
34
+ return {
35
+ value: parseInt(this.$route.query[this.prevValueParam]) || 0
36
+ }
37
+ },
38
+
39
+ computed: {
40
+ progressRatio() {
41
+ return (clamp(0, 100, this.value) / 100).toFixed(4)
42
+ },
43
+
44
+ fgColor() {
45
+ return toColor(this.color)
46
+ }
47
+ },
48
+
49
+ watch: {
50
+ progress: 'animate'
51
+ },
52
+
53
+ mounted() {
54
+ this.animate()
55
+ },
56
+
57
+ methods: {
58
+ animate() {
59
+ anime({
60
+ targets: this,
61
+ value: this.progress,
62
+ duration: 1000,
63
+ easing: 'easeOutCirc'
64
+ })
65
+ }
66
+ }
67
+ }
68
+ </script>
@@ -0,0 +1,104 @@
1
+ <template>
2
+ <AwCard>
3
+ <div
4
+ ref="container"
5
+ class="aw-empty-container"
6
+ :class="{ 'aw-empty-container--visible': isVisible }"
7
+ >
8
+ <slot name="icon">
9
+ <AwIcon
10
+ v-if="icon"
11
+ :name="icon"
12
+ :size="iconSize"
13
+ :style="{ fill: _iconColor }"
14
+ />
15
+ </slot>
16
+
17
+ <AwSubHeadline v-if="title" class="m-0">{{ title }}</AwSubHeadline>
18
+
19
+ <slot name="buttons"></slot>
20
+ </div>
21
+ </AwCard>
22
+ </template>
23
+
24
+ <script>
25
+ import anime from 'animejs'
26
+ import { toColor } from '@AwUtils/styles'
27
+
28
+ export default {
29
+ name: 'AwEmptyContainer',
30
+
31
+ props: {
32
+ icon: {
33
+ type: String,
34
+ default: ''
35
+ },
36
+
37
+ iconSize: {
38
+ type: Number,
39
+ default: 60
40
+ },
41
+
42
+ iconColor: {
43
+ type: String,
44
+ default: 'mono-100'
45
+ },
46
+
47
+ title: {
48
+ type: String,
49
+ default: ''
50
+ }
51
+ },
52
+
53
+ data() {
54
+ return {
55
+ isVisible: true
56
+ }
57
+ },
58
+
59
+ computed: {
60
+ _iconColor() {
61
+ return this.iconColor ? toColor(this.iconColor) : null
62
+ }
63
+ },
64
+
65
+ beforeMount() {
66
+ this.isVisible = false
67
+ },
68
+
69
+ mounted() {
70
+ this.prepare()
71
+
72
+ this.isVisible = true
73
+
74
+ setTimeout(this.animate, 200)
75
+ },
76
+
77
+ methods: {
78
+ prepare() {
79
+ anime.set(this._getElements(), {
80
+ opacity: 0,
81
+ translateY: '0.5rem',
82
+ transition: 'none'
83
+ })
84
+ },
85
+
86
+ animate() {
87
+ anime.set(this._getElements(), { transition: null })
88
+
89
+ anime({
90
+ targets: this._getElements(),
91
+ opacity: 1,
92
+ translateY: 0,
93
+ delay: anime.stagger(120),
94
+ easing: 'easeOutCirc',
95
+ duration: 240
96
+ })
97
+ },
98
+
99
+ _getElements() {
100
+ return this.$refs.container?.children || []
101
+ }
102
+ }
103
+ }
104
+ </script>
@@ -3,6 +3,7 @@
3
3
  v-show="!!croppie"
4
4
  class="aw-cropper"
5
5
  :style="{ width: totalWidth + 'px' }"
6
+ :class="{ 'aw-cropper--square': square }"
6
7
  >
7
8
  <!-- image wrapped because of Croppie -->
8
9
  <div class="aw-cropper__croppie">
@@ -83,7 +84,9 @@ export default {
83
84
  quality: {
84
85
  type: [String, Number],
85
86
  default: 1
86
- }
87
+ },
88
+
89
+ square: Boolean
87
90
  },
88
91
 
89
92
  data() {
@@ -111,6 +114,8 @@ export default {
111
114
  },
112
115
  enableOrientation: true
113
116
  })
117
+
118
+ setTimeout(() => this.croppie.setZoom(0), 60)
114
119
  },
115
120
 
116
121
  rotate() {
@@ -16,6 +16,8 @@
16
16
  :name="name || title"
17
17
  :type="name || title ? 'initials' : 'no-img'"
18
18
  :loading="loading"
19
+ :square="squareAvatar"
20
+ :size="avatarSize"
19
21
  class="aw-island-avatar__icon-userpic"
20
22
  />
21
23
  <button
@@ -147,7 +149,11 @@
147
149
  :title="$t('Upload avatar')"
148
150
  theme="fullscreen"
149
151
  >
150
- <AwCropper :src="uploadedAvatar" @save="saveAvatar" />
152
+ <AwCropper
153
+ :src="uploadedAvatar"
154
+ @save="saveAvatar"
155
+ :square="squareAvatar"
156
+ />
151
157
  </AwModal>
152
158
  </template>
153
159
  </AwIsland>
@@ -210,7 +216,14 @@ export default {
210
216
  default: true
211
217
  },
212
218
 
213
- truncateDescription: Boolean
219
+ truncateDescription: Boolean,
220
+
221
+ squareAvatar: Boolean,
222
+
223
+ avatarSize: {
224
+ type: [Number, String],
225
+ default: null
226
+ }
214
227
  },
215
228
 
216
229
  data() {
@@ -22,12 +22,14 @@
22
22
  >
23
23
  <AwIconSystemMono name="arrow" size="16" />
24
24
  </AwButton>
25
+
25
26
  <AwButton
26
27
  :data-page="prevPage"
27
28
  :disabled="prevPage === null"
28
- theme="icon"
29
+ theme="ghost"
30
+ color="default"
29
31
  size="sm"
30
- class="hidden lg:inline-flex mr-1"
32
+ class="aw-button-nav__arrow-btn hidden lg:inline-flex mr-4"
31
33
  >
32
34
  <AwIconSystemMono name="arrow" size="16" />
33
35
  </AwButton>
@@ -36,7 +38,7 @@
36
38
  {{ $t('Page {page} of {pagesTotal}', { page, pagesTotal }) }}
37
39
  </span>
38
40
  <div
39
- class="hidden lg:inline-flex aw-button-nav aw-button-nav__wrapper"
41
+ class="hidden lg:inline-flex aw-button-nav aw-button-nav__wrapper aw-button-nav--pagination"
40
42
  >
41
43
  <Component
42
44
  v-for="({ component, text }, i) in pageButtons"
@@ -50,7 +52,7 @@
50
52
  }"
51
53
  class="aw-button-nav__toggler"
52
54
  >
53
- <span class="w-8 h-8" tabindex="-1">
55
+ <span tabindex="-1">
54
56
  {{ text }}
55
57
  </span>
56
58
  </Component>
@@ -59,12 +61,14 @@
59
61
  <AwButton
60
62
  :data-page="nextPage"
61
63
  :disabled="nextPage === null"
62
- theme="icon"
63
64
  size="sm"
64
- class="hidden lg:inline-flex ml-1"
65
+ theme="ghost"
66
+ color="default"
67
+ class="aw-button-nav__arrow-btn hidden lg:inline-flex ml-4"
65
68
  >
66
69
  <AwIconSystemMono name="arrow" rotate="180" size="16" />
67
70
  </AwButton>
71
+
68
72
  <AwButton
69
73
  :data-page="nextPage"
70
74
  :disabled="nextPage === null"
@@ -93,7 +93,7 @@ export default {
93
93
  getColor(str) {
94
94
  const index = memoizedHasher(str, this.colors.length)
95
95
 
96
- return this.colors[index]
96
+ return this.colors[index].onColor
97
97
  },
98
98
 
99
99
  _emitOnClick($event) {
@@ -112,30 +112,21 @@
112
112
 
113
113
  <script>
114
114
  import { pathOr } from 'rambdax'
115
+ import pageMixin from '@AwMixins/page'
115
116
  import AwBottomBar from '@AwOrganisms/AwBottomBar.vue'
116
117
  import AwPageHeadline from '@AwPages/_AwPageHeadline.vue'
117
118
 
118
119
  export default {
119
120
  name: 'AwPage',
120
121
 
122
+ mixins: [pageMixin],
123
+
121
124
  components: {
122
125
  AwBottomBar,
123
126
  AwPageHeadline
124
127
  },
125
128
 
126
129
  props: {
127
- // Main headline on the page
128
- title: {
129
- type: String,
130
- default: ''
131
- },
132
-
133
- // Meta title (`title` prop if not provided)
134
- metaTitle: {
135
- type: String,
136
- default: ''
137
- },
138
-
139
130
  titleTag: {
140
131
  type: String,
141
132
  default: null
@@ -147,15 +138,6 @@ export default {
147
138
  default: () => []
148
139
  },
149
140
 
150
- // Breadcrumb object with title and href to return back
151
- breadcrumb: {
152
- type: Object,
153
- default: null,
154
- validator(params) {
155
- return params ? typeof params.href !== 'undefined' : true
156
- }
157
- },
158
-
159
141
  // A prop to toggle page fullscreen mode
160
142
  fullscreen: Boolean,
161
143
 
@@ -185,18 +167,6 @@ export default {
185
167
  }
186
168
  },
187
169
 
188
- head() {
189
- let title = this.metaTitle || this.title
190
-
191
- // if (this._breadcrumb) {
192
- // title = this._breadcrumb.text + ' / ' + title
193
- // }
194
-
195
- return {
196
- title
197
- }
198
- },
199
-
200
170
  data() {
201
171
  return {
202
172
  isFullscreen: false,
@@ -205,14 +175,6 @@ export default {
205
175
  },
206
176
 
207
177
  computed: {
208
- _title() {
209
- return this.title
210
- },
211
-
212
- _hasBreadcrumb() {
213
- return this.breadcrumb ? !!this.breadcrumb.href : false
214
- },
215
-
216
178
  _hideBottomBar() {
217
179
  return this.hideBottomBar === null
218
180
  ? this._hasBreadcrumb