feat(front): add FileIcon component to display file previews and icons based on file type

This commit is contained in:
keven1024
2025-04-20 21:36:10 +08:00
parent a45eed2fbb
commit df38398851
2 changed files with 57 additions and 22 deletions

View File

@@ -12,24 +12,11 @@ watch(value, (v) => {
console.log('value', v)
})
const imageUrl = computed(() => {
if (value?.value?.type?.startsWith('image/')) {
return URL.createObjectURL(value?.value)
}
return null
})
const fileInfo = computed(() => {
const [,name, ext] = value?.value?.name?.match(/^(.+)\.(.+)$/) || []
const [, name, ext] = value?.value?.name?.match(/^(.+)\.(.+)$/) || []
return { name, ext }
})
onUnmounted(() => {
if (imageUrl.value) {
URL.revokeObjectURL(imageUrl.value)
}
})
</script>
<template>
@@ -40,14 +27,7 @@ onUnmounted(() => {
isOverDropZone && '!bg-green-100/50 '
)">
<template v-if="!!value">
<div v-if="!!imageUrl" class="flex max-w-30 max-h-20">
<div class="object-contain m-auto h-full">
<img :src="imageUrl" class="w-full h-full border border-black/20 rounded" />
</div>
</div>
<div v-if="!imageUrl" class="size-16 flex justify-center items-center rounded-xl bg-white/80">
<LucideFile class="size-10" />
</div>
<FileIcon :file="value" />
<div class="flex flex-col gap-0.5 items-center">
<div class="flex max-w-30 w-full">
<div class="truncate">{{ fileInfo?.name }}</div>

View File

@@ -0,0 +1,55 @@
<script setup lang="ts">
import { LucideFileAudio, LucideFileVideo, LucideFile, LucideFileCode, LucideFileArchive, LucideFileText } from 'lucide-vue-next'
const props = defineProps<{
file: File
}>()
const imageUrl = computed(() => {
if (props?.file?.type?.startsWith('image/')) {
return URL.createObjectURL(props?.file)
}
return null
})
onUnmounted(() => {
if (imageUrl.value) {
URL.revokeObjectURL(imageUrl.value)
}
})
const fileIcon = computed(() => {
const [baseType, type] = props?.file?.type?.split('/')
if (baseType === 'video') {
return LucideFileVideo
}
if (baseType === 'audio') {
return LucideFileAudio
}
if (baseType === 'text' || ["json", "ld+json", "html"]?.includes(type)) {
return LucideFileCode
}
if (['pdf', 'msword',
'vnd.openxmlformats-officedocument.wordprocessingml.document',
'vnd.ms-excel',
'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'vnd.ms-powerpoint',
'vnd.openxmlformats-officedocument.presentationml.presentation'].includes(type)) {
return LucideFileText
}
if (['zip', 'vnd.rar', 'x-tar', 'gz', 'bz2', 'x-7z-compressed'].includes(type)) {
return LucideFileArchive
}
return LucideFile
})
</script>
<template>
<div v-if="!!imageUrl" class="flex max-w-30 max-h-20">
<div class="object-contain m-auto h-full">
<img :src="imageUrl" class="w-full h-full border border-black/20 rounded" />
</div>
</div>
<div v-if="!imageUrl" class="size-16 flex justify-center items-center rounded-xl bg-white/80">
<component :is="fileIcon" class="size-10" />
</div>
</template>