135 lines
3.8 KiB
Vue
135 lines
3.8 KiB
Vue
<script setup>
|
|
import { ref, computed, watch } from "vue";
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from "@/Components/ui/dialog";
|
|
import { Button } from "@/Components/ui/button";
|
|
import { Badge } from "../ui/badge";
|
|
|
|
const props = defineProps({
|
|
show: { type: Boolean, default: false },
|
|
src: { type: String, default: "" },
|
|
title: { type: String, default: "Dokument" },
|
|
mimeType: { type: String, default: "" },
|
|
filename: { type: String, default: "" },
|
|
});
|
|
const emit = defineEmits(["close"]);
|
|
|
|
const textContent = ref("");
|
|
const loading = ref(false);
|
|
|
|
const fileExtension = computed(() => {
|
|
if (props.filename) {
|
|
return props.filename.split(".").pop()?.toLowerCase() || "";
|
|
}
|
|
return "";
|
|
});
|
|
|
|
const viewerType = computed(() => {
|
|
const ext = fileExtension.value;
|
|
const mime = props.mimeType.toLowerCase();
|
|
|
|
if (ext === "pdf" || mime === "application/pdf") return "pdf";
|
|
if (["jpg", "jpeg", "png", "gif", "webp"].includes(ext) || mime.startsWith("image/"))
|
|
return "image";
|
|
if (["txt", "csv", "xml"].includes(ext) || mime.startsWith("text/")) return "text";
|
|
|
|
return "unsupported";
|
|
});
|
|
|
|
const loadTextContent = async () => {
|
|
if (!props.src || viewerType.value !== "text") return;
|
|
loading.value = true;
|
|
try {
|
|
const response = await fetch(props.src);
|
|
textContent.value = await response.text();
|
|
} catch (e) {
|
|
textContent.value = "Napaka pri nalaganju vsebine.";
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => [props.show, props.src],
|
|
([show]) => {
|
|
if (show && viewerType.value === "text") {
|
|
loadTextContent();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<Dialog :open="show" @update:open="(open) => !open && $emit('close')">
|
|
<DialogContent class="max-w-full xl:max-w-7xl">
|
|
<DialogHeader>
|
|
<DialogTitle>
|
|
{{ title }}
|
|
</DialogTitle>
|
|
<DialogDescription>
|
|
<Badge>
|
|
{{ fileExtension }}
|
|
</Badge>
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div class="h-[70vh] overflow-auto">
|
|
<!-- PDF Viewer (browser native) -->
|
|
<template v-if="viewerType === 'pdf' && props.src">
|
|
<iframe
|
|
:src="props.src"
|
|
class="w-full h-full rounded border"
|
|
type="application/pdf"
|
|
/>
|
|
</template>
|
|
|
|
<!-- Image Viewer -->
|
|
<template v-else-if="viewerType === 'image' && props.src">
|
|
<img
|
|
:src="props.src"
|
|
:alt="props.title"
|
|
class="max-w-full max-h-full mx-auto object-contain"
|
|
/>
|
|
</template>
|
|
|
|
<!-- Text/CSV/XML Viewer -->
|
|
<template v-else-if="viewerType === 'text'">
|
|
<div v-if="loading" class="flex items-center justify-center h-full">
|
|
<div class="animate-pulse text-gray-500">Nalaganje...</div>
|
|
</div>
|
|
<pre
|
|
v-else
|
|
class="p-4 bg-gray-50 dark:bg-gray-900 rounded border text-sm overflow-auto h-full whitespace-pre-wrap wrap-break-word"
|
|
>{{ textContent }}</pre
|
|
>
|
|
</template>
|
|
|
|
<!-- Unsupported -->
|
|
<template v-else-if="viewerType === 'unsupported'">
|
|
<div
|
|
class="flex flex-col items-center justify-center h-full gap-4 text-gray-500"
|
|
>
|
|
<span>Predogled ni na voljo za to vrsto datoteke.</span>
|
|
<Button as="a" :href="props.src" target="_blank" variant="outline">
|
|
Prenesi datoteko
|
|
</Button>
|
|
</div>
|
|
</template>
|
|
|
|
<!-- No source -->
|
|
<div v-else class="text-sm text-gray-500">Ni dokumenta za prikaz.</div>
|
|
</div>
|
|
|
|
<div class="flex justify-end mt-4">
|
|
<Button type="button" variant="outline" @click="$emit('close')">Zapri</Button>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
</template>
|