afterbefore 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1009,6 +1009,7 @@ async function detectSections(page, maxSections) {
1009
1009
  if (!container || tagged.has(container)) continue;
1010
1010
  if (container.scrollHeight > document.documentElement.scrollHeight * 0.9) continue;
1011
1011
  container.setAttribute("data-ab-section", String(idx));
1012
+ heading.setAttribute("data-ab-heading", String(idx));
1012
1013
  tagged.add(container);
1013
1014
  results.push({
1014
1015
  label: (heading.textContent ?? "").trim(),
@@ -1067,6 +1068,7 @@ async function tagSectionOnPage(page, headingText, index) {
1067
1068
  }
1068
1069
  if (el) {
1069
1070
  el.setAttribute("data-ab-section", String(idx));
1071
+ match.setAttribute("data-ab-heading", String(idx));
1070
1072
  return true;
1071
1073
  }
1072
1074
  return false;
@@ -1074,12 +1076,33 @@ async function tagSectionOnPage(page, headingText, index) {
1074
1076
  { text: headingText, idx: index }
1075
1077
  );
1076
1078
  }
1079
+ async function hideSectionHeading(page, sectionIndex) {
1080
+ await page.evaluate((idx) => {
1081
+ const heading = document.querySelector(`[data-ab-heading="${idx}"]`);
1082
+ if (heading instanceof HTMLElement) {
1083
+ heading.style.display = "none";
1084
+ }
1085
+ }, sectionIndex);
1086
+ }
1087
+ async function showSectionHeading(page, sectionIndex) {
1088
+ await page.evaluate((idx) => {
1089
+ const heading = document.querySelector(`[data-ab-heading="${idx}"]`);
1090
+ if (heading instanceof HTMLElement) {
1091
+ heading.style.display = "";
1092
+ }
1093
+ }, sectionIndex);
1094
+ }
1077
1095
  async function cleanupSectionTags(page) {
1078
1096
  await page.evaluate(() => {
1079
- const tagged = document.querySelectorAll("[data-ab-section]");
1080
- for (const el of tagged) {
1097
+ for (const el of document.querySelectorAll("[data-ab-section]")) {
1081
1098
  el.removeAttribute("data-ab-section");
1082
1099
  }
1100
+ for (const el of document.querySelectorAll("[data-ab-heading]")) {
1101
+ el.removeAttribute("data-ab-heading");
1102
+ if (el instanceof HTMLElement) {
1103
+ el.style.display = "";
1104
+ }
1105
+ }
1083
1106
  });
1084
1107
  }
1085
1108
  function sanitizeSectionLabel(label) {
@@ -1395,12 +1418,16 @@ async function captureAutoSections(afterPage, beforePage, parentPrefix, parentLa
1395
1418
  const sectionAfterPath = join6(outputDir, `${sectionPrefix}-after.png`);
1396
1419
  const sectionBeforePath = join6(outputDir, `${sectionPrefix}-before.png`);
1397
1420
  try {
1421
+ await hideSectionHeading(afterPage, section.index);
1398
1422
  const afterEl = afterPage.locator(`[data-ab-section="${section.index}"]`).first();
1399
1423
  await afterEl.screenshot({ path: sectionAfterPath });
1424
+ await showSectionHeading(afterPage, section.index);
1400
1425
  const found = await tagSectionOnPage(beforePage, section.label, section.index);
1401
1426
  if (found) {
1427
+ await hideSectionHeading(beforePage, section.index);
1402
1428
  const beforeEl = beforePage.locator(`[data-ab-section="${section.index}"]`).first();
1403
1429
  await beforeEl.screenshot({ path: sectionBeforePath });
1430
+ await showSectionHeading(beforePage, section.index);
1404
1431
  } else {
1405
1432
  continue;
1406
1433
  }
@@ -1625,18 +1652,30 @@ function normalizeDimensions(img1, img2) {
1625
1652
  return [pad(img1), pad(img2)];
1626
1653
  }
1627
1654
  async function generateComposite(beforePath, afterPath, outputPath, browser, bgColor) {
1628
- const beforeUri = `data:image/png;base64,${readFileSync5(beforePath).toString("base64")}`;
1629
- const afterUri = `data:image/png;base64,${readFileSync5(afterPath).toString("base64")}`;
1655
+ const beforeBuf = readFileSync5(beforePath);
1656
+ const afterBuf = readFileSync5(afterPath);
1657
+ const beforeUri = `data:image/png;base64,${beforeBuf.toString("base64")}`;
1658
+ const afterUri = `data:image/png;base64,${afterBuf.toString("base64")}`;
1659
+ const beforePng = PNG.sync.read(beforeBuf);
1660
+ const afterPng = PNG.sync.read(afterBuf);
1661
+ const imgW = Math.max(beforePng.width, afterPng.width);
1662
+ const imgH = Math.max(beforePng.height, afterPng.height);
1663
+ const PADDING = 120;
1664
+ const GAP = 80;
1665
+ const LABEL_H = 70;
1666
+ const canvasW = Math.max(600, Math.min(2400, imgW * 2 + GAP + PADDING * 2));
1667
+ const canvasH = Math.max(300, Math.min(2400, imgH + LABEL_H + PADDING * 2));
1668
+ const maxImgH = canvasH - PADDING * 2 - LABEL_H;
1630
1669
  const page = await browser.newPage({
1631
- viewport: { width: 2400, height: 1600 },
1670
+ viewport: { width: canvasW, height: canvasH },
1632
1671
  deviceScaleFactor: 1
1633
1672
  });
1634
1673
  const html = `<!DOCTYPE html>
1635
1674
  <html><head><style>
1636
1675
  * { margin: 0; box-sizing: border-box; }
1637
- body { background: ${bgColor}; display: flex; justify-content: center; align-items: center; width: 2400px; height: 1600px; padding: 120px; gap: 80px; overflow: hidden; }
1676
+ body { background: ${bgColor}; display: flex; justify-content: center; align-items: center; width: ${canvasW}px; height: ${canvasH}px; padding: ${PADDING}px; gap: ${GAP}px; overflow: hidden; }
1638
1677
  .col { flex: 1; display: flex; flex-direction: column; align-items: center; min-width: 0; max-height: 100%; }
1639
- img { width: 100%; max-height: 1280px; object-fit: contain; }
1678
+ img { width: 100%; max-height: ${maxImgH}px; object-fit: contain; }
1640
1679
  .label { margin-top: 40px; font: 500 30px/1 system-ui, sans-serif; flex-shrink: 0; }
1641
1680
  .before { color: #888; }
1642
1681
  .after { color: #22c55e; }
@@ -1867,7 +1906,7 @@ async function runPipeline(options) {
1867
1906
  const outputDir = resolve4(cwd, output, sessionName);
1868
1907
  const startTime = Date.now();
1869
1908
  try {
1870
- const version = true ? "0.1.8" : "dev";
1909
+ const version = true ? "0.1.10" : "dev";
1871
1910
  console.log(`
1872
1911
  afterbefore v${version} \xB7 Comparing against ${base}
1873
1912
  `);
@@ -2012,7 +2051,7 @@ afterbefore v${version} \xB7 Comparing against ${base}
2012
2051
  var program = new Command();
2013
2052
  program.name("afterbefore").description(
2014
2053
  "Automatic before/after screenshot capture for PRs. Git diff is the config."
2015
- ).version("0.1.8").option("--base <ref>", "Base branch or ref to compare against", "main").option("--output <dir>", "Output directory for screenshots", ".afterbefore").option("--post", "Post results as a PR comment via gh CLI", false).option(
2054
+ ).version("0.1.10").option("--base <ref>", "Base branch or ref to compare against", "main").option("--output <dir>", "Output directory for screenshots", ".afterbefore").option("--post", "Post results as a PR comment via gh CLI", false).option(
2016
2055
  "--threshold <percent>",
2017
2056
  "Diff threshold percentage (changes below this are ignored)",
2018
2057
  "0.1"