Skip to content

Commit 336cf02

Browse files
jeremymanningclaude
andcommitted
Update PDF generation to use Tufte style matching original lab manual
- US Letter size format (215.9mm x 279.4mm) - 55% content width with wide right margin for Tufte-style layout - Times font (closest to ET Book in jsPDF) - Italic section heading "Checklist and signature page" - Checkbox symbols (☑ or ☐) based on web form state - Signature with underline and "Signature" label below - Date field with underline and "Date" label below - Centered page numbers in footer 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent c8b5c99 commit 336cf02

File tree

1 file changed

+90
-37
lines changed

1 file changed

+90
-37
lines changed

checklist.js

Lines changed: 90 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -536,66 +536,119 @@ function generateChecklistPDF(dateValue) {
536536

537537
function createPDF(dateValue) {
538538
var jsPDFLib = window.jspdf || { jsPDF: jsPDF };
539-
var doc = new jsPDFLib.jsPDF();
540-
541-
// Title
542-
doc.setFontSize(18);
543-
doc.setFont('helvetica', 'bold');
544-
doc.text('Lab Manual Checklist - Completed', 20, 20);
545-
546-
// Contextual Dynamics Lab header
547-
doc.setFontSize(12);
548-
doc.setFont('helvetica', 'normal');
549-
doc.text('Contextual Dynamics Lab, Dartmouth College', 20, 30);
550-
doc.text('Date: ' + dateValue, 20, 38);
539+
var doc = new jsPDFLib.jsPDF({
540+
unit: 'mm',
541+
format: 'letter' // US Letter size like the original PDF
542+
});
551543

552-
// Checklist items
544+
// Tufte-style layout constants
545+
// Page is 215.9mm x 279.4mm (letter)
546+
// Content area is ~55% of page width, leaving wide right margin
547+
var pageWidth = 215.9;
548+
var pageHeight = 279.4;
549+
var leftMargin = 25; // Left margin
550+
var contentWidth = 100; // ~55% of usable width for main content
551+
var topMargin = 25;
552+
var bottomMargin = 25;
553+
554+
// Use Times/Palatino-like font (closest to ET Book in jsPDF)
555+
var mainFont = 'times';
556+
557+
// Page 1: Checklist title and intro
558+
var yPos = topMargin;
559+
560+
// Section heading - Tufte style (italic, larger)
561+
doc.setFont(mainFont, 'italic');
562+
doc.setFontSize(14);
563+
doc.text('Checklist and signature page', leftMargin, yPos);
564+
yPos += 12;
565+
566+
// Intro paragraph
567+
doc.setFont(mainFont, 'normal');
553568
doc.setFontSize(11);
554-
var yPos = 50;
569+
var introText = 'By signing below, I certify that I have completed the following tasks:';
570+
doc.text(introText, leftMargin, yPos);
571+
yPos += 10;
572+
573+
// Checklist items with checkbox symbols
555574
var checkboxes = document.querySelectorAll('.interactive-checklist input[type="checkbox"]');
556575
var labels = document.querySelectorAll('.interactive-checklist label');
557576

558-
doc.setFont('helvetica', 'bold');
559-
doc.text('Completed Tasks:', 20, yPos);
560-
yPos += 8;
561-
562-
doc.setFont('helvetica', 'normal');
577+
doc.setFontSize(10);
563578
labels.forEach(function(label, index) {
579+
var isChecked = checkboxes[index] && checkboxes[index].checked;
580+
var checkSymbol = isChecked ? '\u2611' : '\u2610'; // ☑ or ☐
564581
var text = label.textContent.trim();
565-
// Wrap long text
566-
var lines = doc.splitTextToSize(String.fromCharCode(0x2713) + ' ' + text, 170);
582+
583+
// Wrap text to content width
584+
var wrappedLines = doc.splitTextToSize(text, contentWidth - 8);
567585

568586
// Check if we need a new page
569-
if (yPos + (lines.length * 6) > 270) {
587+
var itemHeight = wrappedLines.length * 4.5 + 3;
588+
if (yPos + itemHeight > pageHeight - bottomMargin) {
570589
doc.addPage();
571-
yPos = 20;
590+
yPos = topMargin;
572591
}
573592

574-
doc.text(lines, 20, yPos);
575-
yPos += lines.length * 6 + 2;
593+
// Draw checkbox symbol
594+
doc.setFont(mainFont, 'normal');
595+
doc.text(checkSymbol, leftMargin, yPos);
596+
597+
// Draw wrapped text with proper indentation
598+
wrappedLines.forEach(function(line, lineIndex) {
599+
doc.text(line, leftMargin + 6, yPos + (lineIndex * 4.5));
600+
});
601+
602+
yPos += itemHeight;
576603
});
577604

578605
// Signature section
579-
if (yPos > 200) {
606+
// Check if we need a new page for signature
607+
if (yPos + 60 > pageHeight - bottomMargin) {
580608
doc.addPage();
581-
yPos = 20;
609+
yPos = topMargin;
582610
}
583611

584-
yPos += 10;
585-
doc.setFont('helvetica', 'bold');
586-
doc.text('Signature:', 20, yPos);
587-
yPos += 5;
612+
yPos += 8;
613+
614+
// Signature line with label (Tufte style - simple, elegant)
615+
doc.setFont(mainFont, 'normal');
616+
doc.setFontSize(10);
588617

589-
// Add signature image
618+
// Add signature image if exists
590619
if (signatureCanvas) {
591620
var signatureData = signatureCanvas.toDataURL('image/png');
592-
doc.addImage(signatureData, 'PNG', 20, yPos, 80, 30);
593-
yPos += 35;
621+
// Position signature above the line
622+
doc.addImage(signatureData, 'PNG', leftMargin, yPos, 60, 22);
623+
yPos += 24;
594624
}
595625

596-
// Date line
597-
doc.setFont('helvetica', 'normal');
598-
doc.text('Date: ' + dateValue, 20, yPos);
626+
// Signature line
627+
doc.setDrawColor(0);
628+
doc.setLineWidth(0.3);
629+
doc.line(leftMargin, yPos, leftMargin + 70, yPos);
630+
yPos += 4;
631+
doc.setFontSize(9);
632+
doc.text('Signature', leftMargin, yPos);
633+
634+
// Date section
635+
yPos += 12;
636+
doc.setFontSize(10);
637+
doc.text(dateValue, leftMargin, yPos);
638+
yPos += 2;
639+
doc.line(leftMargin, yPos, leftMargin + 40, yPos);
640+
yPos += 4;
641+
doc.setFontSize(9);
642+
doc.text('Date', leftMargin, yPos);
643+
644+
// Add page numbers in footer (Tufte style - centered at bottom)
645+
var pageCount = doc.internal.getNumberOfPages();
646+
for (var i = 1; i <= pageCount; i++) {
647+
doc.setPage(i);
648+
doc.setFont(mainFont, 'normal');
649+
doc.setFontSize(9);
650+
doc.text(String(i), pageWidth / 2, pageHeight - 15, { align: 'center' });
651+
}
599652

600653
// Save the PDF
601654
var filename = 'lab-manual-checklist-' + dateValue + '.pdf';

0 commit comments

Comments
 (0)