makearmy-app/components/utilities/files/FilePreview.tsx

56 lines
1.9 KiB
TypeScript

// components/utilities/files/FilePreview.tsx
"use client";
import { useEffect, useState } from "react";
import { rawUrl, isPreviewableImage, isPreviewableText, isPreviewablePdf } from "./api";
export default function FilePreview({ path, mime, name }: { path: string; mime?: string | null; name?: string }) {
const [text, setText] = useState<string>("");
useEffect(() => {
let cancelled = false;
async function load() {
setText("");
if (isPreviewableText(mime, name)) {
try {
const res = await fetch(rawUrl(path), { cache: "no-store" });
const t = await res.text();
if (!cancelled) setText(t.slice(0, 100_000)); // safety cap
} catch {
if (!cancelled) setText("Unable to load text preview.");
}
}
}
load();
return () => { cancelled = true; };
}, [path, mime, name]);
if (isPreviewableImage(mime, name)) {
return (
<div className="rounded-md border overflow-hidden">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img src={rawUrl(path)} alt={name || ""} className="w-full max-h-[60vh] object-contain bg-muted" />
</div>
);
}
if (isPreviewablePdf(mime, name)) {
return (
<iframe
src={rawUrl(path)}
className="w-full h-[60vh] rounded-md border"
title={name || "PDF preview"}
/>
);
}
if (isPreviewableText(mime, name)) {
return (
<pre className="rounded-md border bg-muted/40 p-3 overflow-auto max-h-[60vh] text-xs whitespace-pre-wrap">
{text || "Loading…"}
</pre>
);
}
return <div className="text-sm text-zinc-400">No preview available.</div>;
}