@@ -536,66 +536,119 @@ function generateChecklistPDF(dateValue) {
536536
537537function 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