mirror of
https://github.com/priyanshujain/margin.git
synced 2026-10-02 19:17:03 +00:00
feat(pdf): wire live Typst PDF dock with HTML fallback
This commit is contained in:
1 parent
29af847179
commit
6769570de3
1 file changed
+50
-2
+50
-2
@@ -1,7 +1,10 @@
|
|||||||
import { useMemo } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { generateHTML } from "@tiptap/core";
|
import { generateHTML } from "@tiptap/core";
|
||||||
import { useBook } from "../store/useBook";
|
import { useBook } from "../store/useBook";
|
||||||
import { editorExtensions } from "../editor/extensions";
|
import { editorExtensions } from "../editor/extensions";
|
||||||
|
import { bookToPdfInputs } from "../export/typst";
|
||||||
|
import { compilePdf } from "../ipc";
|
||||||
|
import { PdfPreview } from "./PdfPreview";
|
||||||
|
|
||||||
const TRIM_LABEL: Record<string, string> = {
|
const TRIM_LABEL: Record<string, string> = {
|
||||||
"6x9": "6 × 9 in",
|
"6x9": "6 × 9 in",
|
||||||
@@ -10,11 +13,56 @@ const TRIM_LABEL: Record<string, string> = {
|
|||||||
a5: "A5",
|
a5: "A5",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const inTauri = typeof window !== "undefined" && "__TAURI_INTERNALS__" in window;
|
||||||
|
|
||||||
export function Dock() {
|
export function Dock() {
|
||||||
|
return inTauri ? <PdfDock /> : <HtmlDock />;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PdfDock() {
|
||||||
|
const book = useBook((s) => s.book);
|
||||||
|
const [pdf, setPdf] = useState<Uint8Array | null>(null);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
const [busy, setBusy] = useState(false);
|
||||||
|
const timer = useRef<ReturnType<typeof setTimeout>>(undefined);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
clearTimeout(timer.current);
|
||||||
|
setBusy(true);
|
||||||
|
timer.current = setTimeout(() => {
|
||||||
|
const { source, images } = bookToPdfInputs(book);
|
||||||
|
compilePdf(source, images)
|
||||||
|
.then((bytes) => {
|
||||||
|
setPdf(bytes);
|
||||||
|
setError(null);
|
||||||
|
})
|
||||||
|
.catch((e) => setError(String(e)))
|
||||||
|
.finally(() => setBusy(false));
|
||||||
|
}, 350);
|
||||||
|
return () => clearTimeout(timer.current);
|
||||||
|
}, [book]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="dock">
|
||||||
|
<div className="dock-head">
|
||||||
|
<span className="label">Preview</span>
|
||||||
|
<span className="meta">{busy ? "updating…" : TRIM_LABEL[book.settings.trim]}</span>
|
||||||
|
</div>
|
||||||
|
{error ? (
|
||||||
|
<pre className="dock-error">{error}</pre>
|
||||||
|
) : pdf ? (
|
||||||
|
<PdfPreview data={pdf} />
|
||||||
|
) : (
|
||||||
|
<div className="dock-empty">Typesetting…</div>
|
||||||
|
)}
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function HtmlDock() {
|
||||||
const chapters = useBook((s) => s.book.chapters);
|
const chapters = useBook((s) => s.book.chapters);
|
||||||
const trim = useBook((s) => s.book.settings.trim);
|
const trim = useBook((s) => s.book.settings.trim);
|
||||||
const activeChapterId = useBook((s) => s.activeChapterId);
|
const activeChapterId = useBook((s) => s.activeChapterId);
|
||||||
|
|
||||||
const idx = chapters.findIndex((c) => c.id === activeChapterId);
|
const idx = chapters.findIndex((c) => c.id === activeChapterId);
|
||||||
const chapter = chapters[idx];
|
const chapter = chapters[idx];
|
||||||
const html = useMemo(() => generateHTML(chapter.content, editorExtensions), [chapter.content]);
|
const html = useMemo(() => generateHTML(chapter.content, editorExtensions), [chapter.content]);
|
||||||
|
|||||||
Reference in new issue
Block a user