@awes-io/ui 2.34.1 → 2.37.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.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,62 @@
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.37.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.36.0...@awes-io/ui@2.37.0) (2021-12-28)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **aw-birthday-picker:** global dayjs with leap year plugin used instead of custom ([047890f](https://github.com/awes-io/client/commit/047890ff1eb26923f455a64dfd12b5a6c5c972c8))
12
+
13
+
14
+ ### Features
15
+
16
+ * scroll buttons collabsing added ([b773080](https://github.com/awes-io/client/commit/b77308027776ca4c2aba94753ec0826819d090c3))
17
+
18
+
19
+
20
+
21
+
22
+ # [2.36.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.35.0...@awes-io/ui@2.36.0) (2021-12-10)
23
+
24
+
25
+ ### Features
26
+
27
+ * logo switching added ([e5e7328](https://github.com/awes-io/client/commit/e5e732812e9acb5c3a6c810d9a7346affa422988))
28
+
29
+
30
+
31
+
32
+
33
+ # [2.35.0](https://github.com/awes-io/client/compare/@awes-io/ui@2.34.2...@awes-io/ui@2.35.0) (2021-12-04)
34
+
35
+
36
+ ### Bug Fixes
37
+
38
+ * default date format ([3435466](https://github.com/awes-io/client/commit/3435466e8ff789d64682ba99e5125eaa5dabf723))
39
+
40
+
41
+ ### Features
42
+
43
+ * **aw-birthday-picker:** leap year support ([43805c3](https://github.com/awes-io/client/commit/43805c3cecacec61340f512fe8e9dfcfae4ba1fb))
44
+ * **aw-date:** editable format validation added ([307ec9e](https://github.com/awes-io/client/commit/307ec9e662f32839178cab4d3c14e506b2abbc97))
45
+ * **aw-date:** editable input ([f6f7237](https://github.com/awes-io/client/commit/f6f723755f3cc9ca1c09d33860ea38c403c023ff))
46
+
47
+
48
+
49
+
50
+
51
+ ## [2.34.2](https://github.com/awes-io/client/compare/@awes-io/ui@2.34.1...@awes-io/ui@2.34.2) (2021-11-26)
52
+
53
+
54
+ ### Bug Fixes
55
+
56
+ * **aw-tel:** type button added to dropdown button ([c1369cd](https://github.com/awes-io/client/commit/c1369cd16efb9b569f5a41a94da2eee746a8e40d))
57
+
58
+
59
+
60
+
61
+
6
62
  ## [2.34.1](https://github.com/awes-io/client/compare/@awes-io/ui@2.34.0...@awes-io/ui@2.34.1) (2021-11-25)
7
63
 
8
64
 
@@ -10,6 +10,7 @@
10
10
  @import './badge.css';
11
11
  @import './birthday-picker.css';
12
12
  @import './button.css';
13
+ @import './button-fixed.css';
13
14
  @import './button-nav.css';
14
15
 
15
16
  @import './calendar.css';
@@ -0,0 +1,49 @@
1
+ .aw-button-fixed {
2
+ display: flex;
3
+ align-items: center;
4
+
5
+ padding: 0.75rem 1rem;
6
+ min-width: 3.5rem;
7
+ min-height: 3.5rem;
8
+ /* border-radius: 1rem; */
9
+
10
+ font-size: 0.75rem;
11
+ font-weight: bold;
12
+ letter-spacing: 0.09375rem;
13
+ text-transform: uppercase;
14
+
15
+ background-color: rgba(var(--btn-bg), 1);
16
+ color: rgba(var(--btn-fg), 1);
17
+
18
+ box-shadow: 0px 0.25rem 0.5rem rgba(var(--btn-bg), 0.2);
19
+
20
+ &__text {
21
+ flex-shrink: 1;
22
+ max-width: 1px;
23
+ margin-right: -1px;
24
+
25
+ opacity: 0.1;
26
+ transition-property: max-width, margin, opacity;
27
+ transition-duration: 120ms;
28
+
29
+ &--expanded {
30
+ max-width: 16rem;
31
+ margin-right: 0.75em;
32
+ opacity: 1;
33
+ transition-timing-function: ease-out;
34
+ transition-duration: 240ms;
35
+ }
36
+ }
37
+
38
+ &:hover {
39
+ background-image: linear-gradient(rgba(var(--btn-fg), 0.15), rgba(var(--btn-fg), 0.15));
40
+ }
41
+
42
+ &:active {
43
+ transform: translateY(1px);
44
+ }
45
+
46
+ &:focus-visible {
47
+ outline: theme('focusOutline');
48
+ }
49
+ }
@@ -6,9 +6,19 @@
6
6
  }
7
7
 
8
8
  &__fixed-btns {
9
+ display: flex;
10
+ flex-direction: column;
11
+ align-items: flex-end;
12
+
13
+ max-width: calc(100vw - 2 * theme('spacing.4', 1rem));
14
+
9
15
  position: fixed;
10
16
  right: theme('spacing.4', 1rem);
11
- bottom: calc(env(safe-area-inset-bottom, 0) + var(--page-buttons-bottom, theme('spacing.4', 1rem)));
17
+ bottom: calc(env(safe-area-inset-bottom, 0) + var(--page-buttons-bottom, 0));
12
18
  z-index: 2;
19
+
20
+ & > * {
21
+ margin-bottom: 1rem;
22
+ }
13
23
  }
14
24
  }
@@ -60,3 +60,28 @@ export const getEventTargetAttribute = ($event, attrName, bound = null) => {
60
60
 
61
61
  return null
62
62
  }
63
+
64
+ /**
65
+ * Detect if client supports passive event listeners
66
+ * @return {Boolean} true if supports
67
+ */
68
+ export const supportsPassive = () => {
69
+ let supports = false
70
+
71
+ if (
72
+ window &&
73
+ typeof window.addEventListener === 'function' &&
74
+ typeof Object.defineProperty === 'function'
75
+ ) {
76
+ const options = Object.defineProperty({}, 'passive', {
77
+ // eslint-disable-next-line getter-return
78
+ get() {
79
+ supports = true
80
+ }
81
+ })
82
+
83
+ window.addEventListener('_', null, options)
84
+ }
85
+
86
+ return supports
87
+ }
@@ -31,7 +31,6 @@
31
31
  </template>
32
32
 
33
33
  <script>
34
- import { equals } from 'rambdax'
35
34
  import FieldMixin from '@AwMixins/field'
36
35
  import ErrorMixin from '@AwMixins/error'
37
36
 
@@ -89,16 +88,16 @@ export default {
89
88
  _onChange($event) {
90
89
  let value = this._createValue($event.target.checked)
91
90
 
92
- if (equals(value, this.checked)) {
93
- $event.target.checked = this.isChecked
94
- return
95
- }
96
-
97
91
  if (this.hasError) {
98
92
  this.setError('')
99
93
  }
100
94
 
101
95
  this.$emit('change', value)
96
+
97
+ // sync checkbox state
98
+ this.$nextTick(() => {
99
+ $event.target.checked = this.isChecked
100
+ })
102
101
  },
103
102
 
104
103
  _createValue(isChecked) {
@@ -20,11 +20,21 @@ export default {
20
20
  default: true
21
21
  },
22
22
 
23
+ justify: {
24
+ type: String,
25
+ default: ''
26
+ },
27
+
28
+ align: {
29
+ type: String,
30
+ default: ''
31
+ },
32
+
23
33
  vertical: Boolean
24
34
  },
25
35
 
26
36
  render(h) {
27
- const { tag, gap, wrapChildren, vertical } = this.$props
37
+ const { tag, gap, wrapChildren, vertical, align, justify } = this.$props
28
38
  const children = this.$scopedSlots.default
29
39
  ? this.$scopedSlots.default()
30
40
  : []
@@ -44,7 +54,12 @@ export default {
44
54
  staticClass: 'aw-flow__wrap',
45
55
  class: {
46
56
  'aw-flow__wrap--children': !wrapChildren,
47
- 'aw-flow__wrap--vertical': vertical
57
+ 'aw-flow__wrap--vertical': vertical,
58
+ 'justify-start': justify === 'center',
59
+ 'justify-end': justify === 'end',
60
+ 'items-start': align === 'start',
61
+ 'items-center': align === 'center',
62
+ 'items-end': align === 'end'
48
63
  }
49
64
  },
50
65
  children.reduce((acc, vNode) => {
@@ -26,25 +26,27 @@ export default {
26
26
  render(h, { props: { name, size, viewBox }, data }) {
27
27
  const attrs = data.attrs || {}
28
28
 
29
- return h('SvgIcon', {
30
- props: { name, viewBox },
31
- staticClass: 'aw-icon',
32
- class: [
33
- data.class,
34
- data.staticClass,
35
- {
36
- 'aw-icon--size-text':
37
- !size && isNil(attrs.width) && isNil(attrs.height)
38
- }
39
- ],
40
- style: [data.style, data.staticStyle],
41
- attrs: {
42
- 'aria-hidden': true,
43
- width: size || null,
44
- height: size || null,
45
- ...attrs
46
- }
47
- })
29
+ return name
30
+ ? h('SvgIcon', {
31
+ props: { name, viewBox },
32
+ staticClass: 'aw-icon',
33
+ class: [
34
+ data.class,
35
+ data.staticClass,
36
+ {
37
+ 'aw-icon--size-text':
38
+ !size && isNil(attrs.width) && isNil(attrs.height)
39
+ }
40
+ ],
41
+ style: [data.style, data.staticStyle],
42
+ attrs: {
43
+ 'aria-hidden': true,
44
+ width: size || null,
45
+ height: size || null,
46
+ ...attrs
47
+ }
48
+ })
49
+ : null
48
50
  }
49
51
  }
50
52
  </script>
@@ -28,7 +28,7 @@
28
28
  ]"
29
29
  tabindex="-1"
30
30
  >
31
- <slot name="icon">
31
+ <slot name="icon" v-bind="{ icon, iconSize }">
32
32
  <AwIcon
33
33
  v-if="icon"
34
34
  :name="icon"
@@ -755,6 +755,9 @@ export default {
755
755
  },
756
756
 
757
757
  _selectIndex(index) {
758
+ const _option = this.optionsList.find((opt) => opt.index === index)
759
+ if (_option && _option.disabled) return
760
+
758
761
  if (this.multiple) {
759
762
  const selected = this.selectedIndexes
760
763
 
@@ -38,7 +38,10 @@
38
38
  :name="_inputKeys.year"
39
39
  :label="$t('AwBirthdayPicker.year')"
40
40
  :clearable="!showYear"
41
+ :option-disabled="isOptionDisabled"
41
42
  class="w-full"
43
+ track-by="year"
44
+ option-label="year"
42
45
  @input="checkMaxDay"
43
46
  @clear="clearYear"
44
47
  />
@@ -120,7 +123,7 @@ export default {
120
123
  },
121
124
 
122
125
  monthsList() {
123
- const date = this.dayjs()
126
+ const date = this.$dayjs()
124
127
  return [...Array(12).keys()].map((el) => ({
125
128
  value: el,
126
129
  text: date.month(el).format('MMMM')
@@ -128,15 +131,9 @@ export default {
128
131
  },
129
132
 
130
133
  daysList() {
131
- const date = this.dayjs()
134
+ const date = this.$dayjs().year(this.year || 2000)
132
135
 
133
- if (this.year) {
134
- date.year(this.year)
135
- }
136
-
137
- const maxDays = this.dayjs()
138
- .month(this.month || 0)
139
- .daysInMonth()
136
+ const maxDays = date.month(this.month || 0).daysInMonth()
140
137
 
141
138
  const arr = [...Array(maxDays + 1).keys()]
142
139
  arr.shift()
@@ -144,8 +141,13 @@ export default {
144
141
  },
145
142
 
146
143
  yearsList() {
147
- const current = this.dayjs().year()
148
- return [...Array(101).keys()].map((el) => current - el)
144
+ const current = this.$dayjs().year()
145
+ return [...Array(101).keys()].map((el) => ({
146
+ year: current - el,
147
+ isLeapYear: this.$dayjs()
148
+ .year(current - el)
149
+ .isLeapYear()
150
+ }))
149
151
  }
150
152
  },
151
153
 
@@ -171,25 +173,10 @@ export default {
171
173
  this.emit()
172
174
  },
173
175
 
174
- // parseString(str) {
175
- // if (!str) return
176
-
177
- // const d = this.toDayjs(str)
178
- // this.day = d.date()
179
- // this.month = d.month()
180
-
181
- // const y = d.year()
182
- // const yString = this.getYearString(str)
183
-
184
- // if (yString.includes(y)) {
185
- // this.year = y
186
- // this.isYearHidden = false
187
- // }
188
- // },
189
-
190
176
  emit() {
191
177
  if (!isNil(this.month) && this.day) {
192
- let d = this.dayjs()
178
+ let d = this.$dayjs()
179
+ .year(this.year || 2000)
193
180
  .month(this.month)
194
181
  .date(this.day)
195
182
  let formatVal = this.shortParseFormat || 'MM-DD'
@@ -210,6 +197,14 @@ export default {
210
197
  this.isYearHidden = true
211
198
  this.year = null
212
199
  this.emit()
200
+ },
201
+
202
+ isOptionDisabled(option) {
203
+ if (this.month === 1 && this.day === 29) {
204
+ return !option.isLeapYear
205
+ }
206
+
207
+ return false
213
208
  }
214
209
  }
215
210
  }
@@ -5,9 +5,11 @@
5
5
  :value="inputValue"
6
6
  :prefix="prefix"
7
7
  :postfix="postfix"
8
- readonly
8
+ :pattern="_editable ? mask : null"
9
+ :readonly="!_editable"
9
10
  @focus="isOpened = true"
10
11
  @click.stop="isOpened = true"
12
+ @input="onInput"
11
13
  >
12
14
  <template #icon>
13
15
  <AwButton
@@ -107,7 +109,12 @@ export default {
107
109
  /**
108
110
  * Show clear button if value exists
109
111
  */
110
- clearable: Boolean
112
+ clearable: Boolean,
113
+
114
+ /**
115
+ * If false input is readonly
116
+ */
117
+ editable: Boolean
111
118
  },
112
119
 
113
120
  data() {
@@ -118,6 +125,12 @@ export default {
118
125
  },
119
126
 
120
127
  computed: {
128
+ _editable() {
129
+ return (
130
+ this.editable && !this.range && /^[DMY\W]+$/.test(this.format)
131
+ )
132
+ },
133
+
121
134
  inputValue() {
122
135
  const result = []
123
136
 
@@ -170,6 +183,10 @@ export default {
170
183
  }
171
184
 
172
185
  return views
186
+ },
187
+
188
+ mask() {
189
+ return this.format.replace(/[DMY]/g, '#')
173
190
  }
174
191
  },
175
192
 
@@ -224,6 +241,16 @@ export default {
224
241
  'resize',
225
242
  this._checkMaxViewsOnResize
226
243
  )
244
+ },
245
+
246
+ onInput(val) {
247
+ if (val.length === this.format.length) {
248
+ const d = this.$dayjs(val, this.format)
249
+ if (d.isValid()) {
250
+ this.viewDate = d
251
+ this.$emit('input', this._getNonRangeValue(d))
252
+ }
253
+ }
227
254
  }
228
255
  }
229
256
  }
@@ -43,7 +43,7 @@ export default {
43
43
  }
44
44
 
45
45
  let age = null
46
- const now = this.dayjs()
46
+ const now = this.$dayjs()
47
47
  const date = this.toDayjs(this.date)
48
48
 
49
49
  const isYearPresent = this.getYearString(this.date).includes(
@@ -27,6 +27,7 @@
27
27
  </template>
28
28
  <template #prefix>
29
29
  <button
30
+ type="button"
30
31
  class="aw-tel__country-toggler focus-outline"
31
32
  @click="_openCountriesDropdown"
32
33
  >
@@ -9,7 +9,7 @@
9
9
  <slot name="heading" v-bind="{ titleTag, title, breadcrumb }">
10
10
  <AwPageHeadline
11
11
  :style="{
12
- '--page-buttons-bottom': _hideBottomBar ? null : '5rem'
12
+ '--page-buttons-bottom': _hideBottomBar ? null : '4rem'
13
13
  }"
14
14
  :title="_title"
15
15
  :breadcrumb="breadcrumb"
@@ -4,6 +4,7 @@
4
4
  <AwFlow
5
5
  v-if="isExpanded && splitButtons.buttons.length"
6
6
  tag="div"
7
+ justify="end"
7
8
  class="aw-page-menu-buttons__expanded-btns"
8
9
  >
9
10
  <AwButton
@@ -34,28 +35,27 @@
34
35
  </AwContextMenu>
35
36
 
36
37
  <!-- fixed button -->
37
- <AwFlow
38
+ <div
38
39
  v-if="!isExpanded && splitButtons.fixed"
39
40
  class="aw-page-menu-buttons__fixed-btns"
40
- tag="div"
41
- vertical
42
41
  >
43
- <AwButton
42
+ <AwButtonFixed
44
43
  v-for="({ listeners, tooltip, ...attrs },
45
44
  i) in splitButtons.fixed"
46
45
  :key="i"
47
- size="lg"
46
+ :expanded="isInTopPosition"
48
47
  v-tooltip="tooltip"
49
48
  v-bind="attrs"
50
49
  v-on="listeners"
51
50
  />
52
- </AwFlow>
51
+ </div>
53
52
  </div>
54
53
  </template>
55
54
 
56
55
  <script>
57
56
  import { isType, defaultTo } from 'rambdax'
58
57
  import { downloadFile } from '@AwUtils/download'
58
+ import { supportsPassive } from '@AwUtils/events'
59
59
 
60
60
  const toIconButton = (props) => ({
61
61
  ...props,
@@ -66,6 +66,10 @@ const toIconButton = (props) => ({
66
66
  export default {
67
67
  name: 'AwPageMenuButtons',
68
68
 
69
+ components: {
70
+ AwButtonFixed: () => import('@AwPages/_AwButtonFixed.vue')
71
+ },
72
+
69
73
  props: {
70
74
  items: {
71
75
  type: Array,
@@ -75,12 +79,20 @@ export default {
75
79
  breakpoint: {
76
80
  type: String,
77
81
  default: 'lg'
82
+ },
83
+
84
+ /* max window scroll when fixed buttons expanded */
85
+ /* pass -1 to collapse button eventually */
86
+ expandOffset: {
87
+ type: Number,
88
+ default: 150 // px
78
89
  }
79
90
  },
80
91
 
81
92
  data() {
82
93
  return {
83
- isDownloading: {}
94
+ isDownloading: {},
95
+ isInTopPosition: true
84
96
  }
85
97
  },
86
98
 
@@ -121,6 +133,10 @@ export default {
121
133
  }
122
134
  },
123
135
 
136
+ mounted() {
137
+ this._initScrollListener()
138
+ },
139
+
124
140
  methods: {
125
141
  _getVisiblity(show) {
126
142
  return isType('Function', show) ? show(this) : defaultTo(true, show)
@@ -145,6 +161,31 @@ export default {
145
161
  } finally {
146
162
  this.$delete(this.isDownloading, url)
147
163
  }
164
+ },
165
+
166
+ _initScrollListener() {
167
+ if (this.expandOffset < 0) {
168
+ this.isInTopPosition = false
169
+ return
170
+ }
171
+
172
+ const opts = supportsPassive()
173
+ ? {
174
+ passive: true
175
+ }
176
+ : false
177
+
178
+ const detectTopPosition = () => {
179
+ this.isInTopPosition = window.pageYOffset < this.expandOffset
180
+ }
181
+
182
+ detectTopPosition()
183
+
184
+ window.addEventListener('scroll', detectTopPosition, opts)
185
+
186
+ this.$once('hook:beforeDestroy', () => {
187
+ window.removeEventListener('scroll', detectTopPosition, opts)
188
+ })
148
189
  }
149
190
  },
150
191
 
@@ -0,0 +1,45 @@
1
+ <template>
2
+ <Component
3
+ :is="_linkComponent"
4
+ v-bind="_linkAttrs"
5
+ :style="buttonStyle"
6
+ class="aw-button-fixed"
7
+ v-on="$listeners"
8
+ >
9
+ <span
10
+ v-if="text"
11
+ class="aw-button-fixed__text truncate"
12
+ :class="{ 'aw-button-fixed__text--expanded': expanded }"
13
+ >
14
+ <slot>{{ text }}</slot>
15
+ </span>
16
+ <slot name="icon">
17
+ <AwIcon :name="icon" size="24" class="flex-shrink-0" />
18
+ </slot>
19
+ </Component>
20
+ </template>
21
+
22
+ <script>
23
+ import linkMixin from '@AwMixins/link'
24
+ import buttonMixin from '@AwMixins/button'
25
+
26
+ export default {
27
+ name: 'AwButtonFixed',
28
+
29
+ mixins: [linkMixin, buttonMixin],
30
+
31
+ props: {
32
+ icon: {
33
+ type: String,
34
+ required: true
35
+ },
36
+
37
+ text: {
38
+ type: String,
39
+ default: ''
40
+ },
41
+
42
+ expanded: Boolean
43
+ }
44
+ }
45
+ </script>
@@ -27,23 +27,14 @@
27
27
  </template>
28
28
 
29
29
  <script>
30
+ import { mapGetters } from 'vuex'
30
31
  import { pathOr } from 'rambdax'
31
32
 
32
33
  export default {
33
34
  name: 'AwLayoutCenter',
34
35
 
35
36
  computed: {
36
- isDark() {
37
- return this.$store.getters['awesIo/isDarkTheme']
38
- },
39
-
40
- logo() {
41
- return pathOr(
42
- null,
43
- ['$awes', '_config', this.isDark ? 'dark' : 'default', 'logo'],
44
- this
45
- )
46
- },
37
+ ...mapGetters('awesIo', ['isDarkTheme', 'logo']),
47
38
 
48
39
  background() {
49
40
  const { src, ...background } = pathOr(
@@ -51,7 +42,7 @@ export default {
51
42
  [
52
43
  '$awes',
53
44
  '_config',
54
- this.isDark ? 'dark' : 'default',
45
+ this.isDarkTheme ? 'dark' : 'default',
55
46
  'background'
56
47
  ],
57
48
  this
@@ -0,0 +1,18 @@
1
+ <template functional>
2
+ <NLink
3
+ to="/"
4
+ class="aw-layout-logo"
5
+ :class="[data.class, data.staticClass]"
6
+ >
7
+ <img v-if="props.logo" v-bind="props.logo" />
8
+ <span class="sr-only">
9
+ {{ $t('AwLayoutDefault.homepage') }}
10
+ </span>
11
+ </NLink>
12
+ </template>
13
+
14
+ <script>
15
+ export default {
16
+ name: 'AwLayoutLogo'
17
+ }
18
+ </script>
@@ -5,10 +5,12 @@
5
5
  'aw-layout-menu--no-submenu': hideAside || !hasSubmenu
6
6
  }"
7
7
  >
8
- <slot name="logo" v-bind="logo">
9
- <NLink to="/" class="aw-layout-menu__logo">
10
- <img v-if="logo" v-bind="logo" />
11
- </NLink>
8
+ <slot name="logo">
9
+ <Component
10
+ :is="logoComponent.is"
11
+ v-bind="logoComponent.props"
12
+ class="aw-layout-menu__logo"
13
+ />
12
14
  </slot>
13
15
 
14
16
  <div class="aw-layout-menu__menu">
@@ -62,6 +64,7 @@
62
64
  import { mapGetters } from 'vuex'
63
65
  import { pathOr, viewOr, lensProp, omit } from 'rambdax'
64
66
  import AwMenuItemIcon from '@AwLayouts/_AwMenuItemIcon.vue'
67
+ import AwLayoutLogo from '@AwLayouts/_AwLayoutLogo.vue'
65
68
  import AwUserMenu from '@AwLayouts/_AwUserMenu.vue'
66
69
  import AwNav from '@AwLayouts/_AwNav.vue'
67
70
 
@@ -70,6 +73,7 @@ export default {
70
73
 
71
74
  components: {
72
75
  AwMenuItemIcon,
76
+ AwLayoutLogo,
73
77
  AwUserMenu,
74
78
  AwNav
75
79
  },
@@ -85,7 +89,7 @@ export default {
85
89
  },
86
90
 
87
91
  computed: {
88
- ...mapGetters('awesIo', ['user', 'isDarkTheme']),
92
+ ...mapGetters('awesIo', ['user', 'logoComponent']),
89
93
 
90
94
  mainMenu() {
91
95
  return viewOr([], lensProp('mainMenu'), this.layoutProvider)
@@ -115,14 +119,6 @@ export default {
115
119
  this.activeMenu
116
120
  )
117
121
  : ''
118
- },
119
-
120
- logo() {
121
- return pathOr(
122
- null,
123
- ['_config', this.isDarkTheme ? 'dark' : 'default', 'logo'],
124
- this.$awes
125
- )
126
122
  }
127
123
  },
128
124
 
@@ -84,14 +84,21 @@
84
84
  />
85
85
  </template>
86
86
 
87
+ <slot name="after-mobile-menu">
88
+ <Component
89
+ v-if="afterMobileMenuComponent"
90
+ :is="afterMobileMenuComponent.is"
91
+ v-bind="afterMobileMenuComponent.props"
92
+ />
93
+ </slot>
94
+
87
95
  <!-- logo -->
88
96
  <slot name="logo" v-bind="logo">
89
- <NLink to="/" class="aw-mobile-menu__logo">
90
- <img v-if="logo" v-bind="logo" />
91
- <span class="sr-only">
92
- {{ $t('AwMobileMenu.home') }}
93
- </span>
94
- </NLink>
97
+ <Component
98
+ :is="logoComponent.is"
99
+ v-bind="logoComponent.props"
100
+ class="aw-mobile-menu__logo"
101
+ />
95
102
  <span class="aw-mobile-menu__version">
96
103
  {{ $t('AwMobileMenu.version', { version: $config.VERSION }) }}
97
104
  </span>
@@ -128,7 +135,11 @@ export default {
128
135
  },
129
136
 
130
137
  computed: {
131
- ...mapGetters('awesIo', ['user']),
138
+ ...mapGetters('awesIo', [
139
+ 'user',
140
+ 'logoComponent',
141
+ 'afterMobileMenuComponent'
142
+ ]),
132
143
 
133
144
  mainMenu() {
134
145
  return viewOr([], lensProp('mainMenu'), this.layoutProvider).filter(
package/lang/de.js CHANGED
@@ -53,6 +53,7 @@ export const AwCodeSnippet = {
53
53
  }
54
54
 
55
55
  export const AwLayoutDefault = {
56
+ homepage: 'Startseite',
56
57
  offline: 'Keine Internetverbindung',
57
58
  offlineText:
58
59
  'Überprüfen Sie Ihre Verbindung und versuchen Sie es erneut ...',
package/lang/en.js CHANGED
@@ -53,6 +53,7 @@ export const AwCodeSnippet = {
53
53
  }
54
54
 
55
55
  export const AwLayoutDefault = {
56
+ homepage: 'Homepage',
56
57
  offline: 'No Internet Connection',
57
58
  offlineText: 'Check your connection and try again ...',
58
59
  toggleMenu: 'Toggle mobile menu',
package/lang/ru.js CHANGED
@@ -57,6 +57,7 @@ export const AwCodeSnippet = {
57
57
  }
58
58
 
59
59
  export const AwLayoutDefault = {
60
+ homepage: 'Главная страница',
60
61
  offline: 'Нет соединения с Интернетом',
61
62
  offlineText: 'Проверьте Ваше подключение и попробуйте еще раз ...',
62
63
  toggleMenu: 'Мобильное меню',
package/lang/uk.js CHANGED
@@ -53,6 +53,7 @@ export const AwCodeSnippet = {
53
53
  }
54
54
 
55
55
  export const AwLayoutDefault = {
56
+ homepage: 'Головна сторінка',
56
57
  offline: 'Немає доступу до Інтернету',
57
58
  offlineText: 'Перевірте Ваше підключення і спробуйте ще раз ...',
58
59
  toggleMenu: 'Мобільне меню',
@@ -1,10 +1,3 @@
1
- import dayjs from 'dayjs'
2
- import customParseFormat from 'dayjs/plugin/customParseFormat'
3
- import localizedFormat from 'dayjs/plugin/localizedFormat'
4
-
5
- dayjs.extend(customParseFormat)
6
- dayjs.extend(localizedFormat)
7
-
8
1
  export default {
9
2
  props: {
10
3
  /**
@@ -26,33 +19,29 @@ export default {
26
19
  }
27
20
  },
28
21
 
29
- computed: {
30
- dayjs() {
31
- return this.$dayjs || dayjs
32
- }
33
- },
34
-
35
22
  methods: {
36
23
  toDayjs(input) {
37
24
  if (typeof input !== 'string') {
38
- return this.dayjs(input)
25
+ return this.$dayjs(input)
39
26
  }
40
27
 
41
28
  if (this.fullParseFormat) {
42
- const dLong = this.dayjs(input, this.fullParseFormat)
29
+ const dLong = this.$dayjs(input, this.fullParseFormat)
43
30
  if (dLong.isValid()) {
44
31
  return dLong
45
32
  }
46
33
  }
47
34
 
48
35
  if (this.shortParseFormat) {
49
- const dShort = this.dayjs(input, this.shortParseFormat)
36
+ const _formatWithYear = `${this.shortParseFormat}.YYYY`
37
+ const _inputWithYear = `${input}.2000` // 2000 is leap year
38
+ const dShort = this.$dayjs(_inputWithYear, _formatWithYear)
50
39
  if (dShort.isValid()) {
51
40
  return dShort
52
41
  }
53
42
  }
54
43
 
55
- return this.dayjs(input)
44
+ return this.$dayjs(input)
56
45
  },
57
46
 
58
47
  parseDate(date) {
@@ -0,0 +1,17 @@
1
+ export default {
2
+ props: {
3
+ color: {
4
+ type: String,
5
+ default: 'accent'
6
+ }
7
+ },
8
+
9
+ computed: {
10
+ buttonStyle() {
11
+ return {
12
+ '--btn-bg': `var(--c-${this.color}-rgb)`,
13
+ '--btn-fg': `var(--c-on-${this.color}-rgb)`
14
+ }
15
+ }
16
+ }
17
+ }
@@ -44,7 +44,7 @@ export const dayjs = {
44
44
  pattern: null,
45
45
  format: true
46
46
  },
47
- plugins: ['dayjs/plugin/relativeTime']
47
+ plugins: ['dayjs/plugin/relativeTime', 'dayjs/plugin/isLeapYear']
48
48
  }
49
49
 
50
50
  export const axios = {
@@ -2,7 +2,7 @@ import Vue from 'vue'
2
2
  import dayjs from 'dayjs'
3
3
 
4
4
  /* eslint-disable */
5
- <% ['dayjs/plugin/relativeTime', 'dayjs/plugin/customParseFormat', 'dayjs/plugin/localizedFormat'].concat(Array.isArray(options.dayjs.plugins) ? options.dayjs.plugins : []).filter((val, i, arr) => arr.indexOf(val) === i).forEach((plugin) => {
5
+ <% ['dayjs/plugin/relativeTime', 'dayjs/plugin/customParseFormat', 'dayjs/plugin/localizedFormat', 'dayjs/plugin/isLeapYear'].concat(Array.isArray(options.dayjs.plugins) ? options.dayjs.plugins : []).filter((val, i, arr) => arr.indexOf(val) === i).forEach((plugin) => {
6
6
  const src = plugin.src || plugin
7
7
  const name = plugin.name || src.replace('dayjs/plugin/', '')
8
8
  const options = plugin.options || {}
@@ -6,6 +6,12 @@ export default ({ store, app }) => {
6
6
  */
7
7
  if (!store.hasModule('awesIo')) {
8
8
  store.registerModule('awesIo', storeModule)
9
+
10
+ // Set default logo
11
+ store.commit('awesIo/SET_LOGO', {
12
+ default: JSON.parse('<%= JSON.stringify(options.default.logo) %>'),
13
+ dark: JSON.parse('<%= JSON.stringify(options.dark.logo) %>')
14
+ })
9
15
  }
10
16
 
11
17
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awes-io/ui",
3
- "version": "2.34.1",
3
+ "version": "2.37.0",
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": "0266a2c4725e14d5c8592275c9eab0b3a113cd0e"
127
+ "gitHead": "c1bfbdde456b9c8019674ec89b2a1e1a82987c96"
128
128
  }
package/store/awesIo.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import Vue from 'vue'
2
- import { pathOr, pick, isType } from 'rambdax'
2
+ import { pathOr, pick, isType, mergeDeepRight } from 'rambdax'
3
3
 
4
4
  const castArray = (val) => (Array.isArray(val) ? val : [])
5
5
 
@@ -20,12 +20,18 @@ export const state = () => ({
20
20
 
21
21
  profileUrl: null,
22
22
 
23
+ logo: {
24
+ default: { src: '' },
25
+ dark: { src: '' }
26
+ },
27
+
23
28
  menus: {
24
29
  main: [],
25
30
  secondary: [],
26
31
  user: []
27
32
  },
28
33
  mobileMenuOpened: false,
34
+ afterMobileMenu: null,
29
35
 
30
36
  headerNotification: null,
31
37
 
@@ -83,7 +89,26 @@ export const getters = {
83
89
  }
84
90
  },
85
91
 
86
- isDarkTheme: pathOr(false, 'isDarkTheme')
92
+ isDarkTheme: pathOr(false, 'isDarkTheme'),
93
+
94
+ logo(state, getters) {
95
+ return getters.isDarkTheme ? state.logo.dark : state.logo.default
96
+ },
97
+
98
+ logoComponent(state, getters) {
99
+ const logoComponent = pathOr(null, 'logo.component', state)
100
+
101
+ return logoComponent && logoComponent.is
102
+ ? logoComponent
103
+ : {
104
+ is: 'AwLayoutLogo',
105
+ props: { logo: getters.logo }
106
+ }
107
+ },
108
+
109
+ afterMobileMenuComponent(state) {
110
+ return state.afterMobileMenu
111
+ }
87
112
  }
88
113
 
89
114
  export const mutations = {
@@ -127,6 +152,32 @@ export const mutations = {
127
152
 
128
153
  TOGGLE_MOBILE_MENU(state, status = !state.mobileMenuOpened) {
129
154
  state.mobileMenuOpened = Boolean(status)
155
+ },
156
+
157
+ SET_LOGO(state, logo) {
158
+ if (typeof logo === 'string') {
159
+ state.logo = mergeDeepRight(state.logo, {
160
+ default: { src: logo },
161
+ dark: { src: logo }
162
+ })
163
+ } else if (typeof logo === 'object' && logo !== null) {
164
+ const _logo = {}
165
+ _logo.default = pathOr(state.logo.default, 'default', logo)
166
+ _logo.dark = pathOr(
167
+ pathOr(state.logo.dark, 'default', logo),
168
+ 'dark',
169
+ logo
170
+ )
171
+ _logo.component = pathOr(state.logo.component, 'component', logo)
172
+
173
+ state.logo = _logo
174
+ }
175
+ },
176
+
177
+ SET_AFTER_MOBILE_MENU(state, payload) {
178
+ if (payload && payload.component) {
179
+ state.afterMobileMenu = payload.component
180
+ }
130
181
  }
131
182
  }
132
183