@awes-io/ui 2.38.0 → 2.40.1

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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,50 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [2.40.1](https://github.com/awes-io/client/compare/@awes-io/ui@2.40.0...@awes-io/ui@2.40.1) (2022-01-21)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **aw-mobile-menu:** use correct heading for submenu ([62a3210](https://github.com/awes-io/client/commit/62a321084a295620802e7bc0fbb92e948400f19a))
12
+
13
+
14
+
15
+
16
+
17
+ # [2.40.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.39.1...@awes-io/ui@2.40.0) (2022-01-21)
18
+
19
+
20
+ ### Features
21
+
22
+ * user menu updated ([b4006e8](https://github.com/awes-io/client/commit/b4006e8fac3a84b646acab6693f1950234ceb950))
23
+
24
+
25
+
26
+
27
+
28
+ ## [2.39.1](https://github.com/awes-io/client/compare/@awes-io/ui@2.39.0...@awes-io/ui@2.39.1) (2022-01-17)
29
+
30
+
31
+ ### Bug Fixes
32
+
33
+ * **aw-address:** inherit passed attrs in select ([0dbf456](https://github.com/awes-io/client/commit/0dbf4566bcc8aaf5e84113977299b8115afbf2f1))
34
+
35
+
36
+
37
+
38
+
39
+ # [2.39.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.38.0...@awes-io/ui@2.39.0) (2022-01-17)
40
+
41
+
42
+ ### Features
43
+
44
+ * aw-address uses select internally ([d8a71f0](https://github.com/awes-io/client/commit/d8a71f0b42f22853ca69d1b61cfdb3d9d91aed40))
45
+
46
+
47
+
48
+
49
+
6
50
  # [2.38.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.37.0...@awes-io/ui@2.38.0) (2021-12-30)
7
51
 
8
52
 
@@ -1,9 +1,10 @@
1
1
  .aw-bottom-bar {
2
2
  --icon-color: rgba(var(--c-on-surface-rgb), 0.5);
3
3
  --icon-color-active: var(--c-accent, currentColor);
4
- @apply bg-surface shadow;
4
+ @apply bg-surface;
5
5
  display: flex;
6
6
  padding-bottom: env(safe-area-inset-bottom, 0);
7
+ box-shadow: 0px -2px 2px rgba(var(--c-mono-100-rgb, 50, 50, 50), 0.1);
7
8
 
8
9
  position: sticky;
9
10
  bottom: 0;
@@ -1,4 +1,5 @@
1
1
  .aw-headline {
2
- font-family: theme('fontfamily.heading', inherit);
3
- font-size: theme('fontSize.lg', 1.125rem);
2
+ font-weight: bold;
3
+ font-family: theme('fontFamily.heading', inherit);
4
+ font-size: theme('fontSize.xl', 1.25rem);
4
5
  }
@@ -16,20 +16,22 @@
16
16
  font-weight: bold;
17
17
  }
18
18
 
19
- & + & {
20
- border-top: 1px solid var(--c-mono-800);
19
+ &__icon-bg {
20
+ margin-left: 1.875rem;
21
+ margin-right: -0.875rem;
22
+ padding: 0.1875rem;
23
+ border-radius: 0.3125rem;
24
+ line-height: 1;
21
25
  }
22
26
 
23
- &__icon {
24
- @apply -mr-1 ml-6;
25
- }
27
+ /* &__icon {} */
26
28
 
27
29
  &__text {
28
- @apply py-2 pl-4 pr-2;
29
30
  display: flex;
30
31
  flex-direction: column;
31
32
  justify-content: center;
32
- min-height: 3.5rem;
33
+ min-height: 3.375rem;
34
+ padding: 0.5rem 0.5rem 0.5rem 1.875rem;
33
35
  flex-grow: 1;
34
36
  }
35
37
 
@@ -39,7 +41,7 @@
39
41
  }
40
42
 
41
43
  &__arrow {
42
- @apply my-3 mr-5;
44
+ margin: 0.75rem 1.875rem 0.75rem 0;
43
45
  color: var(--c-on-surface);
44
46
  }
45
47
  }
@@ -1,17 +1,15 @@
1
1
  .aw-mobile-menu-nav {
2
- font-size: theme('fontSize.lg', 1.125rem);
2
+ font-size: 1rem;
3
3
 
4
4
  h3, h4 {
5
5
  color: var(--c-mono-400);
6
6
  font-size: inherit;
7
- padding: 0 theme('spacing.4', 1rem);
8
- margin-bottom: theme('spacing.4', 1rem);
7
+ text-transform: uppercase;
8
+ padding: 0.625rem 1.875rem 0;
9
+ margin-bottom: 0.5rem;
9
10
  }
10
11
 
11
12
  ol, ul {
12
- border-radius: theme('borderRadius.lg', 0.5rem);
13
- box-shadow: theme('boxShadow.default');
14
-
15
13
  overflow: hidden;
16
14
  list-style: none;
17
15
  padding: 0;
@@ -19,6 +17,18 @@
19
17
  }
20
18
 
21
19
  li + li {
22
- border-top-width: 1px;
20
+ position: relative;
21
+
22
+ &:before {
23
+ @apply bg-mono-900;
24
+ content: '';
25
+ display: block;
26
+ height: 1px;
27
+
28
+ position: absolute;
29
+ top: 0;
30
+ left: 1.875rem;
31
+ right: 1.875rem;
32
+ }
23
33
  }
24
34
  }
@@ -1,8 +1,5 @@
1
- /* $menu-width: 480px; */
2
-
3
1
  .aw-mobile-menu {
4
2
  @apply bg-mono-900;
5
- /* width: $(menu-width); */
6
3
  width: 100%;
7
4
 
8
5
  display: flex;
@@ -27,49 +24,76 @@
27
24
  }
28
25
 
29
26
  &__header {
30
- @apply bg-surface shadow;
27
+ @apply bg-mono-900;
31
28
  display: flex;
32
29
  align-items: center;
33
30
 
34
- padding: theme('spacing.1', 0.25rem) theme('spacing.2', 0.5rem);
35
- margin-bottom: theme('spacing.3', 0.75rem);
31
+ padding: 0.9375rem;
36
32
 
37
- /* position: sticky;
33
+ position: sticky;
38
34
  top: 0;
39
35
  left: 0;
40
36
  right: 0;
41
- z-index: 1; */
37
+ z-index: 1;
42
38
  }
43
39
 
44
- &__user {
45
- padding: 0 theme('spacing.2', 0.5rem);
46
- display: flex;
47
- flex-direction: column;
48
- align-items: center;
49
- margin-bottom: theme('spacing.4', 1rem);
40
+ &__submenu-title {
41
+ margin: 0 0 0 0.9375rem;
50
42
  }
51
43
 
52
- &__user-name {
53
- max-width: 100%;
54
- margin-top: theme('spacing.2', 0.5rem);
44
+ &__user {
45
+ @apply bg-surface;
55
46
 
56
- font-family: theme('fontFamily.heading');
57
- font-size: theme('fontSize.2xl', 1.5rem);
58
- }
47
+ display: grid;
48
+ grid-template-columns: 3.75rem auto minmax(0, 1.5rem);
49
+ grid-template-rows: auto auto;
50
+ padding: 1.25rem 1.875rem;
51
+ margin-bottom: 1.25rem;
59
52
 
60
- &__user-edit {
61
- color: var(--c-mono-400);
62
- margin-left: theme('spacing.2', 0.5rem);
63
- line-height: 1;
53
+ position: relative;
64
54
 
65
- &:hover {
66
- color: var(--c-link);
55
+ .aw-avatar {
56
+ --ui-avatar-size: 3.75rem !important;
57
+ --ui-avatar-font-size: 1.875rem !important;
58
+ grid-column: 1;
59
+ grid-row: 1 / -1;
60
+ }
61
+
62
+ &-name {
63
+ grid-column: 2;
64
+ grid-row: 1;
65
+ align-self: end;
66
+ margin-top: 0;
67
+ line-height: 1;
68
+ padding-left: 0.9375rem;
67
69
  }
68
- }
69
70
 
70
- &__user-desc {
71
- max-width: 100%;
72
- color: var(--c-mono-400);
71
+ &-desc {
72
+ grid-column: 2;
73
+ grid-row: 2;
74
+ align-self: start;
75
+ padding-left: 0.9375rem;
76
+ }
77
+
78
+ &-link {
79
+ color: inherit;
80
+ grid-column: 3;
81
+ grid-row: 1 / -1;
82
+ align-self: center;
83
+ padding-left: 0.5rem;
84
+
85
+ &:hover {
86
+ text-decoration: none;
87
+ color: inherit;
88
+ }
89
+
90
+ &:after {
91
+ content: '';
92
+ display: block;
93
+ position: absolute;
94
+ inset: 0;
95
+ }
96
+ }
73
97
  }
74
98
 
75
99
  &__logo {
@@ -93,34 +117,23 @@
93
117
  }
94
118
 
95
119
  &__close {
96
- display: block;
97
- padding: theme('spacing.3') theme('spacing.4');
98
120
  margin-left: auto;
99
121
  }
100
122
 
101
- /* &__overlay {
102
- content: '';
103
- display: block;
104
- position: fixed;
105
- right: 0;
106
- top: 0;
107
- bottom: 0;
108
- left: $(menu-width);
109
- width: calc(100% - $(menu-width));
110
- background: theme('colors.overlay');
111
- backdrop-filter: blur(3px);
112
-
113
- &:focus {
114
- outline: none;
115
- }
116
- } */
117
-
118
123
  &__widgets {
119
124
  padding: theme('spacing.4');
120
125
  }
121
126
 
122
127
  &__menu {
123
- margin: 0 theme('spacing.2', 0.5rem) theme('spacing.10', 2.5rem);
128
+ margin-bottom: 1.25rem;
129
+ }
130
+
131
+ &--root &__menu h3 {
132
+ @apply sr-only;
133
+ }
134
+
135
+ &--scrolled &__header {
136
+ box-shadow: 0px 2px 2px rgba(var(--c-mono-100-rgb, 50, 50, 50), 0.1);
124
137
  }
125
138
 
126
139
  /**
@@ -132,28 +145,3 @@
132
145
  transition: 60ms opacity ease-out, 0ms visibility;
133
146
  }
134
147
  }
135
-
136
- @screen md {
137
- .aw-mobile-menu {
138
- &__menu {
139
- ol {
140
- display: grid;
141
- grid-template-columns: repeat(2, minmax(10px, 1fr));
142
- grid-gap: theme('spacing.4', 1rem);
143
- border-radius: 0;
144
- box-shadow: none;
145
- overflow: visible;
146
- }
147
-
148
- li + li {
149
- border-top: 0;
150
- }
151
-
152
- li {
153
- border-radius: theme('borderRadius.md', 0.25rem);
154
- box-shadow: theme('boxShadow.default');
155
- overflow: hidden;
156
- }
157
- }
158
- }
159
- }
@@ -14,7 +14,7 @@
14
14
 
15
15
  position: fixed;
16
16
  right: theme('spacing.4', 1rem);
17
- bottom: calc(env(safe-area-inset-bottom, 0) + var(--page-buttons-bottom, 0));
17
+ bottom: calc(env(safe-area-inset-bottom, 0px) + var(--page-buttons-bottom, 0px));
18
18
  z-index: 2;
19
19
 
20
20
  & > * {
@@ -1,4 +1,5 @@
1
1
  .aw-subheadline {
2
- font-family: theme('fontfamily.heading', inherit);
3
- font-size: theme('fontSize.lg', 1.25rem);
2
+ font-weight: bold;
3
+ font-family: theme('fontFamily.heading', inherit);
4
+ font-size: theme('fontSize.base', 1rem);
4
5
  }
@@ -1,9 +1,10 @@
1
1
  export default {
2
2
  close:
3
- 'M18.8 2.2l-1-1L10 9 2.2 1.2l-1 1L9 10l-7.8 7.8 1 1L10 11l7.8 7.8 1-1L11 10l7.8-7.8z',
4
- angle: 'M13 2l-8 8 8 8 1-1-7-7 7-7-1-1z',
3
+ 'M15.88 5.88a1.25 1.25 0 0 0-1.76-1.76L10 8.23 5.88 4.12a1.25 1.25 0 0 0-1.76 1.76L8.23 10l-4.11 4.12a1.25 1.25 0 1 0 1.76 1.76L10 11.77l4.12 4.11a1.25 1.25 0 1 0 1.76-1.76L11.77 10l4.11-4.12Z',
4
+ angle:
5
+ 'M13.4 15.9c.5-.5.5-1.3 0-1.8l-4-4.1 4-4.1c.5-.5.5-1.3 0-1.8s-1.2-.5-1.7 0L7 9.1c-.5.5-.5 1.3 0 1.8l4.7 5c.5.5 1.2.5 1.7 0Z',
5
6
  arrow:
6
- 'M7.2 16.7c.2.3.6.3.9 0 .2-.2.2-.7 0-1l-4.2-5h13.7c.3 0 .5-.3.5-.7 0-.4-.2-.7-.5-.7H3.9l4.1-5c.3-.3.3-.8 0-1-.2-.3-.5-.3-.8 0L2.1 9.5a.5.6 0 000 1l5.1 6.2z',
7
+ 'M8.81 4.12a1.25 1.25 0 0 0-1.77 0L1.57 9.58a1.1 1.1 0 0 0 0 1.57l5.47 5.47a1.25 1.25 0 1 0 1.77-1.77l-3.23-3.23h11.98a1.25 1.25 0 0 0 0-2.5H5.58L8.8 5.88c.49-.48.49-1.28 0-1.76Z',
7
8
  user:
8
9
  'M13.2 11.1c-1 0-1.5.6-3.2.6-1.7 0-2.1-.6-3.2-.6A4.7 4.7 0 002.1 16v1.4c0 1 .8 1.7 1.7 1.7h12.4c1 0 1.7-.8 1.7-1.7v-1.5c0-2.6-2.1-4.7-4.7-4.7zm3.6 6.2c0 .3-.3.6-.6.6H3.8a.6.6 0 01-.5-.6v-1.5c0-2 1.6-3.6 3.5-3.6.7 0 1.4.6 3.2.6 1.8 0 2.5-.6 3.2-.6 2 0 3.6 1.7 3.6 3.7v1.4zM10 10a4.5 4.5 0 100-9 4.5 4.5 0 000 9zm0-7.9A3.4 3.4 0 1110 9 3.4 3.4 0 0110 2z',
9
10
  menu: 'M1 11V9h18v2H1zm0-6V3h18v2H1zm0 12v-2h18v2H1z',
@@ -17,7 +18,7 @@ export default {
17
18
  'M1 10a2 2 0 114 0 2 2 0 01-4 0zm7 0a2 2 0 114 0 2 2 0 01-4 0zm7 0a2 2 0 114 0 2 2 0 01-4 0z',
18
19
  triangle: 'M5 7h10l-5 5z',
19
20
  external:
20
- 'M16 10h-.6a.3.3 0 00-.2.3v6.4a.5.5 0 01-.5.6H3.3a.5.5 0 01-.6-.6V5.3a.5.5 0 01.6-.5h6.4a.3.3 0 00.3-.2V4a.3.3 0 00-.3-.2H3.3a1.6 1.6 0 00-1.6 1.5v11.4a1.6 1.6 0 001.6 1.6h11.4a1.6 1.6 0 001.5-1.6v-6.4a.3.3 0 00-.2-.3zm1.9-8.3h-4.4a.4.4 0 00-.4.4v.3a.4.4 0 00.4.4h3L6 13.3a.4.4 0 000 .5l.2.2a.4.4 0 00.5 0L17.2 3.6v2.9a.4.4 0 00.4.4h.3a.4.4 0 00.4-.4V2.1a.4.4 0 00-.4-.4z',
21
+ 'M6.67 5a1.25 1.25 0 1 0 0 2.5h4.48l-5.78 5.78a1.25 1.25 0 1 0 1.76 1.77l5.78-5.78v4.48a1.25 1.25 0 1 0 2.5 0v-7.5c0-.7-.56-1.25-1.25-1.25h-7.5Z',
21
22
  edit:
22
23
  'M11.7 5.34l2.85 2.86-7.2 7.24-2.85-2.86 7.2-7.24zm5.01-.7l-1.27-1.27c-.49-.5-1.28-.5-1.78 0l-1.21 1.22 2.85 2.86 1.41-1.42c.39-.38.39-1 0-1.38zM3.01 16.6c-.05.24.16.45.39.4l3.17-.78-2.84-2.86L3 16.6z',
23
24
  'info-circle':
@@ -55,7 +55,7 @@ export default {
55
55
  class: {
56
56
  'aw-flow__wrap--children': !wrapChildren,
57
57
  'aw-flow__wrap--vertical': vertical,
58
- 'justify-start': justify === 'center',
58
+ 'justify-center': justify === 'center',
59
59
  'justify-end': justify === 'end',
60
60
  'items-start': align === 'start',
61
61
  'items-center': align === 'center',
@@ -178,6 +178,14 @@
178
178
  </div>
179
179
 
180
180
  <div v-if="_isAjax && _hasNextPage" ref="dropdownEnd"></div>
181
+
182
+ <slot
183
+ name="dropdown-after"
184
+ v-bind="{
185
+ optionsList,
186
+ isLoading
187
+ }"
188
+ ></slot>
181
189
  </slot>
182
190
  </div>
183
191
  </div>
@@ -438,7 +446,7 @@ export default {
438
446
  _showNotFound() {
439
447
  return this._isAjax
440
448
  ? !this.selectOptions.length && !this.isLoading
441
- : !this.optionsList.length
449
+ : this._searchPhraseLength && !this.optionsList.length
442
450
  },
443
451
 
444
452
  isMobile() {
@@ -1,34 +1,26 @@
1
1
  <template>
2
- <div class="relative">
3
- <AwInput v-bind="$attrs" v-model="search" autocomplete="off" />
4
-
5
- <!-- suggestions -->
6
- <AwDropdown
7
- class="w-full z-10"
8
- :show="!!suggestions.length"
9
- close-on-action
10
- >
11
- <AwDropdownButton
12
- icon="location"
13
- v-for="place in suggestions"
14
- :key="place.place_id"
15
- @click="select(place)"
16
- >
17
- {{ place.description }}
18
- </AwDropdownButton>
19
-
2
+ <AwSelectObject
3
+ ref="select"
4
+ v-model="place"
5
+ v-bind="$attrs"
6
+ :options="suggestions"
7
+ track-by="place_id"
8
+ option-label="description"
9
+ @search="search"
10
+ >
11
+ <template #dropdown-after>
20
12
  <!-- branding -->
21
13
  <img
14
+ v-if="suggestions.length"
22
15
  class="block my-2 mx-auto"
23
16
  aria-hidden="true"
24
17
  src="https://maps.gstatic.com/mapfiles/api-3/images/powered-by-google-on-white3.png"
25
18
  alt=""
26
19
  />
27
- </AwDropdown>
28
-
29
- <!-- places service needs a container to init -->
30
- <div ref="place"></div>
31
- </div>
20
+ <!-- places service needs a container to init -->
21
+ <div ref="place"></div>
22
+ </template>
23
+ </AwSelectObject>
32
24
  </template>
33
25
 
34
26
  <script>
@@ -39,6 +31,8 @@ import gmMixin from '@AwMixins/google-maps'
39
31
  export default {
40
32
  name: 'AwAddress',
41
33
 
34
+ inheritAttrs: false,
35
+
42
36
  mixins: [gmMixin],
43
37
 
44
38
  props: {
@@ -56,30 +50,34 @@ export default {
56
50
  autocomplete: null,
57
51
  placesService: null,
58
52
  sessionToken: null,
53
+ isLoading: false,
59
54
  suggestions: [],
60
- placeDescription: '',
61
55
  place: null
62
56
  }
63
57
  },
64
58
 
65
- computed: {
66
- search: {
67
- get() {
68
- return this.placeDescription
69
- },
70
-
71
- set(text) {
72
- this.placeDescription = text
73
-
74
- if (!this.autocomplete) return
59
+ watch: {
60
+ place(place) {
61
+ if (!place || !place.place_id) {
62
+ this.place = null
63
+ return
64
+ }
75
65
 
76
- if (!text) {
66
+ this.placesService.getDetails(
67
+ {
68
+ placeId: place.place_id,
69
+ sessionToken: this.sessionToken
70
+ },
71
+ (details) => {
72
+ if (this.$refs.select) {
73
+ this.$refs.select.searchPhrase = ''
74
+ }
77
75
  this._resetSearch()
78
- return
76
+ this._formatAddressResponse(details).then((result) => {
77
+ this.$emit('input', result)
78
+ })
79
79
  }
80
-
81
- this._query(text)
82
- }
80
+ )
83
81
  }
84
82
  },
85
83
 
@@ -107,13 +105,22 @@ export default {
107
105
  this.placesService = new window.google.maps.places.PlacesService(
108
106
  this.$refs.place
109
107
  )
108
+ },
109
+
110
+ search(text) {
111
+ if (!this.autocomplete) return
110
112
 
111
- if (this.placeDescription) {
112
- this._query(this.placeDescription)
113
+ if (!text) {
114
+ this._resetSearch()
115
+ return
113
116
  }
117
+
118
+ this._query(text)
114
119
  },
115
120
 
116
121
  _query(input) {
122
+ this.$refs.select.isLoading = true
123
+
117
124
  if (!this.sessionToken) {
118
125
  this.sessionToken = new window.google.maps.places.AutocompleteSessionToken()
119
126
  }
@@ -129,10 +136,14 @@ export default {
129
136
  },
130
137
 
131
138
  _setSuggestions(data) {
139
+ this.$refs.select.isLoading = false
132
140
  this.suggestions = data || []
133
141
  },
134
142
 
135
143
  _resetSearch() {
144
+ if (this.$refs.select) {
145
+ this.$refs.select.isLoading = false
146
+ }
136
147
  this.suggestions = []
137
148
  this.sessionToken = null
138
149
  },
@@ -222,32 +233,8 @@ export default {
222
233
  })
223
234
  },
224
235
 
225
- select(place) {
226
- if (!place || !place.place_id) {
227
- this.place = null
228
- this.placeDescription = ''
229
- return
230
- }
231
-
232
- this.placesService.getDetails(
233
- {
234
- placeId: place.place_id,
235
- sessionToken: this.sessionToken
236
- },
237
- (details) => {
238
- this.place = details
239
- this.placeDescription = details.formatted_address
240
- this._resetSearch()
241
- this._formatAddressResponse(details).then((result) => {
242
- this.$emit('input', result)
243
- })
244
- }
245
- )
246
- },
247
-
248
236
  reset() {
249
237
  this.suggestions = []
250
- this.placeDescription = ''
251
238
  this.place = null
252
239
  }
253
240
  }
@@ -209,7 +209,7 @@ export default {
209
209
 
210
210
  return acc.concat({
211
211
  ...pick(
212
- 'icon,iconActive,class,expanded,target,rel,listeners,abstract,key,badge,back',
212
+ 'icon,iconBg,iconActive,class,expanded,target,rel,listeners,abstract,key,badge,back',
213
213
  props
214
214
  ),
215
215
  text,
@@ -1,18 +1,42 @@
1
1
  <template>
2
2
  <div
3
3
  class="aw-mobile-menu"
4
- :class="{ 'aw-mobile-menu--visible': show }"
4
+ :class="{
5
+ 'aw-mobile-menu--visible': show,
6
+ 'aw-mobile-menu--scrolled': scrolled,
7
+ 'aw-mobile-menu--submenu-opened': submenuOpened,
8
+ 'aw-mobile-menu--root': !submenuOpened
9
+ }"
5
10
  @click="_closeOnLinkClick"
6
11
  >
7
12
  <div class="aw-mobile-menu__header">
8
- <button
9
- v-if="submenuOpened"
10
- class="inline-flex items-center focus-outline"
11
- @click="submenuOpened = false"
12
- >
13
- <AwIconSystemMono name="angle" size="16" class="mr-2" />
14
- <span tabindex="-1">{{ $t('AwMobileMenu.back') }}</span>
15
- </button>
13
+ <template v-if="submenuOpened">
14
+ <!-- back button -->
15
+ <AwButton
16
+ theme="ghost"
17
+ color="default"
18
+ class="aw-mobile-menu__back w-10 h-10 flex-shrink-0"
19
+ content-class="p-2"
20
+ @click="submenuOpened = false"
21
+ >
22
+ <template #icon>
23
+ <AwIconSystemMono name="arrow" size="16" />
24
+ </template>
25
+ <span class="sr-only">
26
+ {{ $t('AwMobileMenu.back') }}
27
+ </span>
28
+ </AwButton>
29
+
30
+ <!-- subtitle -->
31
+ <AwHeadline
32
+ v-if="submenuTitle"
33
+ class="aw-mobile-menu__submenu-title truncate pr-2"
34
+ >
35
+ {{ submenuTitle }}
36
+ </AwHeadline>
37
+ </template>
38
+
39
+ <!-- theme switcher -->
16
40
  <AwSwitcher
17
41
  v-else
18
42
  v-model="isDarkTheme"
@@ -25,28 +49,50 @@
25
49
  />
26
50
 
27
51
  <!-- close button -->
28
- <button
29
- class="aw-mobile-menu__close focus-outline"
52
+ <AwButton
53
+ theme="ghost"
54
+ color="default"
55
+ class="aw-mobile-menu__close w-10 h-10 flex-shrink-0"
56
+ content-class="p-2"
30
57
  @click="show = false"
31
58
  >
32
- <AwIconSystemMono name="close" size="16" tabindex="-1" />
59
+ <template #icon>
60
+ <AwIconSystemMono name="close" size="16" />
61
+ </template>
33
62
  <span class="sr-only">
34
63
  {{ $t('AwMobileMenu.close') }}
35
64
  </span>
36
- </button>
65
+ </AwButton>
37
66
  </div>
38
67
 
39
68
  <!-- user -->
40
69
  <div v-if="user" v-show="!submenuOpened" class="aw-mobile-menu__user">
41
- <AwAvatar :src="user.src" :name="user.name" size="148" />
42
- <span class="aw-mobile-menu__user-name truncate">
70
+ <AwAvatar :src="user.src" :name="user.name" size="56" />
71
+ <AwHeadline tag="span" class="aw-mobile-menu__user-name truncate">
43
72
  {{ user.name }}
44
- </span>
45
- <span class="aw-mobile-menu__user-desc truncate">
73
+ </AwHeadline>
74
+ <AwDescription class="aw-mobile-menu__user-desc truncate">
46
75
  {{ user.description }}
47
- </span>
76
+ </AwDescription>
77
+
78
+ <NLink
79
+ v-if="profileUrl"
80
+ :to="profileUrl"
81
+ :aria-label="$t('AwMobileMenu.profile')"
82
+ class="aw-mobile-menu__user-link"
83
+ >
84
+ <AwIconSystemMono name="angle" rotate="180" />
85
+ </NLink>
48
86
  </div>
49
87
 
88
+ <slot v-if="!submenuOpened" name="before-mobile-menu">
89
+ <Component
90
+ v-if="beforeMobileMenuComponent"
91
+ :is="beforeMobileMenuComponent.is"
92
+ v-bind="beforeMobileMenuComponent.props"
93
+ />
94
+ </slot>
95
+
50
96
  <!-- top level menu -->
51
97
  <AwMobileMenuNav
52
98
  v-show="!submenuOpened"
@@ -84,7 +130,7 @@
84
130
  />
85
131
  </template>
86
132
 
87
- <slot name="after-mobile-menu">
133
+ <slot v-if="!submenuOpened" name="after-mobile-menu">
88
134
  <Component
89
135
  v-if="afterMobileMenuComponent"
90
136
  :is="afterMobileMenuComponent.is"
@@ -129,7 +175,9 @@ export default {
129
175
 
130
176
  data() {
131
177
  return {
178
+ scrolled: false,
132
179
  submenuOpened: false,
180
+ submenuTitle: '',
133
181
  submenu: []
134
182
  }
135
183
  },
@@ -138,9 +186,14 @@ export default {
138
186
  ...mapGetters('awesIo', [
139
187
  'user',
140
188
  'logoComponent',
141
- 'afterMobileMenuComponent'
189
+ 'afterMobileMenuComponent',
190
+ 'beforeMobileMenuComponent'
142
191
  ]),
143
192
 
193
+ profileUrl() {
194
+ return pathOr(null, 'awesIo.profileUrl', this.$store.state)
195
+ },
196
+
144
197
  mainMenu() {
145
198
  return viewOr([], lensProp('mainMenu'), this.layoutProvider).filter(
146
199
  ({ is }) => !is
@@ -196,11 +249,12 @@ export default {
196
249
  })
197
250
  } else {
198
251
  enableBodyScroll(this.$el)
199
-
200
252
  // reset submenu
201
253
  this.submenuOpened = false
254
+ this.submenuTitle = ''
202
255
  this.submenu = []
203
256
  }
257
+ this._triggerScrollListener(isVisible)
204
258
  },
205
259
  immediate: true
206
260
  },
@@ -216,7 +270,10 @@ export default {
216
270
  if (typeof this._unwatch === 'function') {
217
271
  this._unwatch()
218
272
  }
273
+
219
274
  this.$el && enableBodyScroll(this.$el)
275
+
276
+ this._triggerScrollListener(false)
220
277
  },
221
278
 
222
279
  methods: {
@@ -231,9 +288,31 @@ export default {
231
288
  ? [{ text, children: submenu }].concat(submenuDeep)
232
289
  : submenuDeep
233
290
 
291
+ this.submenuTitle = text
234
292
  this.submenuOpened = !!this.submenu.length
235
293
  },
236
294
 
295
+ _triggerScrollListener(on = false) {
296
+ if (!this.$el) return
297
+
298
+ const method = (on ? 'add' : 'remove') + 'EventListener'
299
+ this.$el[method]('scroll', this._onScroll, { passive: true })
300
+
301
+ if (on) {
302
+ this._onScroll({ target: this.$el })
303
+ }
304
+ },
305
+
306
+ _onScroll($event) {
307
+ if ($event.target.scrollTop > 30 && !this.scrolled) {
308
+ this.scrolled = true
309
+ }
310
+
311
+ if ($event.target.scrollTop <= 30 && this.scrolled) {
312
+ this.scrolled = false
313
+ }
314
+ },
315
+
237
316
  _closeOnLinkClick($event) {
238
317
  const link = $event.target.matches('a')
239
318
  ? $event.target
@@ -7,12 +7,17 @@
7
7
  v-on="$listeners"
8
8
  >
9
9
  <slot>
10
- <AwIcon
10
+ <span
11
11
  v-if="icon"
12
- :name="(active && iconActive) || icon"
13
- size="24"
14
- class="aw-mobile-menu-item__icon"
15
- />
12
+ class="aw-mobile-menu-item__icon-bg"
13
+ :style="iconColor"
14
+ >
15
+ <AwIcon
16
+ :name="(active && iconActive) || icon"
17
+ size="24"
18
+ class="aw-mobile-menu-item__icon"
19
+ />
20
+ </span>
16
21
  <span class="aw-mobile-menu-item__text" tabindex="-1">
17
22
  {{ text }}
18
23
  <span
@@ -25,14 +30,12 @@
25
30
  <AwIconSystemMono
26
31
  v-if="_linkExternal"
27
32
  name="external"
28
- size="20"
29
33
  class="aw-mobile-menu-item__arrow"
30
34
  />
31
35
  <AwIconSystemMono
32
36
  v-else-if="arrow"
33
37
  name="angle"
34
38
  rotate="180"
35
- size="20"
36
39
  class="aw-mobile-menu-item__arrow"
37
40
  />
38
41
  </slot>
@@ -68,6 +71,11 @@ export default {
68
71
  default: ''
69
72
  },
70
73
 
74
+ iconBg: {
75
+ type: String,
76
+ default: ''
77
+ },
78
+
71
79
  iconActive: {
72
80
  type: String,
73
81
  default: ''
@@ -81,6 +89,17 @@ export default {
81
89
  arrow: Boolean,
82
90
 
83
91
  active: Boolean
92
+ },
93
+
94
+ computed: {
95
+ iconColor() {
96
+ return this.iconBg
97
+ ? {
98
+ backgroundColor: this.iconBg,
99
+ color: '#fff'
100
+ }
101
+ : null
102
+ }
84
103
  }
85
104
  }
86
105
  </script>
@@ -10,7 +10,7 @@
10
10
  <AwMobileMenuItem
11
11
  v-bind="_getItemProps(item)"
12
12
  :href="_getChildrenCount(item) ? null : item.href"
13
- :arrow="!!_getChildrenCount(item)"
13
+ :arrow="!!(item.href || _getChildrenCount(item))"
14
14
  :active="isActive(item)"
15
15
  v-on="
16
16
  _getChildrenCount(item)
package/lang/de.js CHANGED
@@ -22,7 +22,8 @@ export const AwMobileMenu = {
22
22
  mainMenu: 'Hauptmenü',
23
23
  secondaryMenu: 'Sekundäres Menü',
24
24
  userMenu: 'Benutzermenü',
25
- logout: 'Abmelden'
25
+ logout: 'Abmelden',
26
+ profile: 'Benutzerprofil'
26
27
  }
27
28
 
28
29
  export const AwCalendar = {
package/lang/en.js CHANGED
@@ -22,7 +22,8 @@ export const AwMobileMenu = {
22
22
  mainMenu: 'Main menu',
23
23
  secondaryMenu: 'Secondary menu',
24
24
  userMenu: 'User menu',
25
- logout: 'Logout'
25
+ logout: 'Logout',
26
+ profile: 'User profile'
26
27
  }
27
28
 
28
29
  export const AwCalendar = {
package/lang/ru.js CHANGED
@@ -22,7 +22,8 @@ export const AwMobileMenu = {
22
22
  mainMenu: 'Главное меню',
23
23
  secondaryMenu: 'Дополнительное меню',
24
24
  userMenu: 'Меню пользователя',
25
- logout: 'Выход'
25
+ logout: 'Выход',
26
+ profile: 'Настройки пользователя'
26
27
  }
27
28
 
28
29
  export const AwCalendar = {
package/lang/uk.js CHANGED
@@ -22,7 +22,8 @@ export const AwMobileMenu = {
22
22
  mainMenu: 'Головне меню',
23
23
  secondaryMenu: 'Додаткове меню',
24
24
  userMenu: 'Меню користувача',
25
- logout: 'Вихід'
25
+ logout: 'Вихід',
26
+ profile: 'Налаштування користувача'
26
27
  }
27
28
 
28
29
  export const AwCalendar = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awes-io/ui",
3
- "version": "2.38.0",
3
+ "version": "2.40.1",
4
4
  "description": "User Interface (UI) components",
5
5
  "keywords": [
6
6
  "ui",
@@ -124,5 +124,5 @@
124
124
  "vue-template-compiler": "^2.6.10",
125
125
  "webfonts-generator": "^0.4.0"
126
126
  },
127
- "gitHead": "2b9497ac41e66479e4305edeb125e7234add8a51"
127
+ "gitHead": "0a0675bf896822cd1b4bac564cb0b28b79a96c55"
128
128
  }
package/store/awesIo.js CHANGED
@@ -31,6 +31,7 @@ export const state = () => ({
31
31
  user: []
32
32
  },
33
33
  mobileMenuOpened: false,
34
+ beforeMobileMenu: null,
34
35
  afterMobileMenu: null,
35
36
 
36
37
  headerNotification: null,
@@ -106,6 +107,10 @@ export const getters = {
106
107
  }
107
108
  },
108
109
 
110
+ beforeMobileMenuComponent(state) {
111
+ return state.beforeMobileMenu
112
+ },
113
+
109
114
  afterMobileMenuComponent(state) {
110
115
  return state.afterMobileMenu
111
116
  }
@@ -174,6 +179,12 @@ export const mutations = {
174
179
  }
175
180
  },
176
181
 
182
+ SET_BEFORE_MOBILE_MENU(state, payload) {
183
+ if (payload && payload.component) {
184
+ state.beforeMobileMenu = payload.component
185
+ }
186
+ },
187
+
177
188
  SET_AFTER_MOBILE_MENU(state, payload) {
178
189
  if (payload && payload.component) {
179
190
  state.afterMobileMenu = payload.component