atom-nuxt 1.0.141 → 1.0.142
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/module.json
CHANGED
|
@@ -54,19 +54,22 @@ const dialog = ref(false);
|
|
|
54
54
|
const filesToUpload = ref([]);
|
|
55
55
|
const fileToUpload = ref(null);
|
|
56
56
|
const searchValue = ref(null);
|
|
57
|
+
const tempModel = ref(null);
|
|
58
|
+
const cloneModel = () => props.multiple ? [...model.value || []] : model.value;
|
|
57
59
|
const finish = () => {
|
|
60
|
+
model.value = props.multiple ? [...tempModel.value] : tempModel.value;
|
|
58
61
|
dialog.value = false;
|
|
59
62
|
};
|
|
60
63
|
const onSelectImage = (item) => {
|
|
61
64
|
if (props.multiple) {
|
|
62
|
-
if (
|
|
63
|
-
if (!
|
|
64
|
-
|
|
65
|
+
if (!tempModel.value) tempModel.value = [];
|
|
66
|
+
if (!tempModel.value.includes(item)) {
|
|
67
|
+
tempModel.value.push(item);
|
|
65
68
|
} else {
|
|
66
|
-
|
|
69
|
+
tempModel.value = tempModel.value.filter((i) => i !== item);
|
|
67
70
|
}
|
|
68
71
|
} else {
|
|
69
|
-
|
|
72
|
+
tempModel.value = tempModel.value === item ? null : item;
|
|
70
73
|
}
|
|
71
74
|
};
|
|
72
75
|
const {
|
|
@@ -103,12 +106,14 @@ const processUploads = async () => {
|
|
|
103
106
|
await createUpload(upload);
|
|
104
107
|
if (!hasUploadErrors.value && hasItem.value) {
|
|
105
108
|
model.value = completedUpload.value.id;
|
|
109
|
+
dialog.value = false;
|
|
106
110
|
}
|
|
107
111
|
}
|
|
108
112
|
uploadsLoading.value = false;
|
|
109
|
-
if (
|
|
113
|
+
if (props.multiple) {
|
|
110
114
|
filesToUpload.value = [];
|
|
111
|
-
|
|
115
|
+
} else {
|
|
116
|
+
fileToUpload.value = null;
|
|
112
117
|
}
|
|
113
118
|
};
|
|
114
119
|
const selectionFilters = computed(() => {
|
|
@@ -125,6 +130,11 @@ const hasSelection = computed(() => {
|
|
|
125
130
|
return model.value && model.value !== "" && (model.value.length > 0 || model.value > 0);
|
|
126
131
|
}
|
|
127
132
|
});
|
|
133
|
+
watch(() => dialog.value, (val) => {
|
|
134
|
+
if (val) {
|
|
135
|
+
tempModel.value = cloneModel();
|
|
136
|
+
}
|
|
137
|
+
});
|
|
128
138
|
watch(() => filesToUpload.value, () => {
|
|
129
139
|
if (filesToUpload.value.length > 0) {
|
|
130
140
|
processUploads();
|
|
@@ -140,14 +150,20 @@ watch(() => fileToUpload.value, () => {
|
|
|
140
150
|
<template>
|
|
141
151
|
<div>
|
|
142
152
|
<div v-if="title" style="font-size: 12px;" class="text-grey-darken-2 mb-1">{{ title }}</div>
|
|
153
|
+
|
|
143
154
|
<div v-if="!hasSelection" class="mb-3">
|
|
144
|
-
<v-btn :disabled="disabled" @click="dialog = true" size="small"
|
|
145
|
-
color="success">
|
|
155
|
+
<v-btn :disabled="disabled" @click="dialog = true" size="small" color="success">
|
|
146
156
|
Select Media
|
|
147
157
|
</v-btn>
|
|
148
158
|
</div>
|
|
149
|
-
|
|
150
|
-
|
|
159
|
+
|
|
160
|
+
<crud-list-loader
|
|
161
|
+
v-if="hasSelection"
|
|
162
|
+
:per-page="1000"
|
|
163
|
+
:disable-no-results="true"
|
|
164
|
+
:custom-filters="selectionFilters"
|
|
165
|
+
:path="path"
|
|
166
|
+
>
|
|
151
167
|
<template #default="uploadSlot">
|
|
152
168
|
<div v-for="item in uploadSlot.items" :key="item.id">
|
|
153
169
|
<crud-upload-field-selection
|
|
@@ -156,19 +172,20 @@ watch(() => fileToUpload.value, () => {
|
|
|
156
172
|
:file-name-key="fileNameKey"
|
|
157
173
|
:image-click-action="() => { if(replaceable && !multiple) { dialog = true; }}"
|
|
158
174
|
:item="item"
|
|
159
|
-
:selected="false"
|
|
175
|
+
:selected="false"
|
|
176
|
+
>
|
|
160
177
|
<template #additionalActions>
|
|
161
|
-
<slot name="additionalActions" :item="item"
|
|
162
|
-
|
|
163
|
-
</slot>
|
|
178
|
+
<slot name="additionalActions" :item="item" />
|
|
164
179
|
</template>
|
|
165
180
|
</crud-upload-field-selection>
|
|
166
181
|
</div>
|
|
167
182
|
</template>
|
|
168
183
|
</crud-list-loader>
|
|
169
|
-
|
|
184
|
+
|
|
185
|
+
<v-dialog v-model="dialog" @update:modelValue="val => { dialog = val; if (val) tempModel = cloneModel(); }" max-width="1700">
|
|
170
186
|
<v-card>
|
|
171
187
|
<h2 class="mb-0 border-b pa-4" v-if="title">{{ title }}</h2>
|
|
188
|
+
|
|
172
189
|
<div style="height: 90vh; overflow: auto;" class="pa-4 d-flex flex-column">
|
|
173
190
|
<div class="flex-wrap">
|
|
174
191
|
<div class="border pa-3 rounded mb-3">
|
|
@@ -189,13 +206,15 @@ watch(() => fileToUpload.value, () => {
|
|
|
189
206
|
v-model="fileToUpload"
|
|
190
207
|
:disabled="uploadsLoading"
|
|
191
208
|
/>
|
|
192
|
-
<crud-error-display :errors="uploadErrors"
|
|
209
|
+
<crud-error-display :errors="uploadErrors" />
|
|
193
210
|
</div>
|
|
194
|
-
<v-btn
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
211
|
+
<v-btn
|
|
212
|
+
:loading="uploadsLoading"
|
|
213
|
+
class="ml-2"
|
|
214
|
+
@click="processUploads"
|
|
215
|
+
color="primary"
|
|
216
|
+
:disabled="(multiple && (!filesToUpload || filesToUpload.length === 0)) || (!multiple && !fileToUpload)"
|
|
217
|
+
>
|
|
199
218
|
<v-icon small class="mr-1">mdi-upload</v-icon>
|
|
200
219
|
Upload
|
|
201
220
|
</v-btn>
|
|
@@ -204,12 +223,16 @@ watch(() => fileToUpload.value, () => {
|
|
|
204
223
|
<v-text-field
|
|
205
224
|
v-model="searchValue"
|
|
206
225
|
label="Search by file name"
|
|
207
|
-
:disabled="uploadsLoading"
|
|
226
|
+
:disabled="uploadsLoading"
|
|
227
|
+
/>
|
|
208
228
|
</div>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
229
|
+
<crud-list-loader
|
|
230
|
+
v-if="tempModel && (Array.isArray(tempModel) ? tempModel.length : tempModel)"
|
|
231
|
+
:per-page="1000"
|
|
232
|
+
:disable-no-results="true"
|
|
233
|
+
:custom-filters="{ ids: multiple ? tempModel : [tempModel] }"
|
|
234
|
+
:path="path"
|
|
235
|
+
>
|
|
213
236
|
<template #default="uploadSlot">
|
|
214
237
|
<div class="pa-3 border rounded mb-3 bg-white">
|
|
215
238
|
<h4 class="mb-2">Selected media:</h4>
|
|
@@ -219,56 +242,65 @@ watch(() => fileToUpload.value, () => {
|
|
|
219
242
|
:file-name-key="fileNameKey"
|
|
220
243
|
@click="onSelectImage(item.id)"
|
|
221
244
|
:item="item"
|
|
222
|
-
:selected="
|
|
223
|
-
class="col-6"
|
|
224
|
-
|
|
245
|
+
:selected="multiple ? tempModel.includes(item.id) : tempModel === item.id"
|
|
246
|
+
class="col-6"
|
|
247
|
+
/>
|
|
225
248
|
</div>
|
|
226
249
|
</div>
|
|
227
250
|
</template>
|
|
228
251
|
</crud-list-loader>
|
|
229
252
|
|
|
230
253
|
<div class="border pa-3 rounded overflow-scroll flex-fill">
|
|
231
|
-
<crud-list-loader
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
254
|
+
<crud-list-loader
|
|
255
|
+
:custom-filters="{ keywords: searchValue, ...customFilters }"
|
|
256
|
+
:debounced="true"
|
|
257
|
+
:per-page="66"
|
|
258
|
+
:page="uploadsPage"
|
|
259
|
+
:path="path"
|
|
260
|
+
>
|
|
236
261
|
<template #empty>
|
|
237
|
-
<v-alert>
|
|
238
|
-
No media for filter, upload new instead
|
|
239
|
-
</v-alert>
|
|
262
|
+
<v-alert>No media for filter, upload new instead</v-alert>
|
|
240
263
|
</template>
|
|
241
264
|
|
|
242
|
-
<template #default="{items,currentPage,totalPages}">
|
|
243
|
-
<div class="d-flex align-between flex-wrap
|
|
244
|
-
<div
|
|
245
|
-
|
|
265
|
+
<template #default="{ items, currentPage, totalPages }">
|
|
266
|
+
<div class="d-flex align-between flex-wrap" style="gap: 8px; overflow-x: hidden;">
|
|
267
|
+
<div
|
|
268
|
+
class="d-inline-flex border align-center rounded bg-white"
|
|
269
|
+
style="max-width: 250px; flex: 0 0 auto;"
|
|
270
|
+
v-for="item in items"
|
|
271
|
+
:key="'selection-'+item.id"
|
|
272
|
+
>
|
|
246
273
|
<crud-upload-field-selection
|
|
274
|
+
v-model="tempModel"
|
|
247
275
|
:hide-title="true"
|
|
248
276
|
:file-name-key="fileNameKey"
|
|
249
277
|
:mime-key="mimeKey"
|
|
250
278
|
class="flex-fill"
|
|
251
279
|
@click="onSelectImage(item.id)"
|
|
252
280
|
:item="item"
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
</crud-upload-field-selection>
|
|
281
|
+
:selected="multiple ? tempModel.includes(item.id) : tempModel === item.id"
|
|
282
|
+
/>
|
|
256
283
|
</div>
|
|
257
284
|
<v-col cols="12">
|
|
258
|
-
<v-pagination :length="totalPages" v-model="uploadsPage"/>
|
|
285
|
+
<v-pagination :length="totalPages" v-model="uploadsPage" />
|
|
259
286
|
</v-col>
|
|
260
287
|
</div>
|
|
261
288
|
</template>
|
|
262
289
|
</crud-list-loader>
|
|
263
|
-
|
|
264
290
|
</div>
|
|
265
291
|
</div>
|
|
292
|
+
|
|
266
293
|
<div class="border-t pa-4">
|
|
267
|
-
<v-btn
|
|
294
|
+
<v-btn
|
|
295
|
+
v-if="tempModel && (Array.isArray(tempModel) ? tempModel.length > 0 : true)"
|
|
296
|
+
:loading="uploadsLoading"
|
|
297
|
+
@click="finish"
|
|
298
|
+
color="success"
|
|
299
|
+
>
|
|
268
300
|
<v-icon small class="mr-1">mdi-content-save</v-icon>
|
|
269
301
|
Done
|
|
270
302
|
</v-btn>
|
|
271
|
-
<v-btn v-else @click="dialog = false" color=
|
|
303
|
+
<v-btn v-else @click="dialog = false" color="error">
|
|
272
304
|
<v-icon small class="mr-1">mdi-close</v-icon>
|
|
273
305
|
Cancel
|
|
274
306
|
</v-btn>
|
|
@@ -83,70 +83,81 @@ const containerClasses = computed(() => {
|
|
|
83
83
|
"pa-1": true,
|
|
84
84
|
"position-relative": true,
|
|
85
85
|
"cursor": true,
|
|
86
|
-
"d-flex": true
|
|
86
|
+
"d-flex": true,
|
|
87
|
+
"border": selected.value,
|
|
88
|
+
"border-primary": selected.value,
|
|
89
|
+
"shadow": selected.value
|
|
87
90
|
};
|
|
88
91
|
});
|
|
89
92
|
</script>
|
|
90
93
|
|
|
91
94
|
<template>
|
|
92
95
|
<div :class="containerClasses">
|
|
96
|
+
<div class="d-flex justify-center flex-fill align-center" v-bind="props">
|
|
97
|
+
<nuxt-img v-if="isImage"
|
|
98
|
+
@click="imageClickAction"
|
|
99
|
+
style="width:100px; height:100px; object-fit: cover;"
|
|
100
|
+
format="webp"
|
|
101
|
+
:src="url"
|
|
102
|
+
fit="cover"
|
|
103
|
+
:width="item.width ?? 100"
|
|
104
|
+
:height="item.height ?? 'auto'"
|
|
105
|
+
/>
|
|
106
|
+
<video v-else-if="isVideo"
|
|
107
|
+
@click="imageClickAction"
|
|
108
|
+
:src="url"
|
|
109
|
+
:width="50"
|
|
110
|
+
:height="50"
|
|
111
|
+
class="flex-shrink-1"></video>
|
|
112
|
+
<div v-else class="bg-white d-flex justify-center align-center" style="height: 100px; width: 100px;">
|
|
113
|
+
<v-icon :icon="mimeTypeToMdiIcon(item[mimeKey])" size="40" color="primary" class="m-auto"></v-icon>
|
|
114
|
+
</div>
|
|
115
|
+
<div v-if="!hideTitle"
|
|
116
|
+
style="font-size: 12px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-all;"
|
|
117
|
+
class="text-wrap ml-2">{{ item[fileNameKey] }}
|
|
118
|
+
</div>
|
|
119
|
+
<div class="ml-2 d-flex flex-column align-center">
|
|
120
|
+
<v-btn size="x-small" target="_blank" color="primary" :icon="true" :href="downloadUrl">
|
|
121
|
+
<v-icon icon="mdi-download"></v-icon>
|
|
122
|
+
</v-btn>
|
|
123
|
+
<slot name="additionalActions" :item="item">
|
|
124
|
+
</slot>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
</div>
|
|
93
128
|
<v-tooltip>
|
|
94
129
|
<template v-slot:activator="{ props }">
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
:width="item.width ?? 100"
|
|
103
|
-
:height="item.height ?? 'auto'"
|
|
104
|
-
/>
|
|
105
|
-
<video v-else-if="isVideo"
|
|
106
|
-
@click="imageClickAction"
|
|
107
|
-
:src="url"
|
|
108
|
-
:width="50"
|
|
109
|
-
:height="50"
|
|
110
|
-
class="flex-shrink-1"></video>
|
|
111
|
-
<div v-else class="bg-white d-flex justify-center align-center" style="height: 100px; width: 100px;">
|
|
112
|
-
<v-icon :icon="mimeTypeToMdiIcon(item[mimeKey])" size="40" color="primary" class="m-auto"></v-icon>
|
|
113
|
-
</div>
|
|
114
|
-
<div v-if="!hideTitle"
|
|
115
|
-
style="font-size: 12px; overflow-wrap: break-word; word-wrap: break-word; word-break: break-all;"
|
|
116
|
-
class="text-wrap ml-2">{{ item[fileNameKey] }}
|
|
117
|
-
</div>
|
|
118
|
-
<div class="ml-2 d-flex flex-column align-center">
|
|
119
|
-
<v-btn size="x-small" target="_blank" color="primary" :icon="true" :href="downloadUrl">
|
|
120
|
-
<v-icon icon="mdi-download"></v-icon>
|
|
121
|
-
</v-btn>
|
|
122
|
-
<slot name="additionalActions" :item="item">
|
|
123
|
-
</slot>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
</div>
|
|
130
|
+
<v-avatar
|
|
131
|
+
v-bind="props"
|
|
132
|
+
style="position: absolute; top: 5px; left: 5px;"
|
|
133
|
+
size="20"
|
|
134
|
+
color="black">
|
|
135
|
+
<v-icon size="10">mdi-magnify-plus</v-icon>
|
|
136
|
+
</v-avatar>
|
|
127
137
|
</template>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
</div>
|
|
138
|
+
<div>
|
|
139
|
+
<div class="d-flex flex-column justify-center text-wrap flex-shrink-1" style="font-size: 14px;">
|
|
140
|
+
<nuxt-img v-if="isImage"
|
|
141
|
+
style="width:600px; height:auto; max-width:100%;"
|
|
142
|
+
:src="largeUrl"
|
|
143
|
+
:width="item.width ?? 100"
|
|
144
|
+
:height="item.height ?? 'auto'"
|
|
145
|
+
/>
|
|
146
|
+
<div style="overflow-wrap: break-word; word-wrap: break-word; word-break: break-all;"
|
|
147
|
+
class="font-weight-bold text-wrap">{{ item[fileNameKey] }}
|
|
148
|
+
</div>
|
|
149
|
+
<div>
|
|
150
|
+
<small>{{ formatStringDate(item.createdAt, 'DD/MM/YYYY HH:mm', 'YYYY-MM-DD HH:mm:ss') }}</small>
|
|
142
151
|
</div>
|
|
143
152
|
</div>
|
|
153
|
+
</div>
|
|
144
154
|
</v-tooltip>
|
|
155
|
+
|
|
145
156
|
<v-avatar
|
|
146
157
|
style="position: absolute; top: 5px; right: 5px;"
|
|
147
158
|
size="20"
|
|
148
159
|
v-if="selected"
|
|
149
|
-
color="
|
|
160
|
+
color="accent">
|
|
150
161
|
<v-icon dark size="10">mdi-check</v-icon>
|
|
151
162
|
</v-avatar>
|
|
152
163
|
<v-avatar
|