@bildvitta/quasar-ui-asteroid 3.14.0-beta.1 → 3.14.0-beta.3
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/package.json +1 -1
- package/src/components/app-bar/QasAppBar.vue +6 -1
- package/src/components/app-bar/QasAppBar.yml +3 -0
- package/src/components/app-menu/QasAppMenu.vue +3 -2
- package/src/components/app-menu/QasAppMenu.yml +3 -0
- package/src/components/app-menu/composables/use-app-user.js +3 -0
- package/src/components/app-user/QasAppUser.vue +68 -13
- package/src/components/app-user/QasAppUser.yml +3 -0
- package/src/components/avatar/QasAvatar.vue +9 -3
- package/src/components/avatar/QasAvatar.yml +1 -1
- package/src/components/avatar/enums/AvatarColors.js +2 -1
- package/src/components/card/QasCard.vue +3 -3
- package/src/components/chart-view/QasChartView.vue +37 -9
- package/src/components/chart-view/QasChartView.yml +6 -0
- package/src/components/dialog/QasDialog.vue +29 -1
- package/src/components/drawer/QasDrawer.vue +117 -0
- package/src/components/drawer/QasDrawer.yml +57 -0
- package/src/components/infinite-scroll/QasInfiniteScroll.vue +6 -2
- package/src/components/infinite-scroll/QasInfiniteScroll.yml +22 -0
- package/src/components/layout/QasLayout.vue +83 -52
- package/src/components/layout/QasLayout.yml +5 -0
- package/src/components/layout/private/PvLayoutNotificationCard.vue +86 -0
- package/src/components/layout/private/PvLayoutNotificationsDrawer.vue +141 -0
- package/src/components/list-items/QasListItems.vue +33 -5
- package/src/components/list-items/QasListItems.yml +5 -0
- package/src/components/numeric-input/QasNumericInput.vue +2 -2
- package/src/components/uploader/private/PvUploaderGalleryCard.vue +1 -1
- package/src/components/whatsapp-link/QasWhatsappLink.vue +34 -0
- package/src/components/whatsapp-link/QasWhatsappLink.yml +18 -0
- package/src/composables/index.js +3 -0
- package/src/composables/use-notifications.js +114 -0
- package/src/css/plugins/notify.scss +40 -2
- package/src/helpers/private/has-parent-by-class-name.js +15 -0
- package/src/vue-plugin.js +5 -0
package/package.json
CHANGED
|
@@ -54,7 +54,7 @@ const props = defineProps({
|
|
|
54
54
|
}
|
|
55
55
|
})
|
|
56
56
|
|
|
57
|
-
const emit = defineEmits(['sign-out', 'toggle-menu'])
|
|
57
|
+
const emit = defineEmits(['sign-out', 'toggle-menu', 'toggle-notifications'])
|
|
58
58
|
|
|
59
59
|
const router = useRouter()
|
|
60
60
|
const screen = useScreen()
|
|
@@ -68,6 +68,7 @@ const defaultAppUserProps = computed(() => {
|
|
|
68
68
|
},
|
|
69
69
|
|
|
70
70
|
onSignOut: signOut,
|
|
71
|
+
onToggleNotifications: toggleNotifications,
|
|
71
72
|
...props.appUserProps
|
|
72
73
|
}
|
|
73
74
|
})
|
|
@@ -96,6 +97,10 @@ function signOut () {
|
|
|
96
97
|
emit('sign-out')
|
|
97
98
|
}
|
|
98
99
|
|
|
100
|
+
function toggleNotifications () {
|
|
101
|
+
emit('toggle-notifications')
|
|
102
|
+
}
|
|
103
|
+
|
|
99
104
|
function toggleMenuDrawer () {
|
|
100
105
|
emit('toggle-menu')
|
|
101
106
|
}
|
|
@@ -146,7 +146,7 @@ const props = defineProps({
|
|
|
146
146
|
}
|
|
147
147
|
})
|
|
148
148
|
|
|
149
|
-
const emit = defineEmits(['sign-out', 'update:modelValue'])
|
|
149
|
+
const emit = defineEmits(['sign-out', 'update:modelValue', 'toggle-notifications'])
|
|
150
150
|
|
|
151
151
|
const screen = useScreen()
|
|
152
152
|
const router = useRouter()
|
|
@@ -159,7 +159,8 @@ const isMini = ref(screen.isLarge)
|
|
|
159
159
|
const composableParams = {
|
|
160
160
|
props,
|
|
161
161
|
onMenuUpdate: setHasOpenedMenu,
|
|
162
|
-
onSignOut: () => emit('sign-out')
|
|
162
|
+
onSignOut: () => emit('sign-out'),
|
|
163
|
+
onToggleNotifications: () => emit('toggle-notifications')
|
|
163
164
|
}
|
|
164
165
|
|
|
165
166
|
const { defaultAppUserProps, showAppUser } = useAppUser(composableParams)
|
|
@@ -57,6 +57,9 @@ events:
|
|
|
57
57
|
'@sign-out -> function()':
|
|
58
58
|
desc: Dispara quando o botão de "sair" é clicado.
|
|
59
59
|
|
|
60
|
+
'@toggle-notifications -> function()':
|
|
61
|
+
desc: Dispara quando o botão de "Notificações" é clicado.
|
|
62
|
+
|
|
60
63
|
'@update:model-value -> function(value)':
|
|
61
64
|
desc: Dispara quando o model-value altera, também usado para v-model.
|
|
62
65
|
params:
|
|
@@ -6,6 +6,7 @@ import { computed } from 'vue'
|
|
|
6
6
|
* @param {{
|
|
7
7
|
* props: { appUserProps: {} }
|
|
8
8
|
* onSignOut: () => void
|
|
9
|
+
* onToggleNotifications: () => void
|
|
9
10
|
* onMenuUpdate: () => void
|
|
10
11
|
* }} config
|
|
11
12
|
*/
|
|
@@ -14,6 +15,7 @@ export default function useAppUser (config = {}) {
|
|
|
14
15
|
props,
|
|
15
16
|
|
|
16
17
|
onSignOut,
|
|
18
|
+
onToggleNotifications,
|
|
17
19
|
onMenuUpdate
|
|
18
20
|
} = config
|
|
19
21
|
|
|
@@ -29,6 +31,7 @@ export default function useAppUser (config = {}) {
|
|
|
29
31
|
|
|
30
32
|
// eventos
|
|
31
33
|
onSignOut,
|
|
34
|
+
onToggleNotifications,
|
|
32
35
|
...props.appUserProps
|
|
33
36
|
}
|
|
34
37
|
})
|
|
@@ -3,9 +3,7 @@
|
|
|
3
3
|
<div class="relative-position">
|
|
4
4
|
<qas-avatar :image="props.user.photo" :size="props.avatarSize" :title="userName" />
|
|
5
5
|
|
|
6
|
-
<
|
|
7
|
-
{{ props.notifications.count }}
|
|
8
|
-
</q-badge>
|
|
6
|
+
<qas-avatar v-if="hasNotificationInUserAvatar" v-bind="avatarNotificationCountProps" />
|
|
9
7
|
</div>
|
|
10
8
|
|
|
11
9
|
<div class="ellipsis qas-app-user__data">
|
|
@@ -43,20 +41,16 @@
|
|
|
43
41
|
</q-item-section>
|
|
44
42
|
</q-item>
|
|
45
43
|
|
|
46
|
-
<q-item v-if="
|
|
47
|
-
<q-item-section avatar>
|
|
44
|
+
<q-item v-if="isNotificationsEnabled" v-close-popup class="qas-app-user__menu-item" clickable @click="toggleNotificationsDrawer">
|
|
45
|
+
<q-item-section avatar class="relative-position">
|
|
48
46
|
<q-icon name="sym_r_notifications" />
|
|
47
|
+
|
|
48
|
+
<qas-avatar v-if="hasUnreadNotifications" class="qas-app-user__notification-avatar--icon" v-bind="avatarNotificationCountProps" />
|
|
49
49
|
</q-item-section>
|
|
50
50
|
|
|
51
51
|
<q-item-section>
|
|
52
52
|
Notificações
|
|
53
53
|
</q-item-section>
|
|
54
|
-
|
|
55
|
-
<q-item-section side>
|
|
56
|
-
<q-badge color="red">
|
|
57
|
-
{{ props.notifications.count }}
|
|
58
|
-
</q-badge>
|
|
59
|
-
</q-item-section>
|
|
60
54
|
</q-item>
|
|
61
55
|
|
|
62
56
|
<q-item v-close-popup class="qas-app-user__menu-item" clickable @click="signOut">
|
|
@@ -77,6 +71,7 @@
|
|
|
77
71
|
<script setup>
|
|
78
72
|
import QasAvatar from '../avatar/QasAvatar.vue'
|
|
79
73
|
|
|
74
|
+
import useNotifications from '../../composables/use-notifications'
|
|
80
75
|
import { NotifySuccess, NotifyError } from '../../plugins'
|
|
81
76
|
|
|
82
77
|
import { ref, computed, watch, inject } from 'vue'
|
|
@@ -111,14 +106,19 @@ const props = defineProps({
|
|
|
111
106
|
}
|
|
112
107
|
})
|
|
113
108
|
|
|
114
|
-
const emit = defineEmits(['sign-out'])
|
|
109
|
+
const emit = defineEmits(['sign-out', 'toggle-notifications'])
|
|
115
110
|
|
|
116
111
|
// vindo direto do boot api.js
|
|
117
112
|
const axios = inject('axios')
|
|
118
113
|
|
|
114
|
+
const { isNotificationsEnabled, unreadNotificationsCount } = useNotifications()
|
|
115
|
+
|
|
119
116
|
const companiesModel = ref('')
|
|
120
117
|
const loading = ref(false)
|
|
121
118
|
|
|
119
|
+
const { avatarNotificationCountProps } = useAvatarNotifications()
|
|
120
|
+
|
|
121
|
+
// computed
|
|
122
122
|
const defaultCompanyProps = computed(() => {
|
|
123
123
|
return {
|
|
124
124
|
loading: loading.value,
|
|
@@ -131,8 +131,10 @@ const defaultCompanyProps = computed(() => {
|
|
|
131
131
|
})
|
|
132
132
|
|
|
133
133
|
const hasCompaniesSelect = computed(() => !!props.companyProps.options?.length)
|
|
134
|
-
const
|
|
134
|
+
const hasUnreadNotifications = computed(() => unreadNotificationsCount.value > 0)
|
|
135
|
+
const hasNotificationInUserAvatar = computed(() => isNotificationsEnabled && hasUnreadNotifications.value)
|
|
135
136
|
|
|
137
|
+
const unreadNotificationsToString = computed(() => String(unreadNotificationsCount.value))
|
|
136
138
|
const userName = computed(() => props.user.name || props.user.givenName)
|
|
137
139
|
|
|
138
140
|
// watch
|
|
@@ -140,6 +142,41 @@ watch(() => props.companyProps.modelValue, value => {
|
|
|
140
142
|
companiesModel.value = value
|
|
141
143
|
}, { immediate: true })
|
|
142
144
|
|
|
145
|
+
// composable
|
|
146
|
+
function useAvatarNotifications () {
|
|
147
|
+
const hasAnimated = ref(false)
|
|
148
|
+
|
|
149
|
+
watch(() => unreadNotificationsCount.value, () => {
|
|
150
|
+
hasAnimated.value = true
|
|
151
|
+
|
|
152
|
+
setTimeout(() => {
|
|
153
|
+
hasAnimated.value = false
|
|
154
|
+
}, 1000)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
const avatarNotificationCountProps = computed(() => {
|
|
158
|
+
const classes = [
|
|
159
|
+
'qas-app-user__notification-avatar',
|
|
160
|
+
'animated',
|
|
161
|
+
{
|
|
162
|
+
rubberBand: hasAnimated.value
|
|
163
|
+
}
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
return {
|
|
167
|
+
class: classes,
|
|
168
|
+
color: 'red-14',
|
|
169
|
+
size: 'xs',
|
|
170
|
+
title: unreadNotificationsToString.value,
|
|
171
|
+
useCropTitle: false
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
avatarNotificationCountProps
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
143
180
|
// métodos
|
|
144
181
|
function signOut () {
|
|
145
182
|
emit('sign-out')
|
|
@@ -169,10 +206,28 @@ function onMenuHide () {
|
|
|
169
206
|
companiesModel.value = props.companyProps.modelValue
|
|
170
207
|
}
|
|
171
208
|
}
|
|
209
|
+
|
|
210
|
+
function toggleNotificationsDrawer () {
|
|
211
|
+
emit('toggle-notifications')
|
|
212
|
+
}
|
|
172
213
|
</script>
|
|
173
214
|
|
|
174
215
|
<style lang="scss">
|
|
175
216
|
.qas-app-user {
|
|
217
|
+
&__notification-avatar {
|
|
218
|
+
animation-duration: 1s;
|
|
219
|
+
position: absolute;
|
|
220
|
+
top: 0;
|
|
221
|
+
|
|
222
|
+
&:not(&--icon) {
|
|
223
|
+
right: -4px;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
&--icon {
|
|
227
|
+
right: 4px;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
176
231
|
&__data {
|
|
177
232
|
line-height: 1.1;
|
|
178
233
|
}
|
|
@@ -43,6 +43,9 @@ events:
|
|
|
43
43
|
'@sign-out -> function()':
|
|
44
44
|
desc: Dispara quando o botão de "sair" é clicado.
|
|
45
45
|
|
|
46
|
+
'@toggle-notifications -> function()':
|
|
47
|
+
desc: Dispara quando o botão de "Notificações" é clicado.
|
|
48
|
+
|
|
46
49
|
selectors:
|
|
47
50
|
app-user:
|
|
48
51
|
desc: Seletor do componente.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<q-avatar class="text-bold" v-bind="attributes">
|
|
3
3
|
<q-img v-if="hasImage" :alt="props.title" :ratio="1" spinner-color="primary" spinner-size="16px" :src="props.image" @error="onImageLoadedError" />
|
|
4
|
-
<template v-else-if="hasTitle">{{
|
|
4
|
+
<template v-else-if="hasTitle">{{ label }}</template>
|
|
5
5
|
<q-icon v-else :name="props.icon" />
|
|
6
6
|
</q-avatar>
|
|
7
7
|
</template>
|
|
@@ -45,6 +45,11 @@ const props = defineProps({
|
|
|
45
45
|
title: {
|
|
46
46
|
default: '',
|
|
47
47
|
type: String
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
useCropTitle: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: true
|
|
48
53
|
}
|
|
49
54
|
})
|
|
50
55
|
|
|
@@ -64,7 +69,8 @@ const attributes = computed(() => {
|
|
|
64
69
|
const colors = {
|
|
65
70
|
[AvatarColors.Primary]: 'white',
|
|
66
71
|
[AvatarColors.SecondaryContrast]: 'primary',
|
|
67
|
-
[AvatarColors.Grey4]: 'grey-8'
|
|
72
|
+
[AvatarColors.Grey4]: 'grey-8',
|
|
73
|
+
[AvatarColors.Red14]: 'white'
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
return {
|
|
@@ -75,7 +81,7 @@ const attributes = computed(() => {
|
|
|
75
81
|
}
|
|
76
82
|
})
|
|
77
83
|
|
|
78
|
-
const
|
|
84
|
+
const label = computed(() => props.useCropTitle ? props.title[0]?.toUpperCase?.() : props.title)
|
|
79
85
|
|
|
80
86
|
const hasImage = computed(() => !hasImageError.value && !!props.image)
|
|
81
87
|
const hasTitle = computed(() => !!props.title)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="col-12 col-lg-3 col-md-4 col-sm-6">
|
|
3
3
|
<q-card class="border-radius-lg column full-height overflow-hidden" :class="cardClasses">
|
|
4
|
-
<header v-if="props.useHeader" class="overflow-hidden relative-position
|
|
4
|
+
<header v-if="props.useHeader" class="full-width overflow-hidden relative-position">
|
|
5
5
|
<slot name="header">
|
|
6
6
|
<q-carousel v-model="slideImage" animated class="cursor-pointer" height="205px" infinite :navigation="hasImages" navigation-icon="sym_r_fiber_manual_record" swipeable>
|
|
7
7
|
<template #navigation-icon="{ active, btnProps, onClick }">
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
</slot>
|
|
18
18
|
</header>
|
|
19
19
|
|
|
20
|
-
<q-card-section class="col-grow column justify-between
|
|
21
|
-
<div class="
|
|
20
|
+
<q-card-section class="col-grow column full-width justify-between">
|
|
21
|
+
<div class="full-width" :class="gutterClass">
|
|
22
22
|
<slot />
|
|
23
23
|
</div>
|
|
24
24
|
</q-card-section>
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
</template>
|
|
12
12
|
|
|
13
13
|
<template #right>
|
|
14
|
-
<qas-filters v-bind="chartFiltersProps"
|
|
14
|
+
<qas-filters v-bind="chartFiltersProps" />
|
|
15
15
|
</template>
|
|
16
16
|
</qas-header-actions>
|
|
17
17
|
|
|
@@ -74,6 +74,11 @@ export default {
|
|
|
74
74
|
},
|
|
75
75
|
|
|
76
76
|
props: {
|
|
77
|
+
beforeFetch: {
|
|
78
|
+
default: null,
|
|
79
|
+
type: Function
|
|
80
|
+
},
|
|
81
|
+
|
|
77
82
|
entity: {
|
|
78
83
|
required: true,
|
|
79
84
|
type: String
|
|
@@ -137,6 +142,7 @@ export default {
|
|
|
137
142
|
|
|
138
143
|
data () {
|
|
139
144
|
return {
|
|
145
|
+
cancelBeforeFetch: false,
|
|
140
146
|
data: [],
|
|
141
147
|
filters: {},
|
|
142
148
|
isFetched: false,
|
|
@@ -199,7 +205,12 @@ export default {
|
|
|
199
205
|
useSpacing: false,
|
|
200
206
|
useUpdateRoute: false,
|
|
201
207
|
|
|
202
|
-
...this.filtersProps
|
|
208
|
+
...this.filtersProps,
|
|
209
|
+
|
|
210
|
+
'onUpdate:currentFilters': filters => {
|
|
211
|
+
this.filters = filters
|
|
212
|
+
this.filtersProps['onUpdate:currentFilters']?.(filters)
|
|
213
|
+
}
|
|
203
214
|
}
|
|
204
215
|
},
|
|
205
216
|
|
|
@@ -296,7 +307,7 @@ export default {
|
|
|
296
307
|
|
|
297
308
|
watch: {
|
|
298
309
|
filters () {
|
|
299
|
-
this.
|
|
310
|
+
this.handleFetchData()
|
|
300
311
|
},
|
|
301
312
|
|
|
302
313
|
isFetching (value) {
|
|
@@ -306,7 +317,7 @@ export default {
|
|
|
306
317
|
|
|
307
318
|
created () {
|
|
308
319
|
this.registerChartJS()
|
|
309
|
-
this.
|
|
320
|
+
this.handleFetchData()
|
|
310
321
|
},
|
|
311
322
|
|
|
312
323
|
unmounted () {
|
|
@@ -314,17 +325,34 @@ export default {
|
|
|
314
325
|
},
|
|
315
326
|
|
|
316
327
|
methods: {
|
|
317
|
-
|
|
328
|
+
handleFetchData () {
|
|
329
|
+
const hasBeforeFetch = typeof this.beforeFetch === 'function'
|
|
330
|
+
const payload = {
|
|
331
|
+
url: this.url,
|
|
332
|
+
filters: this.filters
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
if (hasBeforeFetch && !this.cancelBeforeFetch) {
|
|
336
|
+
return this.beforeFetch({
|
|
337
|
+
payload,
|
|
338
|
+
resolve: this.fetchData,
|
|
339
|
+
done: () => {
|
|
340
|
+
this.cancelBeforeFetch = true
|
|
341
|
+
}
|
|
342
|
+
})
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
this.fetchData(payload)
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
async fetchData (payload = {}) {
|
|
318
349
|
try {
|
|
319
350
|
this.isFetching = true
|
|
320
351
|
|
|
321
352
|
const response = await getAction.call(this, {
|
|
322
353
|
entity: this.entity,
|
|
323
354
|
key: 'fetchList',
|
|
324
|
-
payload
|
|
325
|
-
url: this.url,
|
|
326
|
-
filters: this.filters
|
|
327
|
-
}
|
|
355
|
+
payload
|
|
328
356
|
})
|
|
329
357
|
|
|
330
358
|
const { results } = response.data
|
|
@@ -4,6 +4,12 @@ meta:
|
|
|
4
4
|
desc: Componente responsável pela renderização de gráficos
|
|
5
5
|
|
|
6
6
|
props:
|
|
7
|
+
before-fetch:
|
|
8
|
+
desc: Callback para controlar o fetch de dados interno do componente.
|
|
9
|
+
default: null
|
|
10
|
+
type: Function
|
|
11
|
+
examples: ['beforeFetch({ payload, resolve, done })']
|
|
12
|
+
|
|
7
13
|
entity:
|
|
8
14
|
desc: Entidade da store, por exemplo se tiver que trabalhar com modulo de usuários, teremos o model "users" na store, que vai ser nossa "entity".
|
|
9
15
|
required: true
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<q-dialog ref="dialogRef" class="qas-dialog" data-cy="dialog" :persistent="props.persistent"
|
|
2
|
+
<q-dialog ref="dialogRef" class="qas-dialog" :class="classes" data-cy="dialog" v-bind="dialogProps" :persistent="props.persistent" @update:model-value="updateModelValue">
|
|
3
3
|
<div class="bg-white q-pa-lg" :style="style">
|
|
4
4
|
<header v-if="hasHeader" class="q-mb-lg">
|
|
5
5
|
<slot name="header">
|
|
@@ -136,6 +136,21 @@ const { defaultCancel, hasCancel } = useCancel(composablesParams)
|
|
|
136
136
|
const { defaultOk, hasOk, onOk } = useOk(composablesParams)
|
|
137
137
|
const { descriptionComponent, mainComponent } = useDynamicComponents({ ...composablesParams, onOk, hasOk })
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Classes criadas para serem utilizadas quando usado com a prop "position", pois
|
|
141
|
+
* o comportamento do dialog muda, e não é possível usar em conjunto com a prop
|
|
142
|
+
* "useFullMaxWidth", então foi necessário uma trativa.
|
|
143
|
+
*/
|
|
144
|
+
const classes = computed(() => {
|
|
145
|
+
const isRightPosition = attrs.position === 'right'
|
|
146
|
+
const isLeftPosition = attrs.position === 'left'
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
'qas-dialog--right': isRightPosition,
|
|
150
|
+
'qas-dialog--left': isLeftPosition
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
|
|
139
154
|
const dialogProps = computed(() => {
|
|
140
155
|
return {
|
|
141
156
|
...(!props.usePlugin && { modelValue: props.modelValue }),
|
|
@@ -183,5 +198,18 @@ function updateModelValue (value) {
|
|
|
183
198
|
.q-dialog__inner > div {
|
|
184
199
|
box-shadow: $shadow-2;
|
|
185
200
|
}
|
|
201
|
+
|
|
202
|
+
&--right {
|
|
203
|
+
.q-dialog__inner {
|
|
204
|
+
width: 100%;
|
|
205
|
+
justify-content: end;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
&--left {
|
|
210
|
+
.q-dialog__inner {
|
|
211
|
+
width: 100%;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
186
214
|
}
|
|
187
215
|
</style>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<qas-dialog class="qas-drawer" v-bind="attributes" @update:model-value="onUpdateModelValue">
|
|
3
|
+
<template #header>
|
|
4
|
+
<div class="items-center justify-between row">
|
|
5
|
+
<span data-cy="drawer-title">
|
|
6
|
+
<slot name="title">
|
|
7
|
+
<h3 v-if="props.title" class="text-h3">
|
|
8
|
+
{{ props.title }}
|
|
9
|
+
</h3>
|
|
10
|
+
</slot>
|
|
11
|
+
</span>
|
|
12
|
+
|
|
13
|
+
<qas-btn v-close-popup class="z-max" color="grey-10" data-cy="drawer-close-btn" icon="sym_r_close" variant="tertiary" @click="emit('update:modelValue', false)" />
|
|
14
|
+
</div>
|
|
15
|
+
</template>
|
|
16
|
+
|
|
17
|
+
<template #description>
|
|
18
|
+
<div>
|
|
19
|
+
<div class="relative-position" data-cy="drawer-default">
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div v-if="props.loading" class="qas-drawer__loading" :style="loadingStyle">
|
|
24
|
+
<div class="full-height relative-position">
|
|
25
|
+
<q-inner-loading :showing="props.loading">
|
|
26
|
+
<q-spinner color="grey" size="2em" />
|
|
27
|
+
</q-inner-loading>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
</qas-dialog>
|
|
33
|
+
</template>
|
|
34
|
+
|
|
35
|
+
<script setup>
|
|
36
|
+
import useScreen from '../../composables/use-screen.js'
|
|
37
|
+
|
|
38
|
+
import { computed, useAttrs } from 'vue'
|
|
39
|
+
|
|
40
|
+
defineOptions({
|
|
41
|
+
name: 'QasDrawer',
|
|
42
|
+
inheritAttrs: false
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
const props = defineProps({
|
|
46
|
+
dialogProps: {
|
|
47
|
+
type: Object,
|
|
48
|
+
default: () => ({})
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
maxWidth: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: ''
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
position: {
|
|
57
|
+
type: String,
|
|
58
|
+
default: 'left',
|
|
59
|
+
validator: value => ['left', 'right'].includes(value)
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
title: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: ''
|
|
65
|
+
},
|
|
66
|
+
|
|
67
|
+
loading: {
|
|
68
|
+
type: Boolean
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
const emit = defineEmits(['update:modelValue'])
|
|
73
|
+
|
|
74
|
+
const attrs = useAttrs()
|
|
75
|
+
const screen = useScreen()
|
|
76
|
+
|
|
77
|
+
const loadingStyle = computed(() => {
|
|
78
|
+
return {
|
|
79
|
+
right: `calc(100% - ${props.maxWidth})`
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const attributes = computed(() => {
|
|
84
|
+
const maxWidth = screen.isSmall ? '100%' : props.maxWidth
|
|
85
|
+
|
|
86
|
+
const { modelValue } = attrs
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
persistent: false,
|
|
90
|
+
modelValue,
|
|
91
|
+
|
|
92
|
+
...props.dialogProps,
|
|
93
|
+
|
|
94
|
+
cancel: false,
|
|
95
|
+
maxWidth,
|
|
96
|
+
maximized: true,
|
|
97
|
+
ok: false,
|
|
98
|
+
position: props.position,
|
|
99
|
+
useFullMaxWidth: true
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
function onUpdateModelValue (value) {
|
|
104
|
+
emit('update:modelValue', value)
|
|
105
|
+
}
|
|
106
|
+
</script>
|
|
107
|
+
|
|
108
|
+
<style lang="scss">
|
|
109
|
+
.qas-drawer {
|
|
110
|
+
&__loading {
|
|
111
|
+
height: 100vh;
|
|
112
|
+
left: 0;
|
|
113
|
+
position: absolute;
|
|
114
|
+
top: 0;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
</style>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
type: component
|
|
2
|
+
|
|
3
|
+
meta:
|
|
4
|
+
desc: Componente de drawer que implementa o QasDialog.
|
|
5
|
+
|
|
6
|
+
props:
|
|
7
|
+
dialog-props:
|
|
8
|
+
desc: Repassa propriedades para o QasDialog.
|
|
9
|
+
default: {}
|
|
10
|
+
type: Object
|
|
11
|
+
|
|
12
|
+
max-width:
|
|
13
|
+
desc: Tamanho máximo do dialog.
|
|
14
|
+
type: String
|
|
15
|
+
|
|
16
|
+
model-value:
|
|
17
|
+
desc: Model do componente, abre ou fecha o drawer.
|
|
18
|
+
type: Boolean
|
|
19
|
+
examples: [v-model="value"]
|
|
20
|
+
model: true
|
|
21
|
+
|
|
22
|
+
position:
|
|
23
|
+
desc: 'Posição do drawer, sendo possível apenas 2 opções: [left, right].'
|
|
24
|
+
default: left
|
|
25
|
+
type: String
|
|
26
|
+
|
|
27
|
+
title:
|
|
28
|
+
desc: Titulo do drawer.
|
|
29
|
+
type: String
|
|
30
|
+
|
|
31
|
+
slots:
|
|
32
|
+
default:
|
|
33
|
+
desc: Slot para conteúdo principal.
|
|
34
|
+
|
|
35
|
+
title:
|
|
36
|
+
desc: Slot para o titulo.
|
|
37
|
+
|
|
38
|
+
events:
|
|
39
|
+
'@update:model-value -> function (value)':
|
|
40
|
+
desc: Dispara toda vez que o model é atualizado, também utilizado para v-model.
|
|
41
|
+
params:
|
|
42
|
+
value:
|
|
43
|
+
desc: Novo valor do v-model
|
|
44
|
+
type: Boolean
|
|
45
|
+
|
|
46
|
+
selectors:
|
|
47
|
+
drawer-close-btn:
|
|
48
|
+
desc: Seletor do botão de fechar.
|
|
49
|
+
examples: ['data-cy="drawer-close-btn"']
|
|
50
|
+
|
|
51
|
+
drawer-default:
|
|
52
|
+
desc: Seletor do botão conteúdo do slot default.
|
|
53
|
+
examples: ['data-cy="drawer-default"']
|
|
54
|
+
|
|
55
|
+
drawer-title:
|
|
56
|
+
desc: Seletor do titulo.
|
|
57
|
+
examples: ['data-cy="drawer-title"']
|