Add accent rule above item header and zebra stripes for expense lines

- Thin accent-coloured line (0.75pt) drawn just above each ITEM /
  PROJECT / TRAVEL header for visual separation between items
- Alternating white / light-grey (0.95) stripe backgrounds on expense
  lines; stripe height is pre-calculated from content so it covers
  vendor, description, receipt and account/program rows cleanly
- Thin grey vendor rule is drawn on top of the stripe background
This commit is contained in:
Claude 2026-05-24 18:46:37 +00:00
parent b6497c4d0a
commit f0f65edc79
No known key found for this signature in database

View file

@ -955,6 +955,7 @@ async function generatePDF() {
state.items.forEach(item => {
// Item header
needSpace(lh * 6); // need room for at least header + one line
pg.drawLine({start:{x:M.left, y:y+3}, end:{x:M.left+W, y:y+3}, thickness:0.75, color:accent});
pg.drawText('ITEM / PROJECT / TRAVEL', {x:M.left, y, size:sz, font:fontBold, color:accent});
const subStr = `Subtotal: ${baseCur} ${fmtAmt(item._subtotal)}`;
const subW = fontBold.widthOfTextAtSize(subStr, sz);
@ -967,9 +968,26 @@ async function generatePDF() {
item.lines.forEach((ln, li) => {
needSpace(lh * 8);
// Thin grey rule above each vendor line
// Spacing between consecutive expense lines
if (!justBroke && li > 0) y -= 6;
// Pre-calculate content height so zebra stripe rect can be drawn before text
const stripeH = (() => {
let h = (lh + 2) * 2; // vendor + description rows
if (ln.hasReceipt && ln.receipts.length > 0) h += lh * ln.receipts.length;
else if (!ln.hasReceipt) h += lh * Math.max(1, wrapText(ln.noReceiptExplanation||'', fontBody, szSm, W*0.6).length);
else h += lh;
h += lh * Math.max(1, (ln.programs||[]).length);
return h + 4;
})();
// Zebra stripe: odd-indexed lines get a light grey background
if (li % 2 === 1) {
pg.drawRectangle({x:M.left, y:y-stripeH, width:W, height:stripeH+lh+2, color:rgb(0.95,0.95,0.95)});
}
// Thin grey rule above vendor text (drawn on top of stripe)
if (!justBroke) {
if (li > 0) y -= 6;
pg.drawLine({start:{x:M.left, y:y+lh+1}, end:{x:M.left+W, y:y+lh+1}, thickness:0.3, color:lineCol});
}