e4dcfc49aa
Tests / Import Check (Python 3.13) (push) Has been cancelled
Tests / Import Check (Python 3.14) (push) Has been cancelled
Tests / Python Tests (Python 3.11) (push) Has been cancelled
Tests / Python Tests (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.14) (push) Has been cancelled
Tests / Test Summary (push) Has been cancelled
Tests / Lint and Format (push) Has been cancelled
Tests / Web Node Tests (push) Has been cancelled
Tests / Import Check (Python 3.11) (push) Has been cancelled
Tests / Import Check (Python 3.12) (push) Has been cancelled
Tests / Python Tests (Python 3.13) (push) Has been cancelled
45 lines
1.4 KiB
TypeScript
45 lines
1.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import { Loader2 } from "lucide-react";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { FilePreviewSource } from "../previewerFor";
|
|
|
|
/**
|
|
* PDF preview powered by the browser's built-in viewer (PDF.js in Chrome /
|
|
* Firefox, Preview in Safari). Loads the original file from /api/attachments
|
|
* via an <iframe> — zero extra bundle weight.
|
|
*
|
|
* The "load" event sometimes fires twice in WebKit because of the inline
|
|
* UA toolbar; we only flip the loading flag on the first one.
|
|
*/
|
|
export default function PdfPreview({
|
|
url,
|
|
filename,
|
|
}: {
|
|
url: string;
|
|
filename: FilePreviewSource["filename"];
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
return (
|
|
<div className="relative h-full w-full bg-[var(--muted)]/30">
|
|
{loading && (
|
|
<div className="pointer-events-none absolute inset-0 z-10 flex items-center justify-center">
|
|
<div className="flex items-center gap-2 text-[12px] text-[var(--muted-foreground)]">
|
|
<Loader2 size={14} className="animate-spin" />
|
|
<span>{t("Loading preview…")}</span>
|
|
</div>
|
|
</div>
|
|
)}
|
|
<iframe
|
|
title={filename}
|
|
src={url}
|
|
className="h-full w-full border-0 bg-[var(--background)]"
|
|
onLoad={() => setLoading(false)}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|