add img preview + fix navbar
This commit is contained in:
@@ -37,12 +37,21 @@
|
||||
<ul v-if="selectedFiles.length" class="mt-4 w-full space-y-2 text-left">
|
||||
<li v-for="file in selectedFiles" :key="file.name" class="flex items-center justify-between text-sm">
|
||||
<div class="flex items-center gap-3">
|
||||
<component
|
||||
:is="getIcon(file).component"
|
||||
class="h-6 w-6"
|
||||
:class="getIcon(file).colorClass"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div class="h-14 w-14 flex-shrink-0 overflow-hidden rounded-md border border-base-300 bg-base-200/70 flex items-center justify-center">
|
||||
<img
|
||||
v-if="isImageFile(file)"
|
||||
:src="getFilePreview(file)"
|
||||
class="h-full w-full object-cover"
|
||||
:alt="`Aperçu de ${file.name}`"
|
||||
>
|
||||
<component
|
||||
v-else
|
||||
:is="getIcon(file).component"
|
||||
class="h-6 w-6"
|
||||
:class="getIcon(file).colorClass"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ file.name }}</span>
|
||||
<span class="text-xs text-gray-500">{{ formatSize(file.size) }} • {{ file.type || 'Type inconnu' }}</span>
|
||||
@@ -58,7 +67,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { ref, computed, watch, onBeforeUnmount } from 'vue'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
import { getFileIcon } from '~/utils/fileIcons'
|
||||
import IconLucideCloudUpload from '~icons/lucide/cloud-upload'
|
||||
@@ -96,6 +105,30 @@ const dragActive = ref(false)
|
||||
const fileInput = ref(null)
|
||||
const internalFiles = ref([])
|
||||
const { showError } = useToast()
|
||||
const previewUrls = new Map()
|
||||
|
||||
const isImageFile = (file) => (file?.type || '').startsWith('image/')
|
||||
|
||||
const getFilePreview = (file) => {
|
||||
if (!isImageFile(file)) { return null }
|
||||
if (!previewUrls.has(file)) {
|
||||
previewUrls.set(file, URL.createObjectURL(file))
|
||||
}
|
||||
return previewUrls.get(file)
|
||||
}
|
||||
|
||||
const cleanupRemovedPreviews = (previousFiles = [], nextFiles = []) => {
|
||||
const nextSet = new Set(nextFiles)
|
||||
previousFiles.forEach((file) => {
|
||||
if (!nextSet.has(file)) {
|
||||
const url = previewUrls.get(file)
|
||||
if (url) {
|
||||
URL.revokeObjectURL(url)
|
||||
previewUrls.delete(file)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const selectedFiles = computed(() => internalFiles.value)
|
||||
|
||||
@@ -103,6 +136,7 @@ watch(
|
||||
() => props.modelValue,
|
||||
(newValue) => {
|
||||
if (Array.isArray(newValue)) {
|
||||
cleanupRemovedPreviews(internalFiles.value, newValue)
|
||||
internalFiles.value = [...newValue]
|
||||
}
|
||||
},
|
||||
@@ -114,6 +148,7 @@ const triggerFileDialog = () => {
|
||||
}
|
||||
|
||||
const emitFiles = (files) => {
|
||||
cleanupRemovedPreviews(internalFiles.value, files)
|
||||
internalFiles.value = files
|
||||
emit('update:modelValue', files)
|
||||
emit('files-added', files)
|
||||
@@ -180,4 +215,11 @@ const formatSize = (size) => {
|
||||
const getIcon = (file) => {
|
||||
return getFileIcon({ name: file.name, mime: file.type })
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
previewUrls.forEach((url) => {
|
||||
URL.revokeObjectURL(url)
|
||||
})
|
||||
previewUrls.clear()
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user