@bildvitta/quasar-ui-asteroid 3.14.0-beta.2 → 3.14.0-beta.4
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/date/QasDate.vue +31 -36
- 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/whatsapp-link/QasWhatsappLink.vue +2 -2
- package/src/components/whatsapp-link/QasWhatsappLink.yml +1 -1
- 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 +3 -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>
|
|
@@ -447,14 +447,11 @@ function onNavigation (date) {
|
|
|
447
447
|
&__event {
|
|
448
448
|
@include set-typography($caption);
|
|
449
449
|
|
|
450
|
-
bottom: -6px;
|
|
451
450
|
color: $primary;
|
|
452
451
|
font-size: 10px !important;
|
|
453
|
-
height: 20px;
|
|
454
|
-
left: 50%;
|
|
455
|
-
position: absolute;
|
|
456
|
-
transform: translateX(-50%);
|
|
457
452
|
width: 100%;
|
|
453
|
+
line-height: 1;
|
|
454
|
+
transition: color var(--qas-generic-transition);
|
|
458
455
|
|
|
459
456
|
&--pointer {
|
|
460
457
|
bottom: -6px;
|
|
@@ -472,6 +469,10 @@ function onNavigation (date) {
|
|
|
472
469
|
width: 6px;
|
|
473
470
|
}
|
|
474
471
|
|
|
472
|
+
.q-date__calendar-item {
|
|
473
|
+
vertical-align: initial;
|
|
474
|
+
}
|
|
475
|
+
|
|
475
476
|
&--inative {
|
|
476
477
|
.q-date {
|
|
477
478
|
&__calendar-item--out,
|
|
@@ -493,31 +494,19 @@ function onNavigation (date) {
|
|
|
493
494
|
}
|
|
494
495
|
}
|
|
495
496
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
padding-bottom: 4px;
|
|
500
|
-
}
|
|
497
|
+
.q-date {
|
|
498
|
+
&__navigation {
|
|
499
|
+
justify-content: space-between;
|
|
501
500
|
|
|
502
|
-
|
|
503
|
-
|
|
501
|
+
> div:last-child,
|
|
502
|
+
> div:first-child {
|
|
503
|
+
min-width: auto;
|
|
504
|
+
width: auto;
|
|
504
505
|
}
|
|
505
506
|
|
|
506
|
-
|
|
507
|
-
|
|
507
|
+
> div:first-child {
|
|
508
|
+
min-width: 120px;
|
|
508
509
|
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
|
|
512
|
-
.q-date__navigation > div:last-child,
|
|
513
|
-
.q-date__navigation > div:first-child {
|
|
514
|
-
min-width: auto;
|
|
515
|
-
width: auto;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
.q-date {
|
|
519
|
-
&__navigation {
|
|
520
|
-
justify-content: space-between;
|
|
521
510
|
|
|
522
511
|
.q-btn {
|
|
523
512
|
@include set-button(tertiary, false, false, grey-10);
|
|
@@ -566,14 +555,15 @@ function onNavigation (date) {
|
|
|
566
555
|
min-height: auto;
|
|
567
556
|
|
|
568
557
|
.q-btn {
|
|
569
|
-
|
|
558
|
+
@include set-typography($subtitle2);
|
|
559
|
+
|
|
560
|
+
border: 1px solid transparent;
|
|
570
561
|
border-radius: $generic-border-radius;
|
|
571
562
|
box-shadow: none;
|
|
572
|
-
height:
|
|
573
|
-
|
|
574
|
-
|
|
563
|
+
height: auto !important;
|
|
564
|
+
line-height: 1;
|
|
565
|
+
width: 26px !important;
|
|
575
566
|
transition: color var(--qas-generic-transition);
|
|
576
|
-
width: 30px !important;
|
|
577
567
|
|
|
578
568
|
.q-ripple,
|
|
579
569
|
.q-focus-helper {
|
|
@@ -592,12 +582,17 @@ function onNavigation (date) {
|
|
|
592
582
|
color: var(--q-primary-contrast);
|
|
593
583
|
}
|
|
594
584
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
585
|
+
&.bg-primary,
|
|
586
|
+
&.q-date__today {
|
|
587
|
+
border-color: $primary;
|
|
588
|
+
border-radius: $generic-border-radius;
|
|
589
|
+
font-weight: 700;
|
|
590
|
+
}
|
|
598
591
|
|
|
599
|
-
|
|
600
|
-
|
|
592
|
+
&.q-date__today {
|
|
593
|
+
color: $primary;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
601
596
|
}
|
|
602
597
|
}
|
|
603
598
|
}
|
|
@@ -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"']
|