diff --git a/src/main/java/com/seleniumboot/reporting/HtmlReportGenerator.java b/src/main/java/com/seleniumboot/reporting/HtmlReportGenerator.java index 13d3a6c..7376cf6 100644 --- a/src/main/java/com/seleniumboot/reporting/HtmlReportGenerator.java +++ b/src/main/java/com/seleniumboot/reporting/HtmlReportGenerator.java @@ -144,7 +144,7 @@ private static String buildScreenshotCell(JsonNode test) { String base64 = Base64.getEncoder().encodeToString(bytes); String src = "data:image/png;base64," + base64; return ""; + + "onclick=\"openLightbox(this)\" title=\"Click to view full size\" />"; } catch (java.io.IOException e) { return "load error"; } @@ -1066,7 +1066,7 @@ private static String buildStepTimeline(JsonNode test) { if (step.has("screenshotBase64")) { String src = "data:image/png;base64," + step.get("screenshotBase64").asText(); thumbHtml = ""; + + "onclick=\"openLightbox(this)\" title=\"Click to view full size\" />"; } sb.append("
") diff --git a/src/main/resources/report/partials/lightbox.html b/src/main/resources/report/partials/lightbox.html index 316a2c8..279988e 100644 --- a/src/main/resources/report/partials/lightbox.html +++ b/src/main/resources/report/partials/lightbox.html @@ -1,5 +1,8 @@ diff --git a/src/main/resources/report/report.css b/src/main/resources/report/report.css index 6de8919..0c4122c 100644 --- a/src/main/resources/report/report.css +++ b/src/main/resources/report/report.css @@ -228,6 +228,12 @@ .lightbox img { max-width: 92vw; max-height: 92vh; border-radius: 6px; box-shadow: 0 8px 40px rgba(0,0,0,.6); } .lightbox-close { position: fixed; top: 18px; right: 24px; color: #fff; font-size: 32px; cursor: pointer; line-height: 1; opacity: .8; } .lightbox-close:hover { opacity: 1; } + .lightbox-nav { position: fixed; top: 50%; transform: translateY(-50%); background: rgba(255,255,255,.15); color: #fff; border: 0; border-radius: 50%; width: 44px; height: 44px; font-size: 20px; cursor: pointer; } + .lightbox-nav:hover:not(:disabled) { background: rgba(255,255,255,.3); } + .lightbox-nav:disabled { opacity: .25; cursor: default; } + .lightbox-prev { left: 20px; } + .lightbox-next { right: 20px; } + .lightbox-counter { position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%); color: #fff; font-size: 14px; background: rgba(0,0,0,.5); padding: 3px 12px; border-radius: 12px; } /* ── Filter + search bar ── */ .filter-bar { display: flex; align-items: center; gap: 10px; padding: 14px 24px; border-bottom: 1px solid var(--border); flex-wrap: wrap; } diff --git a/src/main/resources/report/report.js b/src/main/resources/report/report.js index 5e08d00..d9334e1 100644 --- a/src/main/resources/report/report.js +++ b/src/main/resources/report/report.js @@ -6,18 +6,56 @@ function showTab(tabId, el) { if (el) el.classList.add('active'); } // ── Lightbox ── -function openLightbox(src) { - document.getElementById('lightbox-img').src = src; +var lightboxImgs = []; +var lightboxIdx = 0; +// Screenshots of the same test: its row thumbnail plus the thumbnails in its detail row. +function collectTestScreenshots(img) { + var row = img.closest('tr'); + if (!row) return [img]; + var testRow = row.classList.contains('detail-row') ? row.previousElementSibling : row; + var detailRow = testRow && testRow.nextElementSibling; + var rows = [testRow]; + if (detailRow && detailRow.classList.contains('detail-row')) rows.push(detailRow); + var imgs = []; + rows.forEach(function(r) { + if (r) r.querySelectorAll('img.screenshot-thumb, img.step-thumb').forEach(function(i) { imgs.push(i); }); + }); + return imgs.indexOf(img) >= 0 ? imgs : [img]; +} +function showLightbox() { + document.getElementById('lightbox-img').src = lightboxImgs[lightboxIdx].src; + var multi = lightboxImgs.length > 1; + document.getElementById('lightbox-counter').textContent = multi ? (lightboxIdx + 1) + ' / ' + lightboxImgs.length : ''; + document.getElementById('lightbox-prev').style.display = multi ? '' : 'none'; + document.getElementById('lightbox-next').style.display = multi ? '' : 'none'; + document.getElementById('lightbox-prev').disabled = lightboxIdx === 0; + document.getElementById('lightbox-next').disabled = lightboxIdx === lightboxImgs.length - 1; +} +function openLightbox(img) { + lightboxImgs = collectTestScreenshots(img); + lightboxIdx = lightboxImgs.indexOf(img); + showLightbox(); document.getElementById('lightbox').classList.add('open'); document.body.style.overflow = 'hidden'; } +function stepLightbox(delta, e) { + if (e) e.stopPropagation(); + var next = lightboxIdx + delta; + if (next < 0 || next >= lightboxImgs.length) return; + lightboxIdx = next; + showLightbox(); +} function closeLightbox() { document.getElementById('lightbox').classList.remove('open'); document.getElementById('lightbox-img').src = ''; document.body.style.overflow = ''; + lightboxImgs = []; } document.addEventListener('keydown', function(e) { + if (!document.getElementById('lightbox').classList.contains('open')) return; if (e.key === 'Escape') closeLightbox(); + else if (e.key === 'ArrowLeft') stepLightbox(-1); + else if (e.key === 'ArrowRight') stepLightbox(1); }); // ── Dark mode ── @@ -481,4 +519,4 @@ window.addEventListener('afterprint', function () { } printState = null; -}); +});