feat(documents): add inbox document preview modal

This commit is contained in:
2026-10-01 17:54:04 +02:00
parent f359bfb579
commit 07adca417e
2 changed files with 71 additions and 17 deletions

View File

@@ -1,9 +1,10 @@
<script setup lang="ts">
import { onBeforeUnmount, ref, watch } from "vue"
import { ref, watch } from "vue"
const props = defineProps<{
fileId: string
path?: string | null
interactive?: boolean
}>()
const { $api } = useNuxtApp()
@@ -18,39 +19,47 @@ const revokeObjectUrl = () => {
objectUrl.value = null
}
const loadFile = async () => {
watch(() => props.fileId, async (fileId, _previous, onCleanup) => {
revokeObjectUrl()
loadFailed.value = false
let active = true
const controller = new AbortController()
onCleanup(() => {
active = false
controller.abort()
revokeObjectUrl()
})
try {
const blob = await $api<Blob>(`/api/files/content/${encodeURIComponent(props.fileId)}`, {
responseType: "blob"
const blob = await $api<Blob>(`/api/files/content/${encodeURIComponent(fileId)}`, {
responseType: "blob",
signal: controller.signal,
})
if (!active) return
objectUrl.value = URL.createObjectURL(blob)
} catch (error) {
if (!active) return
loadFailed.value = true
console.error("Dateivorschau konnte nicht geladen werden:", error)
}
}
watch(() => props.fileId, loadFile, { immediate: true })
onBeforeUnmount(revokeObjectUrl)
}, { immediate: true })
</script>
<template>
<div class="authenticated-file-preview">
<div class="authenticated-file-preview" :class="{ 'is-interactive': interactive }">
<iframe
v-if="objectUrl && isPdf"
:src="`${objectUrl}#toolbar=0&navpanes=0&scrollbar=0`"
v-if="objectUrl && isPdf && !loadFailed"
:src="interactive ? objectUrl : `${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">
<img v-else-if="objectUrl && !loadFailed" :src="objectUrl" alt="Dateivorschau" @error="loadFailed = true" />
<div v-else-if="loadFailed" class="preview-placeholder" role="status">
<UIcon name="i-heroicons-document" class="h-10 w-10" />
<span>Keine Vorschau verfügbar</span>
<span v-if="interactive">Du kannst das Dokument herunterladen oder in einem neuen Tab öffnen.</span>
</div>
<USkeleton v-else class="h-full min-h-32 w-full" />
<USkeleton v-else class="h-full min-h-32 w-full" aria-label="Dokumentvorschau wird geladen" />
</div>
</template>
@@ -67,6 +76,10 @@ onBeforeUnmount(revokeObjectUrl)
pointer-events: none;
}
.authenticated-file-preview.is-interactive iframe {
pointer-events: auto;
}
.authenticated-file-preview img {
object-fit: contain;
}
@@ -80,5 +93,8 @@ onBeforeUnmount(revokeObjectUrl)
gap: 0.5rem;
color: rgb(107 114 128);
font-size: 0.875rem;
height: 100%;
padding: 1rem;
text-align: center;
}
</style>