Files
FEDEO/frontend/components/AuthenticatedFilePreview.client.vue

85 lines
2.0 KiB
Vue

<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from "vue"
const props = defineProps<{
fileId: string
path?: string | null
}>()
const { $api } = useNuxtApp()
const objectUrl = ref<string | null>(null)
const loadFailed = ref(false)
const isPdf = computed(() => String(props.path || "").toLowerCase().endsWith(".pdf"))
const revokeObjectUrl = () => {
if (!objectUrl.value) return
URL.revokeObjectURL(objectUrl.value)
objectUrl.value = null
}
const loadFile = async () => {
revokeObjectUrl()
loadFailed.value = false
try {
const blob = await $api<Blob>(`/api/files/content/${encodeURIComponent(props.fileId)}`, {
responseType: "blob"
})
objectUrl.value = URL.createObjectURL(blob)
} catch (error) {
loadFailed.value = true
console.error("Dateivorschau konnte nicht geladen werden:", error)
}
}
watch(() => props.fileId, loadFile, { immediate: true })
onBeforeUnmount(revokeObjectUrl)
</script>
<template>
<div class="authenticated-file-preview">
<iframe
v-if="objectUrl && isPdf"
:src="`${objectUrl}#toolbar=0&navpanes=0&scrollbar=0`"
title="PDF-Vorschau"
loading="lazy"
/>
<img v-else-if="objectUrl" :src="objectUrl" alt="Dateivorschau" />
<div v-else-if="loadFailed" class="preview-placeholder">
<UIcon name="i-heroicons-document" class="h-10 w-10" />
<span>Keine Vorschau verfügbar</span>
</div>
<USkeleton v-else class="h-full min-h-32 w-full" />
</div>
</template>
<style scoped>
.authenticated-file-preview,
.authenticated-file-preview iframe,
.authenticated-file-preview img {
width: 100%;
height: 100%;
}
.authenticated-file-preview iframe {
border: 0;
pointer-events: none;
}
.authenticated-file-preview img {
object-fit: contain;
}
.preview-placeholder {
display: flex;
min-height: 8rem;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.5rem;
color: rgb(107 114 128);
font-size: 0.875rem;
}
</style>