@bildvitta/quasar-ui-asteroid 2.12.4 → 3.0.0-alpha.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/dist/api/QasBox.json +16 -0
- package/dist/api/QasBreakline.json +32 -0
- package/dist/api/QasBtn.json +15 -0
- package/dist/api/QasDebugger.json +13 -0
- package/dist/asteroid.cjs.css +1 -0
- package/dist/asteroid.cjs.js +9154 -0
- package/dist/asteroid.cjs.min.js +6 -0
- package/dist/asteroid.esm.css +1 -0
- package/dist/asteroid.esm.js +9145 -0
- package/dist/asteroid.esm.min.js +6 -0
- package/dist/asteroid.umd.css +1 -0
- package/dist/asteroid.umd.js +9148 -0
- package/dist/asteroid.umd.min.js +6 -0
- package/dist/vetur/asteroid-attributes.json +30 -0
- package/dist/vetur/asteroid-tags.json +29 -0
- package/package.json +42 -56
- package/src/assets/logo-modular.svg +1 -0
- package/src/asteroid.js +1 -0
- package/src/components/actions/QasActions.vue +45 -0
- package/src/components/actions-menu/QasActionsMenu.vue +8 -19
- package/src/components/alert/QasAlert.vue +90 -0
- package/src/components/app-bar/QasAppBar.vue +59 -61
- package/src/components/app-menu/QasAppMenu.vue +128 -41
- package/src/components/avatar/QasAvatar.vue +7 -3
- package/src/components/box/QasBox.vue +12 -4
- package/src/components/box/QasBox.yml +13 -0
- package/src/components/breakline/QasBreakline.vue +37 -0
- package/src/components/breakline/QasBreakline.yml +25 -0
- package/src/components/btn/QasBtn.vue +27 -24
- package/src/components/btn/QasBtn.yml +12 -0
- package/src/components/card/QasCard.vue +29 -21
- package/src/components/checkbox-group/QasCheckboxGroup.vue +31 -17
- package/src/components/copy/QasCopy.vue +22 -11
- package/src/components/date-time-input/QasDateTimeInput.vue +16 -26
- package/src/components/debugger/QasDebugger.vue +2 -0
- package/src/components/debugger/QasDebugger.yml +10 -0
- package/src/components/delete/QasDelete.vue +28 -15
- package/src/components/dialog/QasDialog.vue +71 -67
- package/src/components/dialog-router/QasDialogRouter.vue +12 -4
- package/src/components/field/QasField.vue +22 -25
- package/src/components/filters/QasFilters.vue +31 -24
- package/src/components/form-generator/QasFormGenerator.vue +13 -15
- package/src/components/form-view/QasFormView.vue +117 -66
- package/src/components/gallery/QasGallery.vue +39 -26
- package/src/components/grid-generator/QasGridGenerator.vue +12 -6
- package/src/components/index.js +0 -0
- package/src/components/input/QasInput.vue +38 -36
- package/src/components/label/QasLabel.vue +14 -15
- package/src/components/layout/QasLayout.vue +81 -0
- package/src/components/list-items/QasListItems.vue +16 -8
- package/src/components/list-view/QasListView.vue +31 -28
- package/src/components/map/QasMap.vue +15 -25
- package/src/components/nested-fields/QasNestedFields.vue +39 -36
- package/src/components/numeric-input/QasNumericInput.vue +125 -0
- package/src/components/page-header/QasPageHeader.vue +19 -10
- package/src/components/password-input/QasPasswordInput.vue +20 -18
- package/src/components/password-strength-checker/QasPasswordStrengthChecker.vue +52 -31
- package/src/components/profile/QasProfile.vue +14 -12
- package/src/components/resizer/QasResizer.vue +1 -1
- package/src/components/search-box/QasSearchBox.vue +36 -20
- package/src/components/select/QasSelect.vue +43 -44
- package/src/components/select-list/QasSelectList.vue +64 -51
- package/src/components/signature-pad/QasSignaturePad.vue +57 -41
- package/src/components/signature-uploader/QasSignatureUploader.vue +15 -13
- package/src/components/single-view/QasSingleView.vue +31 -17
- package/src/components/sortable/QasSortable.vue +45 -27
- package/src/components/table-generator/QasTableGenerator.vue +95 -22
- package/src/components/tabs-generator/QasTabsGenerator.vue +36 -24
- package/src/components/text-truncate/QasTextTruncate.vue +25 -17
- package/src/components/transfer/QasTransfer.vue +57 -53
- package/src/components/uploader/QasUploader.vue +169 -48
- package/src/css/background.scss +1 -1
- package/src/css/border.scss +7 -6
- package/src/css/design-system.scss +0 -43
- package/src/css/fonts.scss +2 -28
- package/src/css/opacity.scss +0 -4
- package/src/css/set-brand.scss +15 -0
- package/src/css/transitions.scss +1 -1
- package/src/helpers/add-counter-suffix.js +3 -0
- package/src/helpers/{base64ToBlob.js → base-64-to-blob.js} +0 -0
- package/src/helpers/{constructObject.js → construct-object.js} +0 -0
- package/src/helpers/filter-object.js +8 -6
- package/src/helpers/filters.js +3 -4
- package/src/helpers/get-slot-children-text.js +15 -0
- package/src/helpers/{greatestCommonDivisor.js → greatest-common-divisor.js} +0 -0
- package/src/helpers/images.js +28 -0
- package/src/helpers/index.js +11 -57
- package/src/helpers/is-local-development.js +3 -0
- package/src/helpers/scroll-on-grap.js +61 -0
- package/src/index.cjs.js +1 -0
- package/src/index.esm.js +4 -0
- package/src/index.scss +18 -20
- package/src/index.umd.js +2 -0
- package/src/mixins/context.js +1 -1
- package/src/mixins/dialog-router.js +17 -0
- package/src/mixins/form.js +4 -12
- package/src/mixins/generator.js +14 -14
- package/src/mixins/index.js +2 -8
- package/src/mixins/password.js +73 -11
- package/src/mixins/screen.js +8 -6
- package/src/mixins/view.js +57 -20
- package/src/plugins/Dialog.js +14 -0
- package/src/plugins/NotifySuccess.js +3 -3
- package/src/plugins/index.js +4 -2
- package/src/store/history.js +43 -0
- package/src/store/index.js +1 -0
- package/src/vue-plugin.js +185 -0
- package/.babelrc +0 -12
- package/.storybook/main.js +0 -35
- package/.storybook/preview.js +0 -26
- package/debug.log +0 -1
- package/index.js +0 -4
- package/jest-setup.js +0 -1
- package/jest.config.json +0 -22
- package/postcss.config.js +0 -5
- package/src/components/Introduction.stories.mdx +0 -12
- package/src/components/actions-menu/QasActionsMenu.stories.js +0 -73
- package/src/components/app-bar/QasAppBar.stories.js +0 -88
- package/src/components/app-menu/QasAppMenu.stories.js +0 -62
- package/src/components/apps-menu/QasAppsMenu.spec.js +0 -58
- package/src/components/apps-menu/QasAppsMenu.stories.js +0 -54
- package/src/components/apps-menu/QasAppsMenu.vue +0 -48
- package/src/components/avatar/QasAvatar.spec.js +0 -14
- package/src/components/avatar/QasAvatar.stories.js +0 -52
- package/src/components/box/QasBox.spec.js +0 -18
- package/src/components/box/QasBox.stories.js +0 -35
- package/src/components/break-line/QasBreakLine.stories.js +0 -57
- package/src/components/break-line/QasBreakLine.vue +0 -52
- package/src/components/btn/QasBtn.stories.js +0 -45
- package/src/components/btn-actions/QasBtnActions.stories.js +0 -77
- package/src/components/btn-actions/QasBtnActions.vue +0 -54
- package/src/components/card/QasCard.stories.js +0 -126
- package/src/components/checkbox-group/QasCheckboxGroup.stories.js +0 -59
- package/src/components/copy/QasCopy.stories.js +0 -41
- package/src/components/date-time-input/QasDateTimeInput.stories.js +0 -67
- package/src/components/debugger/QasDebugger.stories.js +0 -33
- package/src/components/decimal-input/QasDecimalInput.stories.js +0 -82
- package/src/components/decimal-input/QasDecimalInput.vue +0 -92
- package/src/components/delete/QasDelete.stories.js +0 -80
- package/src/components/dialog/QasDialog.stories.js +0 -139
- package/src/components/dialog-router/QasDialogRouter.stories.js +0 -38
- package/src/components/field/QasField.stories.js +0 -181
- package/src/components/filters/QasFilters.stories.js +0 -121
- package/src/components/form-generator/QasFormGenerator.stories.js +0 -115
- package/src/components/form-view/QasFormView.stories.js +0 -236
- package/src/components/gallery/QasGallery.stories.js +0 -91
- package/src/components/grid-generator/QasGridGenerator.stories.js +0 -138
- package/src/components/input/QasInput.stories.js +0 -78
- package/src/components/label/QasLabel.stories.js +0 -60
- package/src/components/list-items/QasListItems.stories.js +0 -130
- package/src/components/list-view/QasListView.stories.js +0 -168
- package/src/components/map/QasMap.stories.js +0 -75
- package/src/components/nested-fields/QasNestedFields.stories.js +0 -255
- package/src/components/page-header/QasPageHeader.stories.js +0 -61
- package/src/components/password-input/QasPasswordInput.stories.js +0 -76
- package/src/components/password-strength-checker/QasPasswordStrengthChecker.stories.js +0 -54
- package/src/components/profile/QasProfile.stories.js +0 -131
- package/src/components/resizer/QasResizer.stories.js +0 -43
- package/src/components/search-box/QasSearchBox.stories.js +0 -111
- package/src/components/select/QasSelect.stories.js +0 -113
- package/src/components/select-list/QasSelectList.stories.js +0 -153
- package/src/components/signature-pad/QasSignaturePad.stories.js +0 -51
- package/src/components/signature-uploader/QasSignatureUploader.stories.js +0 -69
- package/src/components/single-view/QasSingleView.stories.js +0 -130
- package/src/components/sortable/QasSortable.stories.js +0 -80
- package/src/components/table-generator/QasTableGenerator.stories.js +0 -116
- package/src/components/tabs-generator/QasTabsGenerator.stories.js +0 -145
- package/src/components/text-truncate/QasTextTruncate.stories.js +0 -55
- package/src/components/tip/QasTip.stories.js +0 -57
- package/src/components/tip/QasTip.vue +0 -68
- package/src/components/tooltip/QasTooltip.stories.js +0 -63
- package/src/components/tooltip/QasTooltip.vue +0 -81
- package/src/components/transfer/QasTransfer.stories.js +0 -118
- package/src/components/uploader/QasCustomUploader.vue +0 -121
- package/src/components/uploader/QasUploader.stories.js +0 -139
- package/src/directives/Test.js +0 -13
- package/src/helpers/historyHandler.js +0 -52
- package/src/helpers/label.js +0 -3
- package/src/index.js +0 -245
- package/src/mixins/map-markers.js +0 -26
- package/src/mixins/unsaved-changes.js +0 -24
- package/src/mixins/uploader.js +0 -30
- package/src/mocks/json/user.json +0 -27
- package/src/mocks/json/users-new.json +0 -23
- package/src/mocks/json/users.json +0 -97
- package/src/mocks/storeModule.js +0 -71
- package/src/pages/Forbidden.vue +0 -6
- package/src/pages/NotFound.vue +0 -6
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="qas-transfer row" :class="gutterClass">
|
|
3
|
+
<div class="col-12" />
|
|
3
4
|
<div class="col-12 col-sm">
|
|
4
5
|
<qas-label :label="label" :quantity="optionsList.length" />
|
|
5
6
|
|
|
6
7
|
<qas-search-box form-mode :list="optionsList" v-bind="searchBoxProps">
|
|
7
8
|
<template #default="{ results }">
|
|
8
9
|
<q-list separator>
|
|
9
|
-
<q-item v-for="(item, index) in results" :key="index" :class="
|
|
10
|
+
<q-item v-for="(item, index) in results" :key="index" :class="getItemClass(item, true)" clickable @click="onSelectQueue(item, true)">
|
|
10
11
|
<slot name="item-first-column">
|
|
11
|
-
<q-item-section>{{ item
|
|
12
|
+
<q-item-section>{{ getItemLabel(item) }}</q-item-section>
|
|
12
13
|
</slot>
|
|
13
14
|
</q-item>
|
|
14
15
|
</q-list>
|
|
@@ -18,10 +19,8 @@
|
|
|
18
19
|
|
|
19
20
|
<div class="col-12 col-sm-auto items-center justify-center q-col-gutter-md row" :class="actionsClass">
|
|
20
21
|
<div>
|
|
21
|
-
<
|
|
22
|
-
|
|
23
|
-
<q-tooltip anchor="top middle" self="center middle">Selecionar</q-tooltip>
|
|
24
|
-
</div>
|
|
22
|
+
<qas-btn :class="iconClass" dense :disabled="!firstQueue.length" flat icon="o_arrow_circle_down" rounded @click="setSelectedFromClick(true)" />
|
|
23
|
+
<q-tooltip anchor="top middle" self="center middle">Selecionar</q-tooltip>
|
|
25
24
|
</div>
|
|
26
25
|
<div>
|
|
27
26
|
<div>
|
|
@@ -34,12 +33,12 @@
|
|
|
34
33
|
<div class="col-12 col-sm">
|
|
35
34
|
<qas-label label="Selecionadas" :quantity="selectedList.length" />
|
|
36
35
|
|
|
37
|
-
<qas-search-box v-bind="searchBoxProps" empty-list-height="300px" form-mode label="Selecionadas" :list="selectedList"
|
|
36
|
+
<qas-search-box v-bind="searchBoxProps" empty-list-height="300px" form-mode label="Selecionadas" :list="selectedList">
|
|
38
37
|
<template #default="{ results }">
|
|
39
38
|
<q-list separator>
|
|
40
|
-
<q-item v-for="(item, index) in results" :key="index" :class="
|
|
39
|
+
<q-item v-for="(item, index) in results" :key="index" :class="getItemClass(item)" clickable @click="onSelectQueue(item)">
|
|
41
40
|
<slot name="item-second-column">
|
|
42
|
-
<q-item-section>{{ item
|
|
41
|
+
<q-item-section>{{ getItemLabel(item) }}</q-item-section>
|
|
43
42
|
</slot>
|
|
44
43
|
</q-item>
|
|
45
44
|
</q-list>
|
|
@@ -50,19 +49,24 @@
|
|
|
50
49
|
</template>
|
|
51
50
|
|
|
52
51
|
<script>
|
|
52
|
+
import { screenMixin } from '../../mixins'
|
|
53
53
|
import { extend } from 'quasar'
|
|
54
54
|
|
|
55
|
-
import QasBtn from '../btn/QasBtn'
|
|
56
|
-
import QasLabel from '../label/QasLabel'
|
|
57
|
-
import QasSearchBox from '../search-box/QasSearchBox'
|
|
55
|
+
import QasBtn from '../btn/QasBtn.vue'
|
|
56
|
+
import QasLabel from '../label/QasLabel.vue'
|
|
57
|
+
import QasSearchBox from '../search-box/QasSearchBox.vue'
|
|
58
58
|
|
|
59
59
|
export default {
|
|
60
|
+
name: 'QasTransfer',
|
|
61
|
+
|
|
60
62
|
components: {
|
|
61
63
|
QasBtn,
|
|
62
64
|
QasLabel,
|
|
63
65
|
QasSearchBox
|
|
64
66
|
},
|
|
65
67
|
|
|
68
|
+
mixins: [screenMixin],
|
|
69
|
+
|
|
66
70
|
props: {
|
|
67
71
|
emitValue: {
|
|
68
72
|
type: Boolean
|
|
@@ -73,12 +77,6 @@ export default {
|
|
|
73
77
|
type: Object
|
|
74
78
|
},
|
|
75
79
|
|
|
76
|
-
hideEmptySlot: {
|
|
77
|
-
default: true,
|
|
78
|
-
type: Boolean
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
// TODO: Criar o "toLabel" para o slugar de selecionados.
|
|
82
80
|
label: {
|
|
83
81
|
default: '',
|
|
84
82
|
required: true,
|
|
@@ -90,22 +88,29 @@ export default {
|
|
|
90
88
|
type: String
|
|
91
89
|
},
|
|
92
90
|
|
|
93
|
-
|
|
91
|
+
modelValue: {
|
|
94
92
|
default: () => [],
|
|
95
93
|
type: Array
|
|
96
94
|
},
|
|
97
95
|
|
|
98
|
-
|
|
96
|
+
options: {
|
|
99
97
|
default: () => [],
|
|
100
98
|
type: Array
|
|
101
99
|
},
|
|
102
100
|
|
|
101
|
+
useEmptySlot: {
|
|
102
|
+
default: true,
|
|
103
|
+
type: Boolean
|
|
104
|
+
},
|
|
105
|
+
|
|
103
106
|
valueKey: {
|
|
104
107
|
default: 'value',
|
|
105
108
|
type: String
|
|
106
109
|
}
|
|
107
110
|
},
|
|
108
111
|
|
|
112
|
+
emits: ['update:modelValue'],
|
|
113
|
+
|
|
109
114
|
data () {
|
|
110
115
|
return {
|
|
111
116
|
firstQueue: [],
|
|
@@ -117,50 +122,46 @@ export default {
|
|
|
117
122
|
|
|
118
123
|
computed: {
|
|
119
124
|
actionsClass () {
|
|
120
|
-
return !this.
|
|
125
|
+
return !this.mx_isSmall && 'column'
|
|
121
126
|
},
|
|
122
127
|
|
|
123
128
|
gutterClass () {
|
|
124
|
-
return `q-col-gutter-${this.
|
|
129
|
+
return `q-col-gutter-${this.mx_untilLarge ? 'md' : 'xl'}`
|
|
125
130
|
},
|
|
126
131
|
|
|
127
132
|
iconClass () {
|
|
128
|
-
return !this.
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
isMedium () {
|
|
132
|
-
return this.$q.screen.lt.md
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
// TODO: Small seria se fosse sm.
|
|
136
|
-
isSmall () {
|
|
137
|
-
return this.$q.screen.xs
|
|
133
|
+
return !this.mx_isSmall && 'qas-transfer__icon'
|
|
138
134
|
},
|
|
139
135
|
|
|
140
136
|
searchBoxProps () {
|
|
141
137
|
return {
|
|
142
138
|
fuseOptions: this.fuseOptions,
|
|
143
|
-
|
|
144
|
-
list: this.options
|
|
139
|
+
useEmptySlot: this.useEmptySlot
|
|
145
140
|
}
|
|
146
141
|
}
|
|
147
142
|
},
|
|
148
143
|
|
|
149
144
|
watch: {
|
|
150
|
-
|
|
151
|
-
handler (
|
|
152
|
-
this.
|
|
145
|
+
modelValue: {
|
|
146
|
+
handler () {
|
|
147
|
+
this.setSelectedFromValue(true)
|
|
153
148
|
},
|
|
154
149
|
|
|
155
150
|
immediate: true
|
|
156
151
|
},
|
|
157
152
|
|
|
158
|
-
|
|
159
|
-
handler (value
|
|
160
|
-
this.
|
|
153
|
+
options: {
|
|
154
|
+
handler (value) {
|
|
155
|
+
this.optionsList = extend(true, [], value)
|
|
161
156
|
},
|
|
162
157
|
|
|
163
158
|
immediate: true
|
|
159
|
+
},
|
|
160
|
+
|
|
161
|
+
selectedList: {
|
|
162
|
+
handler () {
|
|
163
|
+
this.updateModelValue()
|
|
164
|
+
}
|
|
164
165
|
}
|
|
165
166
|
},
|
|
166
167
|
|
|
@@ -178,7 +179,18 @@ export default {
|
|
|
178
179
|
})
|
|
179
180
|
},
|
|
180
181
|
|
|
181
|
-
|
|
182
|
+
getItemClass (object, isFirst) {
|
|
183
|
+
return this[isFirst
|
|
184
|
+
? 'firstQueue'
|
|
185
|
+
: 'secondQueue'
|
|
186
|
+
].some(item => item[this.valueKey] === object[this.valueKey]) && 'bg-secondary'
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
getItemLabel (item) {
|
|
190
|
+
return item?.[this.labelKey]
|
|
191
|
+
},
|
|
192
|
+
|
|
193
|
+
getModelValue () {
|
|
182
194
|
const selectedList = extend(true, [], this.selectedList)
|
|
183
195
|
return this.emitValue ? selectedList.map(item => item[this.valueKey]) : selectedList
|
|
184
196
|
},
|
|
@@ -191,27 +203,19 @@ export default {
|
|
|
191
203
|
this[model] = []
|
|
192
204
|
},
|
|
193
205
|
|
|
194
|
-
itemClass (object, isFirst) {
|
|
195
|
-
return this[isFirst
|
|
196
|
-
? 'firstQueue'
|
|
197
|
-
: 'secondQueue'
|
|
198
|
-
].some(item => item[this.valueKey] === object[this.valueKey]) && 'bg-secondary'
|
|
199
|
-
},
|
|
200
|
-
|
|
201
206
|
onSelectQueue (item, isFirst) {
|
|
202
207
|
const model = isFirst ? 'firstQueue' : 'secondQueue'
|
|
203
208
|
const index = this[model].findIndex(selected => selected[this.valueKey] === item[this.valueKey])
|
|
204
209
|
|
|
205
|
-
|
|
210
|
+
~index ? this[model].splice(index, 1) : this[model].push(item)
|
|
206
211
|
},
|
|
207
212
|
|
|
208
213
|
setSelectedFromClick (isFirst) {
|
|
209
214
|
this.handleSelectedList(isFirst)
|
|
210
|
-
this.updateValue()
|
|
211
215
|
},
|
|
212
216
|
|
|
213
217
|
setSelectedFromValue (isFirst) {
|
|
214
|
-
this.
|
|
218
|
+
this.modelValue.forEach(item => {
|
|
215
219
|
const selected = this.optionsList.find(option => {
|
|
216
220
|
return option[this.valueKey] === (this.emitValue ? item : item[this.valueKey])
|
|
217
221
|
})
|
|
@@ -224,8 +228,8 @@ export default {
|
|
|
224
228
|
this.handleSelectedList(isFirst)
|
|
225
229
|
},
|
|
226
230
|
|
|
227
|
-
|
|
228
|
-
return this.$emit('
|
|
231
|
+
updateModelValue () {
|
|
232
|
+
return this.$emit('update:modelValue', this.getModelValue())
|
|
229
233
|
}
|
|
230
234
|
}
|
|
231
235
|
}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<q-field borderless :error="hasErrorMessage" :error-message="errorMessage" :hint="hintValue" no-error-icon>
|
|
3
|
-
<
|
|
2
|
+
<q-field borderless class="qas-uploader" :error="hasErrorMessage" :error-message="errorMessage" :hint="hintValue" no-error-icon>
|
|
3
|
+
<q-uploader ref="uploader" auto-upload bordered :class="uploaderClasses" :factory="factory" flat :max-files="maxFiles" method="PUT" :readonly="readonly" v-bind="attributes" @factory-failed="factoryFailed" @uploaded="uploaded" @uploading="updateUploading(true)">
|
|
4
4
|
<template #header="scope">
|
|
5
5
|
<slot name="header" :scope="scope">
|
|
6
6
|
<div class="flex flex-center full-width justify-between no-border no-wrap q-gutter-xs q-pa-sm text-white transparent">
|
|
7
7
|
<q-spinner v-if="scope.isUploading" size="24px" />
|
|
8
8
|
|
|
9
9
|
<div class="col column items-start justify-center">
|
|
10
|
-
<div v-if="
|
|
11
|
-
<div v-if="scope.files.length" class="q-uploader__subtitle">
|
|
10
|
+
<div v-if="$attrs.label" class="q-uploader__title">{{ $attrs.label }}</div>
|
|
11
|
+
<div v-if="scope.files.length" class="q-uploader__subtitle">
|
|
12
|
+
{{ scope.uploadProgressLabel }} ({{ scope.uploadSizeLabel }})
|
|
13
|
+
</div>
|
|
12
14
|
</div>
|
|
13
15
|
|
|
14
|
-
<
|
|
15
|
-
|
|
16
|
-
<q-uploader-add-trigger v-if="showAddFile" ref="uploaderTrigger" />
|
|
16
|
+
<qas-btn v-if="showAddFile" ref="buttonUpload" color="white" dense flat icon="o_add" round @click="$refs.hidenInput.click()" />
|
|
17
17
|
|
|
18
|
-
<
|
|
18
|
+
<input ref="hidenInput" class="qas-uploader__input" :multiple="isMultiple" type="file">
|
|
19
19
|
|
|
20
|
-
<
|
|
21
|
-
<
|
|
20
|
+
<qas-btn ref="buttonCleanFiles" class="hidden" color="white" @click="scope.removeUploadedFiles" />
|
|
21
|
+
<qas-btn v-if="scope.canUpload" color="white" dense flat icon="o_cloud_upload" round @click="scope.upload" />
|
|
22
|
+
<qas-btn v-if="scope.isUploading" color="white" dense flat icon="o_clear" round @click="scope.abort" />
|
|
22
23
|
</div>
|
|
23
24
|
</slot>
|
|
24
25
|
</template>
|
|
@@ -26,24 +27,24 @@
|
|
|
26
27
|
<template #list="scope">
|
|
27
28
|
<slot name="list" :scope="scope">
|
|
28
29
|
<div class="col-12 q-col-gutter-md row">
|
|
29
|
-
<div v-for="(file, index) in
|
|
30
|
-
<qas-avatar class="q-mr-sm" color="grey-3" icon="o_attach_file" :image="file.image" rounded :text-color="
|
|
30
|
+
<div v-for="(file, index) in getFilesList(scope.files, scope)" :key="index" class="row" :class="itemClass">
|
|
31
|
+
<qas-avatar class="q-mr-sm" color="grey-3" icon="o_attach_file" :image="file.image" rounded :text-color="getColorFileIcon(file)" />
|
|
31
32
|
|
|
32
33
|
<div class="col items-center no-wrap row">
|
|
33
34
|
<div class="column no-wrap" :class="{ col: isMultiple }">
|
|
34
|
-
<div class="ellipsis" :class="
|
|
35
|
+
<div class="ellipsis" :class="getFileNameClass(file.isFailed)">{{ file.name }}</div>
|
|
35
36
|
<div v-if="file.isUploaded" class="text-caption">{{ file.progressLabel }} ({{ file.sizeLabel }})</div>
|
|
36
37
|
</div>
|
|
37
38
|
<div class="items-center q-ml-sm row">
|
|
38
39
|
<q-icon v-if="file.isFailed" color="negative" name="o_warning" size="20px" />
|
|
39
|
-
<
|
|
40
|
+
<qas-btn v-if="!scope.readonly" dense flat icon="o_delete" round @click="removeItem(index, scope, file)" />
|
|
40
41
|
</div>
|
|
41
42
|
</div>
|
|
42
43
|
</div>
|
|
43
44
|
</div>
|
|
44
45
|
</slot>
|
|
45
46
|
</template>
|
|
46
|
-
</
|
|
47
|
+
</q-uploader>
|
|
47
48
|
|
|
48
49
|
<slot :context="self" name="custom-upload" />
|
|
49
50
|
|
|
@@ -54,24 +55,37 @@
|
|
|
54
55
|
</template>
|
|
55
56
|
|
|
56
57
|
<script>
|
|
57
|
-
import QasAvatar from '../avatar/QasAvatar'
|
|
58
|
-
|
|
59
|
-
import api from 'axios'
|
|
58
|
+
import QasAvatar from '../avatar/QasAvatar.vue'
|
|
59
|
+
|
|
60
60
|
import { uid, extend } from 'quasar'
|
|
61
61
|
import { NotifyError } from '../../plugins'
|
|
62
|
-
import
|
|
62
|
+
import { getImageSize, getResizeDimensions } from '../../helpers/images'
|
|
63
|
+
|
|
64
|
+
import Pica from 'pica'
|
|
65
|
+
import api from 'axios'
|
|
63
66
|
|
|
64
67
|
export default {
|
|
65
68
|
name: 'QasUploader',
|
|
66
69
|
|
|
67
70
|
components: {
|
|
68
|
-
QasAvatar
|
|
69
|
-
QasCustomUploader
|
|
71
|
+
QasAvatar
|
|
70
72
|
},
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
inheritAttrs: false,
|
|
73
75
|
|
|
74
76
|
props: {
|
|
77
|
+
acceptResizeTypes: {
|
|
78
|
+
default: () => [
|
|
79
|
+
'image/jpeg',
|
|
80
|
+
'image/png',
|
|
81
|
+
'image/gif',
|
|
82
|
+
'image/bmp',
|
|
83
|
+
'image/webp',
|
|
84
|
+
'image/jpg'
|
|
85
|
+
],
|
|
86
|
+
type: Array
|
|
87
|
+
},
|
|
88
|
+
|
|
75
89
|
entity: {
|
|
76
90
|
required: true,
|
|
77
91
|
type: String
|
|
@@ -92,20 +106,43 @@ export default {
|
|
|
92
106
|
type: Number
|
|
93
107
|
},
|
|
94
108
|
|
|
109
|
+
picaResizeOptions: {
|
|
110
|
+
default: () => ({}),
|
|
111
|
+
type: Object
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
sizeLimit: {
|
|
115
|
+
default: 1280,
|
|
116
|
+
type: Number
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
useResize: {
|
|
120
|
+
default: true,
|
|
121
|
+
type: Boolean
|
|
122
|
+
},
|
|
123
|
+
|
|
95
124
|
readonly: {
|
|
96
125
|
type: Boolean
|
|
97
126
|
},
|
|
98
127
|
|
|
99
|
-
|
|
128
|
+
modelValue: {
|
|
100
129
|
default: '',
|
|
101
130
|
type: [Array, String]
|
|
131
|
+
},
|
|
132
|
+
|
|
133
|
+
uploading: {
|
|
134
|
+
type: Boolean
|
|
102
135
|
}
|
|
103
136
|
},
|
|
104
137
|
|
|
138
|
+
emits: ['update:modelValue', 'update:uploading'],
|
|
139
|
+
|
|
105
140
|
data () {
|
|
106
141
|
return {
|
|
107
142
|
isFetching: false,
|
|
108
|
-
isUploading: false
|
|
143
|
+
isUploading: false,
|
|
144
|
+
hidenInputElement: null,
|
|
145
|
+
uploader: null
|
|
109
146
|
}
|
|
110
147
|
},
|
|
111
148
|
|
|
@@ -121,7 +158,7 @@ export default {
|
|
|
121
158
|
showAddFile () {
|
|
122
159
|
if (this.readonly) return
|
|
123
160
|
|
|
124
|
-
return this.maxFiles ? this.
|
|
161
|
+
return this.maxFiles ? this.modelValue.length < this.maxFiles : true
|
|
125
162
|
},
|
|
126
163
|
|
|
127
164
|
isMultiple () {
|
|
@@ -129,7 +166,7 @@ export default {
|
|
|
129
166
|
},
|
|
130
167
|
|
|
131
168
|
hasCustomUpload () {
|
|
132
|
-
return this.$slots['custom-upload']
|
|
169
|
+
return this.$slots['custom-upload']
|
|
133
170
|
},
|
|
134
171
|
|
|
135
172
|
itemClass () {
|
|
@@ -141,7 +178,7 @@ export default {
|
|
|
141
178
|
},
|
|
142
179
|
|
|
143
180
|
hasHeaderSlot () {
|
|
144
|
-
return this.$slots.header
|
|
181
|
+
return this.$slots.header
|
|
145
182
|
},
|
|
146
183
|
|
|
147
184
|
hasErrorMessage () {
|
|
@@ -153,19 +190,37 @@ export default {
|
|
|
153
190
|
...this.$attrs,
|
|
154
191
|
...this.$props
|
|
155
192
|
}
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
defaultPicaResizeOptions () {
|
|
196
|
+
return {
|
|
197
|
+
unsharpAmount: 160,
|
|
198
|
+
unsharpRadius: 0.6,
|
|
199
|
+
unsharpThreshold: 1,
|
|
200
|
+
...this.picaResizeOptions
|
|
201
|
+
}
|
|
156
202
|
}
|
|
157
203
|
},
|
|
158
204
|
|
|
159
|
-
|
|
160
|
-
|
|
205
|
+
mounted () {
|
|
206
|
+
this.hidenInputElement = this.$refs.hidenInput
|
|
207
|
+
this.uploader = this.$refs.uploader
|
|
208
|
+
|
|
209
|
+
this.hidenInputElement?.addEventListener?.('change', this.addFiles)
|
|
210
|
+
},
|
|
161
211
|
|
|
212
|
+
unmounted () {
|
|
213
|
+
this.hidenInputElement?.removeEventListener?.('change', this.addFiles)
|
|
214
|
+
},
|
|
215
|
+
|
|
216
|
+
methods: {
|
|
162
217
|
async factory ([file]) {
|
|
163
218
|
if (!this.isMultiple && !this.hasHeaderSlot) {
|
|
164
219
|
this.$refs.buttonCleanFiles.$el.click()
|
|
165
220
|
}
|
|
166
221
|
|
|
167
222
|
const name = `${uid()}.${file.name.split('.').pop()}`
|
|
168
|
-
const { endpoint } = await this.
|
|
223
|
+
const { endpoint } = await this.fetchCredentials(name)
|
|
169
224
|
|
|
170
225
|
return {
|
|
171
226
|
headers: [
|
|
@@ -178,16 +233,27 @@ export default {
|
|
|
178
233
|
},
|
|
179
234
|
|
|
180
235
|
factoryFailed () {
|
|
236
|
+
this.updateUploading(false)
|
|
181
237
|
NotifyError('Ops! Erro ao enviar o arquivo.')
|
|
182
238
|
},
|
|
183
239
|
|
|
240
|
+
dispatchUpload () {
|
|
241
|
+
this.$refs.buttonCleanFiles.$el.click()
|
|
242
|
+
this.hidenInputElement.click()
|
|
243
|
+
},
|
|
244
|
+
|
|
184
245
|
uploaded (response) {
|
|
185
246
|
const fullPath = response.xhr.responseURL.split('?').shift()
|
|
186
247
|
|
|
187
|
-
this.$emit(
|
|
248
|
+
this.$emit(
|
|
249
|
+
'update:modelValue',
|
|
250
|
+
this.isMultiple ? [...this.modelValue, fullPath] : fullPath || ''
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
this.updateUploading(false)
|
|
188
254
|
},
|
|
189
255
|
|
|
190
|
-
async
|
|
256
|
+
async fetchCredentials (filename) {
|
|
191
257
|
this.isFetching = true
|
|
192
258
|
|
|
193
259
|
try {
|
|
@@ -209,26 +275,21 @@ export default {
|
|
|
209
275
|
if (file.isFailed) return
|
|
210
276
|
|
|
211
277
|
if (!this.isMultiple) {
|
|
212
|
-
return this.$emit('
|
|
278
|
+
return this.$emit('update:modelValue')
|
|
213
279
|
}
|
|
214
280
|
|
|
215
|
-
const clonedValue = extend(true, [], this.
|
|
216
|
-
const numberIndex = this.
|
|
281
|
+
const clonedValue = extend(true, [], this.modelValue)
|
|
282
|
+
const numberIndex = this.modelValue.findIndex(file => this.getFileName(file) === index)
|
|
217
283
|
clonedValue.splice(numberIndex, 1)
|
|
218
|
-
this.$emit('
|
|
219
|
-
},
|
|
220
|
-
|
|
221
|
-
dispatchUpload () {
|
|
222
|
-
this.$refs.buttonCleanFiles.$el.click()
|
|
223
|
-
this.$refs.uploaderTrigger.$el.click()
|
|
284
|
+
this.$emit('update:modelValue', clonedValue)
|
|
224
285
|
},
|
|
225
286
|
|
|
226
|
-
|
|
287
|
+
getFileName (value) {
|
|
227
288
|
return value.split('/').pop()
|
|
228
289
|
},
|
|
229
290
|
|
|
230
|
-
|
|
231
|
-
const pathsList = Array.isArray(this.
|
|
291
|
+
getFilesList (uploadedFiles) {
|
|
292
|
+
const pathsList = Array.isArray(this.modelValue) ? this.modelValue : (this.modelValue ? [this.modelValue] : [])
|
|
232
293
|
|
|
233
294
|
uploadedFiles = uploadedFiles.map((file, indexToDelete) => {
|
|
234
295
|
return {
|
|
@@ -253,13 +314,13 @@ export default {
|
|
|
253
314
|
}
|
|
254
315
|
|
|
255
316
|
if (typeof file === 'string') {
|
|
256
|
-
const fileName = this.
|
|
317
|
+
const fileName = this.getFileName(file)
|
|
257
318
|
files[fileName] = { image: file, isUploaded: false, name: fileName }
|
|
258
319
|
return
|
|
259
320
|
}
|
|
260
321
|
|
|
261
322
|
if (file.image) {
|
|
262
|
-
const fileName = this.
|
|
323
|
+
const fileName = this.getFileName(file.image)
|
|
263
324
|
files[fileName] = file
|
|
264
325
|
}
|
|
265
326
|
})
|
|
@@ -267,7 +328,7 @@ export default {
|
|
|
267
328
|
return files
|
|
268
329
|
},
|
|
269
330
|
|
|
270
|
-
|
|
331
|
+
getFileNameClass (isFailed) {
|
|
271
332
|
return isFailed ? 'text-negative' : 'text-grey-8'
|
|
272
333
|
},
|
|
273
334
|
|
|
@@ -275,9 +336,69 @@ export default {
|
|
|
275
336
|
return file.__status === 'failed'
|
|
276
337
|
},
|
|
277
338
|
|
|
278
|
-
|
|
339
|
+
getColorFileIcon (file) {
|
|
279
340
|
return this.isFailed(file) ? 'negative' : 'primary'
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
async addFiles () {
|
|
344
|
+
const filesList = Array.from(this.hidenInputElement.files)
|
|
345
|
+
const processedFiles = []
|
|
346
|
+
|
|
347
|
+
filesList.forEach(file => processedFiles.push(this.resizeImage(file)))
|
|
348
|
+
this.uploader.addFiles(await Promise.all(processedFiles))
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
// Função para redimensionar imagens
|
|
352
|
+
async resizeImage (file) {
|
|
353
|
+
const { type } = file
|
|
354
|
+
|
|
355
|
+
if (!this.acceptResizeTypes.includes(type) || !this.useResize) return file
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
const image = new Image()
|
|
359
|
+
const canvas = document.createElement('canvas')
|
|
360
|
+
|
|
361
|
+
image.src = URL.createObjectURL(file)
|
|
362
|
+
|
|
363
|
+
// Retorna largura e altura da original da imagem
|
|
364
|
+
const { width, height } = await getImageSize(image)
|
|
365
|
+
|
|
366
|
+
if (width <= this.sizeLimit) return file
|
|
367
|
+
|
|
368
|
+
// Retorna os novos tamanhos redimensionados
|
|
369
|
+
const resizedDimensions = getResizeDimensions(this.sizeLimit, width, height)
|
|
370
|
+
|
|
371
|
+
canvas.width = resizedDimensions.width
|
|
372
|
+
canvas.height = resizedDimensions.height
|
|
373
|
+
|
|
374
|
+
// Resolve problemas com cors
|
|
375
|
+
image.crossOrigin = ''
|
|
376
|
+
|
|
377
|
+
image.width = width
|
|
378
|
+
image.height = height
|
|
379
|
+
|
|
380
|
+
const pica = Pica()
|
|
381
|
+
const resizedImage = await pica.resize(image, canvas, this.defaultPicaResizeOptions)
|
|
382
|
+
const blob = await pica.toBlob(resizedImage, type, 0.90)
|
|
383
|
+
|
|
384
|
+
return new File([blob], file.name, { type })
|
|
385
|
+
} catch {
|
|
386
|
+
// Caso não consiga redimensionar retorna o arquivo original
|
|
387
|
+
return file
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
updateUploading (uploading) {
|
|
392
|
+
this.$emit('update:uploading', uploading)
|
|
280
393
|
}
|
|
281
394
|
}
|
|
282
395
|
}
|
|
283
396
|
</script>
|
|
397
|
+
|
|
398
|
+
<style lang="scss">
|
|
399
|
+
.qas-uploader {
|
|
400
|
+
&__input {
|
|
401
|
+
display: none;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
</style>
|
package/src/css/background.scss
CHANGED
package/src/css/border.scss
CHANGED
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
}
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
-
@mixin
|
|
8
|
+
@mixin set-border-color($name, $color) {
|
|
9
9
|
.border-#{$name} {
|
|
10
|
-
@extend %border-color;
|
|
11
10
|
border: 0 solid $color !important;
|
|
11
|
+
|
|
12
|
+
@extend %border-color;
|
|
12
13
|
}
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
@include
|
|
16
|
-
@include
|
|
17
|
-
@include
|
|
18
|
-
@include
|
|
16
|
+
@include set-border-color(primary, $primary);
|
|
17
|
+
@include set-border-color(primary-contrast, $primary-contrast);
|
|
18
|
+
@include set-border-color(secondary, $secondary);
|
|
19
|
+
@include set-border-color(secondary-contrast, $secondary-contrast);
|
|
19
20
|
|
|
20
21
|
// Direction
|
|
21
22
|
.border-top {
|