From e424008d5699daefae59a0fdc38d337abae496ac Mon Sep 17 00:00:00 2001 From: PJ Date: Sat, 20 Jun 2026 13:02:30 -0400 Subject: [PATCH] feat(export): PDF and EPUB export with save dialog --- src/export/exporters.ts | 19 +++++++++++++++++++ src/project.ts | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/export/exporters.ts diff --git a/src/export/exporters.ts b/src/export/exporters.ts new file mode 100644 index 0000000..4e78c69 --- /dev/null +++ b/src/export/exporters.ts @@ -0,0 +1,19 @@ +import type { Book } from "../model/book"; +import { bookToPdfInputs } from "./typst"; +import { buildEpub } from "./epub"; +import { compilePdf } from "../ipc"; +import { saveBytes } from "../project"; + +const PDF = [{ name: "PDF", extensions: ["pdf"] }]; +const EPUB = [{ name: "EPUB", extensions: ["epub"] }]; + +export async function exportPdf(book: Book): Promise { + const { source, images } = bookToPdfInputs(book); + const bytes = await compilePdf(source, images); + await saveBytes(bytes, `${book.metadata.title || "Untitled"}.pdf`, PDF); +} + +export async function exportEpub(book: Book): Promise { + const bytes = await buildEpub(book); + await saveBytes(bytes, `${book.metadata.title || "Untitled"}.epub`, EPUB); +} diff --git a/src/project.ts b/src/project.ts index 54c8353..83bd76f 100644 --- a/src/project.ts +++ b/src/project.ts @@ -18,3 +18,22 @@ export async function openBook(): Promise<{ book: Book; path: string } | null> { const contents = await invoke("read_file", { path: selected }); return { book: JSON.parse(contents) as Book, path: selected }; } + +function toBase64(bytes: Uint8Array): string { + let binary = ""; + const chunk = 0x8000; + for (let i = 0; i < bytes.length; i += chunk) { + binary += String.fromCharCode(...bytes.subarray(i, i + chunk)); + } + return btoa(binary); +} + +export async function saveBytes( + bytes: Uint8Array, + defaultName: string, + filters: { name: string; extensions: string[] }[] +): Promise { + const path = await save({ filters, defaultPath: defaultName }); + if (!path) return; + await invoke("write_bytes", { path, data: toBase64(bytes) }); +}