From 8f64694115b8f87aca68eb730bb71b4d4e63b1ad Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 09:53:46 +0000 Subject: [PATCH 1/5] Fix PDF line separator position and footer bleed-through - Move inter-line separator from bottom to top of each expense line; skip on first line and on page breaks (justBroke flag) so the continuation header is never followed immediately by a divider - Increase needSpace from lh*5 (70pt) to lh*7 (98pt) to match the actual line block height (~6lh + 16pt), preventing content from overrunning M.bottom and bleeding into the footer area https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 527d86e..78c5cb5 100644 --- a/index.html +++ b/index.html @@ -557,14 +557,17 @@ async function generatePDF() { let pg, y; const receiptRefs = []; // { pageIdx, x, y, receiptKey } + let justBroke = false; function addPage(isFirst) { pg = doc.addPage([pageW, pageH]); pages.push(pg); y = pageH - M.top; + justBroke = true; if (!isFirst) drawContHeader(); } function needSpace(h) { + justBroke = false; if (y - h < M.bottom) { addPage(false); } } @@ -632,8 +635,13 @@ async function generatePDF() { y -= lh + 4; // Lines - item.lines.forEach(ln => { - needSpace(lh * 5); + item.lines.forEach((ln, li) => { + needSpace(lh * 7); + if (li > 0 && !justBroke) { + y -= 4; + pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:0.3, color:lineCol}); + y -= 8; + } const c1=0, c2=W*0.18, c3=W*0.6, c4=W*0.78; const r2v=0, r2r=W*0.6, r2a=W*0.78; @@ -692,10 +700,7 @@ async function generatePDF() { y -= lh; }); } - y -= 4; - // Light divider between lines - pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:0.3, color:lineCol}); - y -= 8; + y -= 6; }); // Item divider From 971c1f2fc922ba61b7eec99d64045c6091d65de2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 09:58:17 +0000 Subject: [PATCH 2/5] Replace three blue separators before grand total with one double-weight line The last item divider plus two double-rule lines produced three blue lines. Removed the item divider and the double-rule pair; replaced with a single line at thickness 3 (double the standard 1.5). https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/index.html b/index.html index 78c5cb5..d829ce5 100644 --- a/index.html +++ b/index.html @@ -703,16 +703,11 @@ async function generatePDF() { y -= 6; }); - // Item divider - pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:1, color:accent}); - y -= lh; }); // Grand total needSpace(lh * 2); - pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:1.5, color:accent}); - y -= 4; - pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:1.5, color:accent}); + pg.drawLine({start:{x:M.left,y}, end:{x:M.left+W,y}, thickness:3, color:accent}); y -= lh; const gtStr = `Total reimbursement claim: ${baseCur} ${fmtAmt(state._grandTotal)}`; const gtW = fontBold.widthOfTextAtSize(gtStr, sz + 2); From 0dd4506ed5f25f817f6c72017f6a9fc1e7b2acbe Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 09:59:54 +0000 Subject: [PATCH 3/5] PDF: right-align FX rate, use standard font for FX rate and amount https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index d829ce5..0eac17d 100644 --- a/index.html +++ b/index.html @@ -656,7 +656,8 @@ async function generatePDF() { pg.drawText(truncate(ln.vendor, fontBody, sz, (c3-c2)-8), {x:M.left+c2, y, size:sz, font:fontBody, color:black}); pg.drawText(ln.currency, {x:M.left+c3, y, size:sz, font:fontBody, color:black}); const fxStr = ln.currency === baseCur ? '–' : parseFloat(ln.fxRate).toFixed(5); - pg.drawText(fxStr, {x:M.left+c4, y, size:sz, font:fontMono, color:black}); + const fxW = fontBody.widthOfTextAtSize(fxStr, sz); + pg.drawText(fxStr, {x:M.left+W-fxW, y, size:sz, font:fontBody, color:black}); y -= lh + 2; // Row 2 labels @@ -668,8 +669,8 @@ async function generatePDF() { pg.drawText(truncate(ln.description, fontBody, sz, (r2r-r2v)-8), {x:M.left+r2v, y, size:sz, font:fontBody, color:black}); pg.drawText(ln.hasReceipt ? 'Yes' : 'No', {x:M.left+r2r, y, size:sz, font:fontBody, color:black}); const amtStr = `${ln.currency} ${fmtAmt(ln.amount)}`; - const amtW = fontMono.widthOfTextAtSize(amtStr, sz); - pg.drawText(amtStr, {x:M.left+W-amtW, y, size:sz, font:fontMono, color:black}); + const amtW = fontBody.widthOfTextAtSize(amtStr, sz); + pg.drawText(amtStr, {x:M.left+W-amtW, y, size:sz, font:fontBody, color:black}); y -= lh + 2; // Row 3 labels From 31b5b2e25593134f54506b3b592860841a0cc0b9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 10:00:43 +0000 Subject: [PATCH 4/5] Footer left: show 'Reimbursement form' and staff name on second line https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 0eac17d..60c76ea 100644 --- a/index.html +++ b/index.html @@ -779,8 +779,8 @@ async function generatePDF() { pages.forEach((p, i) => { const fy = M.bottom - 30; p.drawLine({start:{x:M.left, y:fy+18}, end:{x:M.left+W, y:fy+18}, thickness:0.5, color:lineCol}); - const footLeft = CFG.footer || 'Reimbursement form'; - p.drawText(footLeft, {x:M.left, y:fy, size:szSm-1, font:fontBody, color:gray}); + p.drawText('Reimbursement form', {x:M.left, y:fy, size:szSm-1, font:fontBody, color:gray}); + p.drawText(state.staff, {x:M.left, y:fy-lh+2, size:szSm-1, font:fontBody, color:gray}); const pgStr = `Page ${i+1}/${totalPages}`; const pgW2 = fontBody.widthOfTextAtSize(pgStr, szSm-1); p.drawText(pgStr, {x:M.left+W-pgW2, y:fy, size:szSm-1, font:fontBody, color:gray}); From 67786317d71269cfe7701441696124e8f803e15e Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 13 May 2026 10:01:52 +0000 Subject: [PATCH 5/5] Standardise all field labels to szSm-1 in PDF output Staff/Period/Currency header labels and Explanation were using szSm while all line field labels used szSm-1, causing inconsistent sizing. https://claude.ai/code/session_014uUwDBtG5y5FuWcy5zqVD1 --- index.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/index.html b/index.html index 60c76ea..eaa5dcd 100644 --- a/index.html +++ b/index.html @@ -609,9 +609,9 @@ async function generatePDF() { const col2 = W * 0.5; const col3 = W * 0.8; - pg.drawText('Staff', {x:M.left, y, size:szSm, font:fontBold, color:gray}); - pg.drawText('Period', {x:M.left+col2, y, size:szSm, font:fontBold, color:gray}); - pg.drawText('Currency', {x:M.left+col3, y, size:szSm, font:fontBold, color:gray}); + pg.drawText('Staff', {x:M.left, y, size:szSm-1, font:fontBold, color:gray}); + pg.drawText('Period', {x:M.left+col2, y, size:szSm-1, font:fontBold, color:gray}); + pg.drawText('Currency', {x:M.left+col3, y, size:szSm-1, font:fontBold, color:gray}); y -= lh; pg.drawText(state.staff, {x:M.left, y, size:sz, font:fontBody, color:black}); pg.drawText(`${formatDate(state.periodFrom)} to ${formatDate(state.periodTo)}`, {x:M.left+col2, y, size:sz, font:fontBody, color:black}); @@ -692,7 +692,7 @@ async function generatePDF() { }); } else if (!ln.hasReceipt) { needSpace(lh * 2); - pg.drawText('Explanation:', {x:M.left, y, size:szSm, font:fontBold, color:gray}); + pg.drawText('Explanation:', {x:M.left, y, size:szSm-1, font:fontBold, color:gray}); y -= lh; const explLines = wrapText(ln.noReceiptExplanation || '–', fontBody, sz, W); explLines.forEach(line => {