@bildvitta/quasar-ui-asteroid 3.2.0 → 3.3.0-beta.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bildvitta/quasar-ui-asteroid",
3
3
  "description": "Asteroid",
4
- "version": "3.2.0",
4
+ "version": "3.3.0-beta.1",
5
5
  "author": "Bild & Vitta <systemteam@bild.com.br>",
6
6
  "license": "MIT",
7
7
  "main": "dist/asteroid.cjs.min.js",
@@ -21,11 +21,11 @@ props:
21
21
  default: []
22
22
  type: Array
23
23
 
24
-
25
24
  events:
26
25
  '@update:model-value -> function(value)':
27
26
  desc: Dispara quando o model-value altera, também usado para v-model.
28
27
  params:
29
28
  value:
30
29
  desc: Novo valor do model.
31
- type: []
30
+ default: []
31
+ type: Array
@@ -104,6 +104,10 @@ export default {
104
104
  type: Boolean
105
105
  },
106
106
 
107
+ useFullMaxWidth: {
108
+ type: Boolean
109
+ },
110
+
107
111
  useValidationAllAtOnce: {
108
112
  type: Boolean
109
113
  }
@@ -133,6 +137,7 @@ export default {
133
137
 
134
138
  style () {
135
139
  return {
140
+ ...(this.useFullMaxWidth && { width: '100%' }),
136
141
  maxWidth: this.maxWidth || (this.$qas.screen.isSmall ? '' : '600px'),
137
142
  minWidth: this.minWidth || (this.$qas.screen.isSmall ? '' : '400px')
138
143
  }
@@ -60,6 +60,10 @@ props:
60
60
  desc: Define se a tag onde fica a descrição no dialog vai ser um "<q-form />" ou "<div />".
61
61
  type: Boolean
62
62
 
63
+ use-full-max-width:
64
+ desc: propriedade para utilizar `100% do maxWidth`.
65
+ type: Boolean
66
+
63
67
  use-validation-at-once:
64
68
  desc: Valida todos os campos de uma única vez, ao invés de ser um por vez (que é o padrão).
65
69
  type: Boolean
@@ -1,39 +1,60 @@
1
1
 
2
2
  <template>
3
- <qas-box class="gallery">
3
+ <div class="qas-gallery">
4
4
  <div class="q-col-gutter-md row">
5
- <div v-for="(image, index) in initialImages()" :key="index" :class="galleryColumnsClasses">
6
- <q-img class="cursor-pointer rounded-borders" :height="imageHeight" :src="image" @click="toggleCarouselDialog(index)" @error="onError(image)" />
5
+ <div v-for="(image, index) in getInitialImages()" :key="index" :class="galleryColumnsClasses" :data-cy="`gallery-image-${index}`">
6
+ <div class="bg-white q-pa-md rounded-borders shadow-2">
7
+ <div class="flat items-center justify-between no-wrap q-mb-xs row text-grey-9">
8
+ <div class="ellipsis q-mr-xs qas-gallery__name">
9
+ <slot v-if="image.name" :image="image" :index="index" name="header">
10
+ {{ image.name }}
11
+ </slot>
12
+ </div>
13
+
14
+ <div v-if="useDestroy">
15
+ <slot :destroy="onDestroy" :image="image" :index="index" name="destroy">
16
+ <qas-btn color="grey-9" dense :disabled="isDestroyDisabled(image)" flat round size="sm" @click="onDestroy(image, index)">
17
+ <q-icon name="o_delete" size="xs" />
18
+ </qas-btn>
19
+ </slot>
20
+ </div>
21
+ </div>
22
+
23
+ <q-img class="cursor-pointer rounded-borders" height="150px" :src="image.url" @click="toggleCarouselDialog(index)" @error="onError(image.url)" />
24
+ </div>
7
25
  </div>
26
+
8
27
  <slot>
9
28
  <div v-if="!hideShowMore" class="full-width text-center">
10
- <qas-btn class="text-weight-bolder" color="primary" flat @click="showMore">{{ showMoreLabel }}</qas-btn>
29
+ <qas-btn color="primary" data-cy="gallery-btn-show-more" flat :label="showMoreLabel" @click="showMore" />
11
30
  </div>
12
31
  </slot>
13
- <qas-dialog v-model="carouselDialog" :cancel="false" class="q-pa-xl" min-width="1100px" :ok="false" :persistent="false">
14
- <template #header>
15
- <div class="text-right">
16
- <qas-btn v-close-popup dense flat icon="o_close" rounded @click="toggleCarouselDialog" />
17
- </div>
18
- </template>
19
- <template #description>
20
- <q-carousel v-model="imageIndex" animated :arrows="!$qas.screen.isSmall" control-text-color="primary" :fullscreen="$qas.screen.isSmall" :height="carouselImageHeight" :next-icon="carouselNextIcon" :prev-icon="carouselPreviousIcon" swipeable :thumbnails="showThumbnails">
21
- <q-carousel-slide v-for="(image, index) in clonedImages" :key="index" class="bg-no-repeat bg-size-contain" :img-src="image" :name="index">
22
- <div v-if="$qas.screen.isSmall" class="full-width justify-end row">
23
- <qas-btn dense flat icon="o_close" @click="toggleCarouselDialog" />
24
- </div>
25
- </q-carousel-slide>
26
- </q-carousel>
27
- </template>
28
- </qas-dialog>
32
+
33
+ <pv-gallery-carousel-dialog v-model="carouselDialog" v-model:imageIndex="imageIndex" :images="normalizedImages" />
34
+
35
+ <pv-gallery-delete-dialog v-model="showDeleteDialog" v-bind="deleteGalleryDialogProps" @cancel="resetCurrentModel" @error="onDeleteError" @success="onDeleteSuccess" />
29
36
  </div>
30
- </qas-box>
37
+ </div>
31
38
  </template>
32
39
 
33
40
  <script>
41
+ import QasBtn from '../btn/QasBtn.vue'
42
+ import PvGalleryDeleteDialog from './private/PvGalleryDeleteDialog.vue'
43
+ import PvGalleryCarouselDialog from './private/PvGalleryCarouselDialog.vue'
44
+ import { extend } from 'quasar'
45
+ import { deleteMixin } from '../../mixins'
46
+
34
47
  export default {
35
48
  name: 'QasGallery',
36
49
 
50
+ components: {
51
+ PvGalleryCarouselDialog,
52
+ PvGalleryDeleteDialog,
53
+ QasBtn
54
+ },
55
+
56
+ mixins: [deleteMixin],
57
+
37
58
  props: {
38
59
  carouselNextIcon: {
39
60
  type: String,
@@ -45,24 +66,14 @@ export default {
45
66
  default: 'o_chevron_left'
46
67
  },
47
68
 
48
- height: {
49
- type: String,
50
- default: ''
51
- },
52
-
53
69
  initialSize: {
54
70
  type: Number,
55
- default: 6
56
- },
71
+ default: 4,
72
+ validator: value => {
73
+ const acceptableValues = [1, 2, 3, 4, 6, 12]
57
74
 
58
- images: {
59
- type: Array,
60
- default: () => []
61
- },
62
-
63
- loadSize: {
64
- type: Number,
65
- default: 6
75
+ return acceptableValues.includes(value)
76
+ }
66
77
  },
67
78
 
68
79
  showMoreLabel: {
@@ -72,81 +83,162 @@ export default {
72
83
 
73
84
  useLoadAll: {
74
85
  type: Boolean
86
+ },
87
+
88
+ useDestroy: {
89
+ type: Boolean
90
+ },
91
+
92
+ useObjectModel: {
93
+ type: Boolean
94
+ },
95
+
96
+ modelValue: {
97
+ type: Array,
98
+ default: () => []
99
+ },
100
+
101
+ modelKey: {
102
+ type: String,
103
+ default: ''
75
104
  }
76
105
  },
77
106
 
107
+ emits: [
108
+ 'delete-error',
109
+ 'delete-success',
110
+ 'update:modelValue'
111
+ ],
112
+
78
113
  data () {
79
114
  return {
80
115
  carouselDialog: false,
81
- clonedImages: [],
82
- imageIndex: [],
83
- displayedImages: this.initialSize
116
+ imageIndex: 0,
117
+ displayedImages: this.initialSize,
118
+ showDeleteDialog: false,
119
+ currentModel: [],
120
+ imageToBeDestroyed: { index: null }
84
121
  }
85
122
  },
86
123
 
87
124
  computed: {
88
- imageHeight () {
89
- if (this.isSingleImage) {
90
- return this.height || 'auto'
91
- }
92
-
93
- return this.$qas.screen.isSmall ? '90px' : '120px'
94
- },
95
-
96
125
  galleryColumnsClasses () {
97
- if (this.isSingleImage) return 'col-12'
126
+ const size = 12 / this.initialSize
127
+ const col = `col-${size}`
98
128
 
99
- return this.$qas.screen.isSmall ? 'col-6' : 'col-2'
129
+ return this.$qas.screen.isSmall ? 'col-12' : col
100
130
  },
101
131
 
102
132
  hideShowMore () {
103
- return (this.clonedImages.length <= this.displayedImages) || this.useLoadAll
133
+ return (this.normalizedImages.length <= this.displayedImages) || this.useLoadAll
104
134
  },
105
135
 
106
- carouselImageHeight () {
107
- return 'calc((500/976) * 100vh)'
136
+ normalizedImages () {
137
+ if (!this.useObjectModel) {
138
+ return this.clonedImages.map(url => ({ url }))
139
+ }
140
+
141
+ return this.clonedImages
108
142
  },
109
143
 
110
- showThumbnails () {
111
- return !this.isSingleImage
144
+ clonedImages () {
145
+ return extend(true, [], this.modelValue)
112
146
  },
113
147
 
114
- isSingleImage () {
115
- return this.clonedImages.length === 1
148
+ deleteGalleryDialogProps () {
149
+ return {
150
+ customId: this.customId,
151
+ dialogProps: this.dialogProps,
152
+ entity: this.entity,
153
+ modelKey: this.modelKey,
154
+ payload: this.currentModel,
155
+ url: this.url
156
+ }
116
157
  }
117
158
  },
118
159
 
119
160
  watch: {
120
- images: {
161
+ normalizedImages: {
121
162
  handler (value) {
122
- this.clonedImages = [...value]
163
+ this.currentModel = extend(true, [], value)
123
164
  },
165
+
124
166
  immediate: true
125
167
  }
126
168
  },
127
169
 
128
170
  methods: {
129
- toggleCarouselDialog (image) {
130
- this.imageIndex = image
171
+ toggleCarouselDialog (index) {
172
+ this.imageIndex = index
131
173
  this.carouselDialog = !this.carouselDialog
132
174
  },
133
175
 
134
176
  showMore () {
135
- this.displayedImages += this.loadSize
177
+ this.displayedImages += this.displayedImages
136
178
  },
137
179
 
138
180
  onError (error) {
139
- const index = this.clonedImages.findIndex(image => image === error)
181
+ const index = this.normalizedImages.findIndex(image => image.url === error)
140
182
 
141
183
  if (~index) {
142
- this.clonedImages.splice(index, 1)
184
+ this.normalizedImages.splice(index, 1)
143
185
  this.$forceUpdate()
144
186
  }
145
187
  },
146
188
 
147
- initialImages () {
148
- return this.useLoadAll ? this.clonedImages : this.clonedImages.slice(0, this.displayedImages)
189
+ getInitialImages () {
190
+ return this.useLoadAll
191
+ ? this.normalizedImages
192
+ : this.normalizedImages.slice(0, this.displayedImages)
193
+ },
194
+
195
+ onDestroy (image, index) {
196
+ if (this.isDestroyDisabled(image)) return
197
+
198
+ this.imageToBeDestroyed.index = index
199
+
200
+ this.currentModel.splice(this.imageToBeDestroyed.index, 1)
201
+
202
+ this.showDeleteDialog = !this.showDeleteDialog
203
+ },
204
+
205
+ isDestroyDisabled (image) {
206
+ return 'destroyable' in image && !image.destroyable
207
+ },
208
+
209
+ onDeleteSuccess () {
210
+ this.normalizedImages.splice(this.imageToBeDestroyed.index, 1)
211
+
212
+ this.$emit('update:modelValue', this.normalizedImages)
213
+
214
+ this.$emit(
215
+ 'delete-success',
216
+ { data: this.normalizedImages, index: this.imageToBeDestroyed.index }
217
+ )
218
+ },
219
+
220
+ resetCurrentModel () {
221
+ this.currentModel = extend(true, [], this.normalizedImages)
222
+ },
223
+
224
+ onDeleteError (error) {
225
+ this.resetCurrentModel()
226
+
227
+ this.$emit(
228
+ 'delete-error',
229
+ { data: error, index: this.imageToBeDestroyed.index }
230
+ )
149
231
  }
150
232
  }
151
233
  }
152
234
  </script>
235
+
236
+ <!-- TODO rever tipografia -->
237
+ <style lang="scss">
238
+ .qas-gallery {
239
+ &__name {
240
+ font-size: 16px;
241
+ font-weight: 600;
242
+ }
243
+ }
244
+ </style>
@@ -3,49 +3,129 @@ type: component
3
3
  mixins:
4
4
  - '@bildvitta/quasar-ui-asteroid/dist/api/QasBox.json'
5
5
 
6
-
7
6
  meta:
8
7
  desc: Componente para galeria, mostrando images dentro de um "QasDialog" ao clicar nelas.
9
8
 
10
9
  props:
11
- carousel-next-icon:
12
- desc: Ícone dentro do carousel para passar para próxima imagem.
13
- default: o_chevron_right
10
+ custom-id:
11
+ desc: Por padrão, o componente vai pegar o "id" que vem como parâmetro na url, caso queira que o id seja diferente da url, use esta prop (utilizado para remover imagem, custom-id referente ao model e não a imagem).
14
12
  type: String
13
+ examples: ['my-custom-id']
15
14
 
16
- carousel-previous-icon:
17
- desc: Ícone dentro do carousel para passar para a imagem anterior.
18
- default: o_chevron_left
19
- type: String
15
+ dialog-props:
16
+ desc: Props para ser repassada para o componente "QasDialog" (utilizado para dialog de remover imagem).
17
+ default: {}
18
+ type: Object
20
19
 
21
- height:
22
- desc: Altura da imagem (fora do dialog).
20
+ entity:
21
+ 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" (utilizado para remover imagem).
23
22
  type: String
24
23
 
25
- images:
26
- desc: Imagens a serem exibidas.
27
- default: 6
28
- type: Number
29
-
30
24
  initial-size:
31
25
  desc: Quantidade de imagens iniciais.
32
26
  default: 6
33
27
  type: Number
34
28
 
35
- load-size:
36
- desc: Quantidade de fotos carregadas por vez.
37
- default: 6
38
- type: Number
39
-
40
29
  show-more-label:
41
30
  desc: Rótulo do botão de "mostrar mais".
42
31
  default: Ver mais
43
32
  type: String
44
33
 
34
+ model-value:
35
+ desc: Model do componente, usado para v-model.
36
+ default: []
37
+ type: Array
38
+ examples: [v-model"value"]
39
+ model: true
40
+
41
+ model-key:
42
+ desc: Chave identificadora do model, usada para identificar qual campo ela é referente.
43
+ default: ''
44
+ type: String
45
+ examples: [photos]
46
+
47
+ url:
48
+ desc: Envia como parâmetro para a action "update" do modulo correspondente a "entity" (utilizado para remover imagem).
49
+ type: String
50
+
51
+ use-destroy:
52
+ desc: Usado para habilitar botão de remover imagem da galeroa.
53
+ type: Boolean
54
+
45
55
  use-load-all:
46
56
  desc: Carrega todas imagens de uma única vez.
47
57
  type: Boolean
48
58
 
59
+ use-object-model:
60
+ desc: Usado para definir o model como objeto.
61
+ type: Boolean
62
+
49
63
  slots:
50
64
  default:
51
65
  desc: Slot para todo conteúdo onde fica o botão "mostrar mais".
66
+
67
+ destroy:
68
+ desc: Slot para o ícone de remover.
69
+ scope:
70
+ destroy:
71
+ desc: Função para remover e atualizar o model.
72
+ default: undefined
73
+ type: Function
74
+
75
+ index:
76
+ desc: index atual.
77
+ default: 0
78
+ type: Number
79
+
80
+ image:
81
+ desc: imagem atual.
82
+ default: {}
83
+ type: Object
84
+
85
+ header:
86
+ desc: Slot para o header.
87
+ scope:
88
+ index:
89
+ desc: index atual.
90
+ default: 0
91
+ type: Number
92
+
93
+ image:
94
+ desc: imagem atual.
95
+ default: {}
96
+ type: Object
97
+
98
+ events:
99
+ '@update:model-value -> function(value)':
100
+ desc: Dispara quando o model-value altera, também usado para v-model.
101
+ params:
102
+ value:
103
+ desc: Novo valor do model.
104
+ default: []
105
+ type: Array
106
+
107
+ 'delete-success -> function({ data, index })':
108
+ desc: Dispara quando deleta uma imagem da galeria com sucesso.
109
+ params:
110
+ data:
111
+ desc: Novo valor do v-model.
112
+ default: []
113
+ type: Array
114
+
115
+ index:
116
+ desc: Index da imagem deletada.
117
+ default: []
118
+ type: Array
119
+
120
+ 'delete-error -> function({ data, index })':
121
+ desc: Dispara ocorre uma falha ao deletar uma imagem da galeria.
122
+ params:
123
+ data:
124
+ desc: Valor retornado no erro.
125
+ default: []
126
+ type: Array
127
+
128
+ index:
129
+ desc: Index da imagem que seria deletada.
130
+ default: []
131
+ type: Array
@@ -0,0 +1,82 @@
1
+ <template>
2
+ <qas-dialog v-model="model" :cancel="false" class="q-pa-xl" max-width="1100px" :ok="false" :persistent="false" use-full-max-width>
3
+ <template #header>
4
+ <div class="text-right">
5
+ <qas-btn v-close-popup dense flat icon="o_close" rounded @click="close" />
6
+ </div>
7
+ </template>
8
+
9
+ <template #description>
10
+ <q-carousel v-model="imageIndexModel" animated :arrows="!$qas.screen.isSmall" control-text-color="primary" data-cy="gallery-carousel" :fullscreen="$qas.screen.isSmall" :height="carouselImageHeight" next-icon="o_chevron_right" prev-icon="o_chevron_left" swipeable :thumbnails="!isSingleImage">
11
+ <q-carousel-slide v-for="(image, index) in images" :key="index" class="bg-no-repeat bg-size-contain" :data-cy="`gallery-carousel-slide-${index}`" :img-src="image.url" :name="index">
12
+ <div v-if="$qas.screen.isSmall" class="full-width justify-end row">
13
+ <qas-btn dense flat icon="o_close" @click="close" />
14
+ </div>
15
+ </q-carousel-slide>
16
+ </q-carousel>
17
+ </template>
18
+ </qas-dialog>
19
+ </template>
20
+
21
+ <script>
22
+ export default {
23
+ name: 'PvGalleryCarouselDialog',
24
+
25
+ props: {
26
+ images: {
27
+ type: Array,
28
+ default: () => []
29
+ },
30
+
31
+ imageIndex: {
32
+ type: Number,
33
+ default: 0
34
+ },
35
+
36
+ modelValue: {
37
+ type: Boolean
38
+ }
39
+ },
40
+
41
+ emits: [
42
+ 'update:modelValue',
43
+ 'update:imageIndex'
44
+ ],
45
+
46
+ computed: {
47
+ model: {
48
+ get () {
49
+ return this.modelValue
50
+ },
51
+
52
+ set (value) {
53
+ return this.$emit('update:modelValue', value)
54
+ }
55
+ },
56
+
57
+ imageIndexModel: {
58
+ get () {
59
+ return this.imageIndex
60
+ },
61
+
62
+ set (value) {
63
+ return this.$emit('update:imageIndex', value)
64
+ }
65
+ },
66
+
67
+ carouselImageHeight () {
68
+ return 'calc((500/976) * 100vh)'
69
+ },
70
+
71
+ isSingleImage () {
72
+ return this.images.length === 1
73
+ }
74
+ },
75
+
76
+ methods: {
77
+ close () {
78
+ this.$emit('update:modelValue', false)
79
+ }
80
+ }
81
+ }
82
+ </script>
@@ -0,0 +1,63 @@
1
+ <template>
2
+ <qas-dialog v-bind="mx_defaultDialogProps" />
3
+ </template>
4
+
5
+ <script>
6
+ import { getAction } from '@bildvitta/store-adapter'
7
+
8
+ import QasDialog from '../../dialog/QasDialog.vue'
9
+ import { promiseHandler } from '../../../helpers'
10
+ import { deleteMixin } from '../../../mixins'
11
+
12
+ export default {
13
+ name: 'PvGalleryDeleteDialog',
14
+
15
+ components: {
16
+ QasDialog
17
+ },
18
+
19
+ mixins: [deleteMixin],
20
+
21
+ props: {
22
+ payload: {
23
+ type: Array,
24
+ default: () => []
25
+ },
26
+
27
+ modelKey: {
28
+ type: String,
29
+ default: ''
30
+ }
31
+ },
32
+
33
+ emits: [
34
+ 'success',
35
+ 'error',
36
+ 'cancel'
37
+ ],
38
+
39
+ methods: {
40
+ // chamado no mixin
41
+ async destroy () {
42
+ const { data, error } = await promiseHandler(
43
+ getAction.call(this, {
44
+ entity: this.entity,
45
+ key: 'update',
46
+ payload: {
47
+ id: this.mx_id,
48
+ url: this.url,
49
+ payload: { [this.modelKey]: this.payload }
50
+ }
51
+ }),
52
+ {
53
+ errorMessage: 'Ops! Não foi possível deletar o item.',
54
+ successMessage: 'Item deletado com sucesso!'
55
+ }
56
+ )
57
+
58
+ if (data) return this.$emit('success', data)
59
+ if (error) return this.$emit('error', error)
60
+ }
61
+ }
62
+ }
63
+ </script>
@@ -0,0 +1,49 @@
1
+ export default {
2
+ props: {
3
+ customId: {
4
+ default: '',
5
+ type: [Number, String]
6
+ },
7
+
8
+ dialogProps: {
9
+ default: () => ({}),
10
+ type: Object
11
+ },
12
+
13
+ entity: {
14
+ default: '',
15
+ type: String
16
+ },
17
+
18
+ url: {
19
+ default: '',
20
+ type: String
21
+ }
22
+ },
23
+
24
+ computed: {
25
+ mx_defaultDialogProps () {
26
+ return {
27
+ card: {
28
+ title: 'Confirmar',
29
+ description: 'Tem certeza que deseja excluir este item?'
30
+ },
31
+
32
+ ok: {
33
+ label: 'Excluir',
34
+ onClick: this.destroy
35
+ },
36
+
37
+ cancel: {
38
+ onClick: () => this.$emit('cancel')
39
+ },
40
+
41
+ ...this.dialogProps
42
+ }
43
+ },
44
+
45
+ mx_id () {
46
+ return this.customId || this.$route.params.id
47
+ }
48
+ }
49
+ }
@@ -4,9 +4,11 @@ import generatorMixin from './generator.js'
4
4
  import searchFilterMixin from './search-filter.js'
5
5
  import passwordMixin from './password.js'
6
6
  import viewMixin from './view.js'
7
+ import deleteMixin from './delete.js'
7
8
 
8
9
  export {
9
10
  contextMixin,
11
+ deleteMixin,
10
12
  formMixin,
11
13
  generatorMixin,
12
14
  searchFilterMixin,