/* global React */ // ============================================================ // PDF export — clones the live, already-paginated preview sheets // into a print root and opens the browser's print dialog set to // true Letter size. The result is pixel-identical to the preview. // ============================================================ const { useState: useStatePR, useEffect: useEffectPR, useRef: useRefPR } = React; // Collect the rendered page nodes from a preview container, in order. function gatherPages(node) { if (!node) return []; const pages = []; node.querySelectorAll(".pg-sheet").forEach((s) => pages.push(s)); // résumé pages node.querySelectorAll(".cover").forEach((c) => pages.push(c)); // appended cover letter if (!pages.length) node.querySelectorAll(".paper").forEach((p) => pages.push(p)); // fallback return pages; } // Build (or rebuild) the hidden print root from cloned page nodes. function buildPrintRoot(pages) { const old = document.getElementById("print-root"); if (old) old.remove(); const root = document.createElement("div"); root.id = "print-root"; pages.forEach((p) => { const page = document.createElement("div"); page.className = "print-page"; const scale = document.createElement("div"); scale.className = "print-scale"; scale.appendChild(p.cloneNode(true)); page.appendChild(scale); root.appendChild(page); }); document.body.appendChild(root); return root; } function sanitizeFileName(name) { return (name || "resume").replace(/[\\/:*?"<>|]+/g, "").replace(/\s+/g, " ").trim() || "resume"; } // Run the print flow: clone → set title (drives the default PDF filename) → print → cleanup. function runPrint(getNode, fileName) { const node = typeof getNode === "function" ? getNode() : getNode; const pages = gatherPages(node); if (!pages.length) { window.alert("Nothing to export yet — add some content first."); return; } buildPrintRoot(pages); const prevTitle = document.title; document.title = sanitizeFileName(fileName); let done = false; const cleanup = () => { if (done) return; done = true; const r = document.getElementById("print-root"); if (r) r.remove(); document.title = prevTitle; window.removeEventListener("afterprint", cleanup); }; window.addEventListener("afterprint", cleanup); // fonts + layout settle, then print; afterprint (or the fallback) tidies up setTimeout(() => { window.print(); setTimeout(cleanup, 1500); }, 80); } // ---- Export modal ---------------------------------------------------------- function ExportModal({ defaultName, kind, getNode, onClose, reason, isPro }) { const [name, setName] = useStatePR(defaultName || "resume"); const [count, setCount] = useStatePR(0); const inputRef = useRefPR(null); useEffectPR(() => { const node = typeof getNode === "function" ? getNode() : getNode; setCount(gatherPages(node).length || 1); const t = setTimeout(() => { if (inputRef.current) { inputRef.current.focus(); inputRef.current.select(); } }, 60); const onKey = (e) => { if (e.key === "Escape") onClose(); }; document.addEventListener("keydown", onKey); return () => { clearTimeout(t); document.removeEventListener("keydown", onKey); }; }, []); const go = () => { onClose(); setTimeout(() => runPrint(getNode, name), 30); }; return (
Print-ready, exactly as you see it.