| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
Highlights pixel-level differences in GitLab MR image diffs. Works on any GitLab instance.
Create a new bookmark in your browser with the URL below (paste it into the URL field directly, dragging doesn't work from Markdown):
javascript:(function%20()%20%7B%20const%20PANEL_ATTR%20%3D%20%22data-gl-diff-panel%22%3B%20function%20processViewers()%20%7B%20document%20.querySelectorAll('button%5Baria-label%3D%22Show%20file%20contents%22%5D')%20.forEach((b)%20%3D%3E%20b.click())%3B%20document%20.querySelectorAll('%5Bdata-testid%3D%22expand-button%22%5D')%20.forEach((b)%20%3D%3E%20b.click())%3B%20document.querySelectorAll(%22.view-modes-menu%20li%22).forEach((li)%20%3D%3E%20%7B%20if%20(li.textContent.trim()%20%3D%3D%3D%20%222-up%22%20%26%26%20!li.classList.contains(%22active%22))%20li.click()%3B%20%7D)%3B%20document.querySelectorAll(%22.diff-viewer%20.image%22).forEach((viewer)%20%3D%3E%20%7B%20if%20(viewer.querySelector(%22%5B%22%20%2B%20PANEL_ATTR%20%2B%20%22%5D%22))%20return%3B%20const%20oldImg%20%3D%20viewer.querySelector(%22.frame.deleted%20img%22)%3B%20const%20newImg%20%3D%20viewer.querySelector(%22.frame.added%20img%22)%3B%20if%20(!oldImg%20%7C%7C%20!newImg)%20return%3B%20injectDiffPanel(viewer%2C%20oldImg.src%2C%20newImg.src)%3B%20%7D)%3B%20%7D%20let%20debTimer%3B%20const%20obs%20%3D%20new%20MutationObserver(()%20%3D%3E%20%7B%20clearTimeout(debTimer)%3B%20debTimer%20%3D%20setTimeout(processViewers%2C%20200)%3B%20%7D)%3B%20obs.observe(document.body%2C%20%7BchildList%3A%20true%2C%20subtree%3A%20true%7D)%3B%20processViewers()%3B%20function%20injectDiffPanel(viewer%2C%20oldSrc%2C%20newSrc)%20%7B%20const%20panel%20%3D%20document.createElement(%22div%22)%3B%20panel.setAttribute(PANEL_ATTR%2C%20%221%22)%3B%20panel.style.cssText%20%3D%20%22margin%3A0%3Bpadding%3A10px%2012px%2014px%3Bbackground%3A%230d0d0d%3Bborder-top%3A3px%20solid%20%23fc6d26%3B%22%3B%20const%20label%20%3D%20document.createElement(%22div%22)%3B%20label.textContent%20%3D%20%22%E2%96%B6%20Pixel%20diff%20%E2%80%94%20grey%20%3D%20unchanged%20%C2%B7%20colour%20%3D%20changed%22%3B%20label.style.cssText%20%3D%20%22color%3A%23fc6d26%3Bfont%3A700%2011px%2F2.2%20monospace%3Bletter-spacing%3A.05em%3Bmargin-bottom%3A4px%3B%22%3B%20const%20outerWrap%20%3D%20document.createElement(%22div%22)%3B%20outerWrap.style.cssText%20%3D%20%22position%3Arelative%3Bline-height%3A0%3B%22%3B%20const%20baseImg%20%3D%20new%20Image()%3B%20baseImg.src%20%3D%20newSrc%3B%20baseImg.style.cssText%20%3D%20%22display%3Ablock%3Bfilter%3Agrayscale(1)%20contrast(0.3)%20brightness(1.0)%3B%22%3B%20const%20diffGroup%20%3D%20document.createElement(%22div%22)%3B%20diffGroup.style.cssText%20%3D%20%22position%3Aabsolute%3Btop%3A0%3Bleft%3A0%3B%22%20%2B%20%22filter%3Abrightness(10)%20saturate(4)%3B%22%20%2B%20%22mix-blend-mode%3Acolor-dodge%3B%22%3B%20const%20img1%20%3D%20new%20Image()%3B%20img1.src%20%3D%20oldSrc%3B%20img1.style.cssText%20%3D%20%22display%3Ablock%3B%22%3B%20const%20img2%20%3D%20new%20Image()%3B%20img2.src%20%3D%20newSrc%3B%20img2.style.cssText%20%3D%20%22position%3Aabsolute%3Btop%3A0%3Bleft%3A0%3Bmix-blend-mode%3Adifference%3B%22%3B%20diffGroup.append(img1%2C%20img2)%3B%20outerWrap.append(baseImg%2C%20diffGroup)%3B%20panel.append(label%2C%20outerWrap)%3B%20viewer.appendChild(panel)%3B%20Promise.all(%5B%20img1.decode().catch(()%20%3D%3E%20%7B%7D)%2C%20img2.decode().catch(()%20%3D%3E%20%7B%7D)%2C%20%5D).then(()%20%3D%3E%20%7B%20const%20oldW%20%3D%20img1.naturalWidth%2C%20oldH%20%3D%20img1.naturalHeight%3B%20const%20newW%20%3D%20img2.naturalWidth%2C%20newH%20%3D%20img2.naturalHeight%3B%20if%20(!oldW%20%7C%7C%20!newW)%20return%3B%20const%20maxW%20%3D%20Math.max(oldW%2C%20newW)%3B%20const%20maxH%20%3D%20Math.max(oldH%2C%20newH)%3B%20const%20style%20%3D%20getComputedStyle(panel)%3B%20const%20availW%20%3D%20panel.clientWidth%20-%20parseFloat(style.paddingLeft)%20-%20parseFloat(style.paddingRight)%3B%20if%20(availW%20%3C%3D%200)%20return%3B%20const%20scale%20%3D%20maxW%20%3E%20availW%20%3F%20availW%20%2F%20maxW%20%3A%201%3B%20outerWrap.style.width%20%3D%20maxW%20*%20scale%20%2B%20%22px%22%3B%20outerWrap.style.height%20%3D%20maxH%20*%20scale%20%2B%20%22px%22%3B%20diffGroup.style.width%20%3D%20%22100%25%22%3B%20diffGroup.style.height%20%3D%20%22100%25%22%3B%20baseImg.style.cssText%20%3D%20%60display%3Ablock%3Bwidth%3A%24%7BnewW%20*%20scale%7Dpx%3Bheight%3A%24%7BnewH%20*%20scale%7Dpx%3Bfilter%3Agrayscale(1)%20contrast(0.3)%20brightness(1.0)%3B%60%3B%20img1.style.cssText%20%3D%20%60display%3Ablock%3Bwidth%3A%24%7BoldW%20*%20scale%7Dpx%3Bheight%3A%24%7BoldH%20*%20scale%7Dpx%3B%60%3B%20img2.style.cssText%20%3D%20%60position%3Aabsolute%3Btop%3A0%3Bleft%3A0%3Bwidth%3A%24%7BnewW%20*%20scale%7Dpx%3Bheight%3A%24%7BnewH%20*%20scale%7Dpx%3Bmix-blend-mode%3Adifference%3B%60%3B%20%7D)%3B%20%7D%20%7D)()%3B
Reading the diff: The panel shows the new screenshot in greyscale as context. Changed pixels glow in colour on top. Grey = unchanged, colour = changed.
After editing gitlab-image-diff.js, run
node -e "
const src = require('fs').readFileSync('./gitlab-image-diff.js', 'utf8');
const min = src
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\/\/[^\n]*/g, '')
.replace(/\s+/g, ' ')
.trim();
process.stdout.write('javascript:' + encodeURIComponent(min) + '\n');
"Paste the output into the Installation section above.
Pure CSS compositing.
Layer 1 — base: new image with filter: grayscale(1) contrast(0.3) brightness(1.0)
Layer 2 — diff group, composited onto layer 1 with mix-blend-mode: color-dodge:
| Back | FazBrowse Home | New Git URL |