From 8b9c878132f8414d92c2ca47f31f1123bd248cd8 Mon Sep 17 00:00:00 2001 From: OpenClaw Bot Date: Sun, 8 Mar 2026 10:35:29 +0100 Subject: [PATCH] fix: robust per-card PDF export to avoid blank pages --- public/index.html | 63 ++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 22 deletions(-) diff --git a/public/index.html b/public/index.html index da77eb6..7546621 100644 --- a/public/index.html +++ b/public/index.html @@ -73,6 +73,8 @@ body.modal-open { overflow: hidden; } + +
@@ -496,44 +498,61 @@ function closeAiModal(){ } async function downloadPdf(){ - if (!window.html2pdf) { + if (!window.html2canvas || !window.jspdf?.jsPDF) { alert('PDF-Export-Bibliothek nicht geladen.'); return; } const root = document.createElement('div'); root.style.position = 'fixed'; - root.style.left = '0'; + root.style.left = '-10000px'; root.style.top = '0'; - root.style.width = '210mm'; - root.style.minHeight = '297mm'; + root.style.width = '1200px'; root.style.background = '#fff'; - root.style.padding = '8mm'; - root.style.zIndex = '-1'; - root.style.opacity = '0.01'; - root.style.pointerEvents = 'none'; root.innerHTML = app.innerHTML; - root.querySelectorAll('.card-actions,.card-action-btn,button,[data-edit-all]').forEach(el => el.remove()); - root.querySelectorAll('.exercise-container').forEach(el => { el.style.pageBreakAfter = 'always'; }); root.querySelectorAll('.card-size').forEach(el => { el.style.boxShadow = 'none'; - el.style.margin = '0 auto 10mm auto'; + el.style.margin = '0 0 12px 0'; }); - document.body.appendChild(root); - const opt = { - margin: [5, 5, 5, 5], - filename: `coachingcards-${new Date().toISOString().slice(0,10)}.pdf`, - image: { type: 'jpeg', quality: 0.98 }, - html2canvas: { scale: 2, useCORS: true, backgroundColor: '#ffffff', logging: false }, - jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }, - pagebreak: { mode: ['css', 'legacy'] } - }; - try { - await window.html2pdf().set(opt).from(root).save(); + const cards = [...root.querySelectorAll('.card-size')]; + if (!cards.length) { + alert('Keine Karten für den Export sichtbar.'); + return; + } + + const { jsPDF } = window.jspdf; + const pdf = new jsPDF({ orientation: 'portrait', unit: 'mm', format: 'a4' }); + const pageW = pdf.internal.pageSize.getWidth(); + const pageH = pdf.internal.pageSize.getHeight(); + const margin = 8; + const usableW = pageW - margin * 2; + const usableH = pageH - margin * 2; + + for (let i = 0; i < cards.length; i++) { + const canvas = await window.html2canvas(cards[i], { + scale: 2, + useCORS: true, + backgroundColor: '#ffffff', + logging: false + }); + const img = canvas.toDataURL('image/jpeg', 0.98); + const imgW = canvas.width; + const imgH = canvas.height; + const ratio = Math.min(usableW / imgW, usableH / imgH); + const drawW = imgW * ratio; + const drawH = imgH * ratio; + const x = margin + (usableW - drawW) / 2; + const y = margin + (usableH - drawH) / 2; + + if (i > 0) pdf.addPage(); + pdf.addImage(img, 'JPEG', x, y, drawW, drawH, undefined, 'FAST'); + } + + pdf.save(`coachingcards-${new Date().toISOString().slice(0,10)}.pdf`); } finally { root.remove(); }