mirror of
https://github.com/keven1024/015.git
synced 2026-05-26 07:08:02 +00:00
feat(front): add FileIcon component to display file previews and icons based on file type
This commit is contained in:
@@ -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>
|
||||
|
||||
55
front/components/FileIcon.vue
Normal file
55
front/components/FileIcon.vue
Normal 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>
|
||||
Reference in New Issue
Block a user