Skip to content

Commit ec07489

Browse files
committed
fix: generate thumbnails of file model
1 parent c07cabb commit ec07489

File tree

3 files changed

+36
-26
lines changed

3 files changed

+36
-26
lines changed

packages/common-helpers/src/files.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ export const fileMatchesMimeTypes = (file: File, mimeTypes: iMime[]) => {
108108
* Create base64 image string from image file
109109
*/
110110
export const getBase64FromImageFile = (file: File) => {
111-
//build base64 image string
111+
// build base64 image string
112112
const reader = new FileReader();
113113

114114
return new Promise<string>((resolve) => {

packages/components-vue/src/components/form/Simple.vue

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
/**
9090
* Make model
9191
*/
92-
make?: (...args: P) => tFormInput[];
92+
make?: (...args: P) => tFormInput[] | Promise<tFormInput[]>;
9393
/** Make all inputs read only by disabling them */
9494
readonly?: boolean;
9595
}
@@ -103,7 +103,10 @@
103103
defineOptions({ name: "FormSimple", inheritAttrs: true });
104104
105105
const props = defineProps<iFormSimple<P>>();
106-
const emit = defineEmits(["update:invalid", "update:model-value"]);
106+
const emit = defineEmits<{
107+
"update:invalid": [iInvalidInput[]];
108+
"update:model-value": [tFormInput[]];
109+
}>();
107110
108111
const { t, tet } = useHelpers(useI18n);
109112
const { defaultCountry, getCountries, getCountryStates } = useCountries();
@@ -141,7 +144,10 @@
141144
142145
// update values
143146
model.value[index].values = values;
144-
emit("update:model-value", props.modelValue?.toSpliced(index, 1, model.value[index]));
147+
emit(
148+
"update:model-value",
149+
(props.modelValue || []).toSpliced(index, 1, model.value[index])
150+
);
145151
146152
if (!props.invalid?.length) return;
147153
@@ -218,11 +224,11 @@
218224
// lifecycle
219225
watch(
220226
() => props.payload,
221-
(newPayload, oldPayload) => {
227+
async (newPayload, oldPayload) => {
222228
if (!props.make || (firstMake.value && isEqual(newPayload, oldPayload))) return;
223229
224230
firstMake.value = true;
225-
emit("update:model-value", props.make(...(<P>(newPayload || []))));
231+
emit("update:model-value", await props.make(...(<P>(newPayload || []))));
226232
},
227233
{ immediate: true }
228234
);

packages/components-vue/src/components/input/File.vue

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44
button
55
v-bind="{ ...props, theme: fileInputTheme.themeValues }"
66
>
7-
<div
8-
v-if="minAmount !== maxAmount && thumbnails.length"
9-
class="flx --flxRow --flx-start-center --gap-10"
10-
>
7+
<div v-if="thumbnails.length" class="flx --flxRow --flx-start-center --gap-10">
118
<ul class="flx --flxRow-wrap --flx-start-center --gap-10">
129
<li
1310
v-for="(thumb, thumb_index) in thumbnails"
@@ -18,7 +15,7 @@
1815
class="avatar --index --bdr flx --flx-center"
1916
:tooltip="t('file_delete_files', 1)"
2017
tooltip-position="bottom"
21-
@click.prevent="removeFile(thumb_index)"
18+
@click.prevent="(e: Event) => removeFile(thumb_index, e)"
2219
>
2320
<div class="back">
2421
<BaseImg :src="thumb" :alt="t('file_thumb')" />
@@ -123,7 +120,7 @@
123120
</template>
124121

125122
<script setup lang="ts">
126-
import { ref, computed } from "vue";
123+
import { ref, computed, watch } from "vue";
127124
import debounce from "lodash-es/debounce";
128125
import omit from "lodash-es/omit";
129126
@@ -216,16 +213,14 @@
216213
const isAdvancedUpload = ref(false);
217214
const isLoading = ref(false);
218215
const isDragover = ref(false);
219-
const minAmount = computed(() => props.min ?? 1);
220216
const maxAmount = computed(() => props.max ?? 100);
221217
const maxFileSize = computed(() => props.maxSize ?? 1e7);
222218
223219
/**
224220
* setFiles
225221
*/
226-
function setFiles(files: File[] = [], thumbs: string[] = []) {
227-
thumbnails.value = thumbs;
228-
emit("update:model-value", files);
222+
function setFiles(files: File[] = [], event?: Event) {
223+
if (event) emit("update:model-value", files);
229224
}
230225
/**
231226
* check support for drag and drop
@@ -242,13 +237,12 @@
242237
/**
243238
* stores the files
244239
*/
245-
async function storeFiles(files: FileList, target: Event) {
240+
async function storeFiles(files: FileList | File[], event?: Event) {
246241
isLoading.value = true;
247242
248243
// copy the files
249244
const filesArr = Array.from(files); // FileList is unstable
250245
const savedFiles = [...props.modelValue].filter((v) => v instanceof File);
251-
const savedThumbs = [...thumbnails.value];
252246
253247
try {
254248
for (let i = 0; i < filesArr.length; i++) {
@@ -261,7 +255,7 @@
261255
amount: maxAmount.value,
262256
}),
263257
icon: "warning",
264-
target,
258+
target: event,
265259
});
266260
267261
break;
@@ -278,29 +272,28 @@
278272
title: t("swal.file_wrong_format_image"),
279273
text: t("swal.file_wrong_format_image_text"),
280274
icon: "warning",
281-
target,
275+
target: event,
282276
});
283277
} else {
284278
// is image file
285279
if (filesArr[i].size < maxFileSize.value) {
286280
const fileName = `${props.filePrefix ?? "image"}_${i}`;
287281
288282
savedFiles.push(renameFile(filesArr[i], fileName));
289-
savedThumbs.push(await getBase64FromImageFile(filesArr[i]));
290283
} else {
291284
// file too big
292285
Swal.fire({
293286
title: t("swal.file_too_big"),
294287
text: t("swal.file_too_big_text"),
295288
icon: "warning",
296-
target,
289+
target: event,
297290
});
298291
}
299292
}
300293
}
301294
302295
// last one, save all.
303-
setFiles(savedFiles, savedThumbs);
296+
setFiles(savedFiles, event);
304297
} catch (err) {
305298
logger("InputFile:storeFiles", err);
306299
Swal.fire({
@@ -309,7 +302,7 @@
309302
icon: "error",
310303
timer: undefined,
311304
showConfirmButton: true,
312-
target,
305+
target: event,
313306
});
314307
}
315308
@@ -319,9 +312,9 @@
319312
/**
320313
* remove the given file in the given key
321314
*/
322-
const removeFile = debounce((index: number) => {
315+
const removeFile = debounce((index: number, event?: Event) => {
323316
// modify and set again
324-
setFiles(props.modelValue.toSpliced(index, 1), thumbnails.value.toSpliced(index, 1));
317+
setFiles(props.modelValue.toSpliced(index, 1), event);
325318
});
326319
327320
/**
@@ -381,4 +374,15 @@
381374
382375
// lifecycle
383376
if (isBrowser) isAdvancedUpload.value = checkAdvancedUploadSupport();
377+
378+
watch(
379+
() => props.modelValue,
380+
async (newFiles) => {
381+
// TODO: optimize thumbnails generation for larger filesets
382+
thumbnails.value = await Promise.all(
383+
newFiles.map((file) => getBase64FromImageFile(file))
384+
);
385+
},
386+
{ immediate: true }
387+
);
384388
</script>

0 commit comments

Comments
 (0)