Files
Inventory/app/components/DocumentThumbnail.vue

103 lines
2.5 KiB
Vue

<template>
<div
v-if="document"
class="flex items-center justify-center overflow-hidden rounded-md border border-base-200 bg-base-200/70"
:class="thumbnailClass"
>
<img
v-if="canRenderImage"
:src="previewSrc"
class="h-full w-full object-cover"
:alt="altText"
loading="lazy"
decoding="async"
>
<component
v-else
:is="icon.component"
class="h-6 w-6"
:class="icon.colorClass"
aria-hidden="true"
/>
</div>
<div
v-else
class="flex h-16 w-16 items-center justify-center rounded-md border border-dashed border-base-200 bg-base-200/40 text-xs text-base-content/40"
aria-hidden="true"
>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { getFileIcon } from '~/utils/fileIcons';
import { isImageDocument, isPdfDocument } from '~/utils/documentPreview';
type GenericDocument = {
id?: string | number;
name?: string | null;
filename?: string | null;
mimeType?: string | null;
path?: string | null;
size?: number | null;
};
const props = defineProps<{
document: GenericDocument | null | undefined;
alt?: string;
}>();
const normalizedDocument = computed(() => props.document ?? null);
const canRenderImage = computed(() => {
const doc = normalizedDocument.value;
return !!(doc && isImageDocument(doc) && doc.path);
});
const canRenderPdf = computed(() => {
// Rendering many PDF iframes in a list is very heavy for the browser.
// We intentionally disable inline PDF previews and fall back to an icon.
return false;
});
const appendPdfViewerParams = (src: string) => {
if (!src || src.startsWith('data:')) {
return src;
}
if (src.includes('#')) {
return `${src}&toolbar=0&navpanes=0`;
}
return `${src}#toolbar=0&navpanes=0`;
};
const previewSrc = computed(() => {
const doc = normalizedDocument.value;
if (!doc || !doc.path) {
return '';
}
if (isPdfDocument(doc)) {
return appendPdfViewerParams(doc.path);
}
return doc.path;
});
const thumbnailClass = computed(() => (canRenderImage.value || canRenderPdf.value ? 'h-20 w-16' : 'h-16 w-16'));
const icon = computed(() => {
const doc = normalizedDocument.value;
return getFileIcon({
name: doc?.filename || doc?.name || '',
mime: doc?.mimeType || undefined,
});
});
const altText = computed(() => {
if (props.alt) {
return props.alt;
}
const doc = normalizedDocument.value;
return doc?.name ? `Aperçu de ${doc.name}` : 'Aperçu du document';
});
</script>