119 lines
5.4 KiB
Vue
119 lines
5.4 KiB
Vue
<script setup>
|
|
import { computed, ref } from 'vue';
|
|
import FileUpload from 'primevue/fileupload';
|
|
import { formatFileSize } from '../../../utils/fileUtils';
|
|
import { convertEnglishToPersian } from '../../../utils/numberUtils';
|
|
|
|
const files = defineModel({ type: Array, default: () => [] });
|
|
|
|
defineProps({
|
|
title: {
|
|
type: String,
|
|
required: true
|
|
}
|
|
});
|
|
|
|
const MAX_FILE_SIZE = 10485760;
|
|
|
|
const fileUpload = ref(null);
|
|
const dragging = ref(false);
|
|
|
|
const totalSize = computed(() => files.value.reduce((sum, file) => sum + file.size, 0));
|
|
|
|
const openFileDialog = () => {
|
|
fileUpload.value.choose();
|
|
};
|
|
|
|
const onSelectedFiles = (event) => {
|
|
files.value = event.files;
|
|
};
|
|
|
|
const onRemoveFile = (removeFileCallback, index) => {
|
|
removeFileCallback(index);
|
|
files.value = fileUpload.value.files;
|
|
};
|
|
|
|
const onClearFiles = (clearCallback) => {
|
|
clearCallback();
|
|
files.value = [];
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
class="ui-file-upload"
|
|
:class="{ 'ui-file-upload--dragging': dragging, 'ui-file-upload--filled': files.length }"
|
|
@dragover="dragging = true"
|
|
@dragleave="dragging = false"
|
|
@drop="dragging = false"
|
|
>
|
|
<FileUpload
|
|
ref="fileUpload"
|
|
name="files[]"
|
|
:customUpload="true"
|
|
:showUploadButton="false"
|
|
:showCancelButton="false"
|
|
:multiple="true"
|
|
accept="image/*"
|
|
:maxFileSize="MAX_FILE_SIZE"
|
|
@select="onSelectedFiles"
|
|
>
|
|
<template #content="{ files: selectedFiles, removeFileCallback, clearCallback }">
|
|
<div v-if="selectedFiles.length > 0" class="flex flex-col gap-3">
|
|
<ul class="grid grid-cols-[repeat(auto-fill,5rem)] gap-2">
|
|
<li
|
|
v-for="(file, index) of selectedFiles"
|
|
:key="file.name + file.type + file.size"
|
|
class="group relative aspect-square rounded-xl overflow-hidden border border-[#DEE3EB] bg-[#F8FAFC]"
|
|
>
|
|
<img role="presentation" :alt="file.name" :src="file.objectURL" class="w-full h-full object-cover" />
|
|
<div class="absolute inset-x-0 bottom-0 px-2 pb-1.5 pt-4 bg-gradient-to-t from-[#2F343D]/80 to-transparent text-white">
|
|
<p class="text-[10px] font-[600] truncate" dir="ltr">{{ file.name }}</p>
|
|
<p class="text-[9px] font-normal opacity-80" dir="ltr">{{ formatFileSize(file.size) }}</p>
|
|
</div>
|
|
<button
|
|
type="button"
|
|
class="absolute top-1.5 left-1.5 w-5 h-5 flex items-center justify-center rounded-full bg-white/90 text-[#7A1419] shadow-sm transition-opacity opacity-0 group-hover:opacity-100 focus:opacity-100"
|
|
:aria-label="`حذف ${file.name}`"
|
|
@click.stop="onRemoveFile(removeFileCallback, index)"
|
|
>
|
|
<i class="fi fi-rr-cross-small text-[12px] leading-none"></i>
|
|
</button>
|
|
</li>
|
|
<li>
|
|
<button
|
|
type="button"
|
|
class="w-full aspect-square rounded-xl border border-dashed border-[#C1D0E8] bg-white flex flex-col items-center justify-center gap-1 text-[#365891] transition-colors hover:border-[#365891] hover:bg-[#EEF2F8]"
|
|
@click="openFileDialog"
|
|
>
|
|
<i class="fi fi-rr-plus text-[16px] leading-none"></i>
|
|
<span class="text-[10px] font-[600]">افزودن</span>
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<div class="flex items-center justify-between gap-2 border-t border-[#EBEBEB] pt-2">
|
|
<p class="text-[11px] font-normal text-[#576989]">
|
|
{{ convertEnglishToPersian(String(selectedFiles.length)) }} فایل · <span dir="ltr">{{ formatFileSize(totalSize) }}</span>
|
|
</p>
|
|
<button type="button" class="text-[11px] font-[600] text-[#7A1419]" @click="onClearFiles(clearCallback)">حذف همه</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template #empty>
|
|
<button type="button" class="ui-file-upload-dropzone" @click="openFileDialog">
|
|
<span class="ui-file-upload-icon">
|
|
<i class="fi fi-rr-cloud-upload text-[20px] leading-none"></i>
|
|
</span>
|
|
<span class="text-[12px] font-[700] text-[#3E4C63]">{{ title }}</span>
|
|
<span class="text-[11px] font-normal text-[#576989] leading-5">
|
|
فایل را اینجا رها کنید یا برای انتخاب کلیک کنید
|
|
</span>
|
|
<span class="mt-1 text-[10px] font-normal text-[#576989] bg-white border border-[#DEE3EB] rounded-md px-2 py-0.5">
|
|
JPG، PNG · حداکثر {{ formatFileSize(MAX_FILE_SIZE) }}
|
|
</span>
|
|
</button>
|
|
</template>
|
|
</FileUpload>
|
|
</div>
|
|
</template>
|