import { lazy, Suspense, useEffect, useState } from "react"; import { get } from "../api"; import { useT } from "../i18n"; import { Spinner } from "./Activity"; const ModelViewer = lazy(() => import("./ModelViewer").then((m) => ({ default: m.ModelViewer }))); export type PreviewKind = "image" | "pdf" | "doc" | "audio" | "module" | "model"; const KINDS: [RegExp, PreviewKind][] = [ [/\.(png|jpe?g|gif|webp|bmp|svg)$/i, "image"], [/\.pdf$/i, "pdf"], [/\.(docx|pptx|xlsx|xlsm|xls|ods)$/i, "doc"], [/\.(wav|mp3|ogg|oga|flac|m4a)$/i, "audio"], [/\.(xm|mod|s3m|it)$/i, "module"], [/\.(glb|gltf|stl|obj|step|stp|igs|iges)$/i, "model"], ]; export function previewKind(path: string): PreviewKind | undefined { return KINDS.find(([re]) => re.test(path))?.[1]; } const q = (p: string) => `path=${encodeURIComponent(p)}`; function PdfPreview({ path }: { path: string }) { const t = useT(); const [pages, setPages] = useState(); const [page, setPage] = useState(1); useEffect(() => { setPage(1); get<{ pages: number }>(`/files/preview/pdf-info?${q(path)}`).then((r) => setPages(r.pages)).catch(() => setPages(1)); }, [path]); return (
{t("preview.page", { n: page, total: pages ?? "…" })} {t("preview.openBrowser")}
{`page
); } interface DocData { kind: "text" | "table"; text?: string; sheets?: { name: string; rows: string[][]; total_rows: number }[]; } function DocPreview({ path }: { path: string }) { const t = useT(); const [data, setData] = useState(); const [error, setError] = useState(); const [sheet, setSheet] = useState(0); useEffect(() => { setData(undefined); setSheet(0); get(`/files/preview/doc?${q(path)}`).then(setData).catch((e) => setError(e.message)); }, [path]); if (error) return
{error}
; if (!data) return
; if (data.kind === "text") return
{data.text}
; const s = data.sheets?.[sheet]; return (
{data.sheets?.map((x, i) => ( ))}
{s && ( {s.rows.map((r, i) => ( {r.map((c, j) => ( ))} ))}
{i + 1}{c}
)} {s && s.total_rows > s.rows.length &&
{t("preview.moreRows", { n: s.total_rows - s.rows.length })}
}
); } export function FilePreview({ path, kind }: { path: string; kind: PreviewKind }) { const t = useT(); const raw = `/api/files/raw?${q(path)}`; switch (kind) { case "image": return (
); case "pdf": return ; case "doc": return ; case "audio": return (
); case "module": return (
{t("preview.moduleHint")}
); case "model": { const ext = path.split(".").pop()!.toLowerCase(); return ( }> ); } } }