diff --git a/bun.lockb b/bun.lockb
index 5bc1240..c2c51a9 100644
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/package.json b/package.json
index e513de4..4cfb6ee 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"@tiptap/pm": "^3.20.1",
"@tiptap/react": "^3.20.1",
"@tiptap/starter-kit": "^3.20.1",
+ "html2pdf.js": "^0.14.0",
"lucide-react": "^0.511.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
diff --git a/src/components/Toolbar.tsx b/src/components/Toolbar.tsx
index 65cbd22..ed5e9eb 100644
--- a/src/components/Toolbar.tsx
+++ b/src/components/Toolbar.tsx
@@ -22,10 +22,12 @@ import {
Link,
ImageIcon,
MinusIcon,
+ FileDown,
} from "lucide-react";
import ColorPicker from "./ColorPicker";
import LinkPopover from "./LinkPopover";
import ImagePopover from "./ImagePopover";
+import { exportToPdf } from "../utils/exportToPdf";
const FONT_FAMILIES = [
"Arial",
@@ -519,6 +521,16 @@ function Toolbar({ editor }: ToolbarProps) {
>
+
+
+
+ {/* Export to PDF */}
+ exportToPdf(editor)}
+ >
+
+
>
);
diff --git a/src/utils/exportToPdf.ts b/src/utils/exportToPdf.ts
new file mode 100644
index 0000000..c7eed8a
--- /dev/null
+++ b/src/utils/exportToPdf.ts
@@ -0,0 +1,68 @@
+import type { Editor } from "@tiptap/react";
+import html2pdf from "html2pdf.js";
+
+const EDITOR_STYLES = `
+ .pdf-export-container {
+ font-family: Arial, sans-serif;
+ font-size: 11pt;
+ line-height: 1.5;
+ color: #000;
+ }
+ .pdf-export-container ul {
+ list-style-type: disc;
+ padding-left: 1.5em;
+ margin: 0.5em 0;
+ }
+ .pdf-export-container ol {
+ list-style-type: decimal;
+ padding-left: 1.5em;
+ margin: 0.5em 0;
+ }
+ .pdf-export-container ul ul {
+ list-style-type: circle;
+ }
+ .pdf-export-container ul ul ul {
+ list-style-type: square;
+ }
+ .pdf-export-container li {
+ margin: 0.2em 0;
+ }
+ .pdf-export-container a {
+ color: #1a73e8;
+ text-decoration: underline;
+ }
+ .pdf-export-container img {
+ max-width: 100%;
+ height: auto;
+ }
+ .pdf-export-container hr {
+ border: none;
+ border-top: 1px solid #dadce0;
+ margin: 1em 0;
+ }
+`;
+
+export function exportToPdf(editor: Editor): void {
+ const editorHtml = editor.getHTML();
+
+ const wrapper = document.createElement("div");
+
+ const styleElement = document.createElement("style");
+ styleElement.textContent = EDITOR_STYLES;
+ wrapper.appendChild(styleElement);
+
+ const content = document.createElement("div");
+ content.className = "pdf-export-container";
+ content.innerHTML = editorHtml;
+ wrapper.appendChild(content);
+
+ const options = {
+ margin: [0.5, 1, 0.5, 1] as [number, number, number, number],
+ filename: "document.pdf",
+ image: { type: "jpeg" as const, quality: 0.98 },
+ html2canvas: { scale: 2, useCORS: true },
+ jsPDF: { unit: "in", format: "letter", orientation: "portrait" as const },
+ };
+
+ html2pdf().set(options).from(wrapper).save();
+}