Created
February 6, 2026 13:18
-
-
Save micartey/4efaaae678ecf33be133c9d720db258d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name GitHub SVG Inline & Selectable | |
| // @namespace http://tampermonkey.net/ | |
| // @version 1.0 | |
| // @description Replaces img tags with inline SVGs on GitHub to allow text selection, removing wrapping links. | |
| // @author You | |
| // @match https://github.com/* | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| 'use strict'; | |
| // The core conversion logic | |
| function convertSvgs() { | |
| const selector = 'img[src$=".svg"]:not([data-svg-processed])'; | |
| document.querySelectorAll(selector).forEach(async img => { | |
| // Mark immediately to prevent double-fetching during async wait | |
| img.setAttribute('data-svg-processed', 'true'); | |
| try { | |
| const response = await fetch(img.src); | |
| if (!response.ok) throw new Error('Fetch failed'); | |
| const text = await response.text(); | |
| const parser = new DOMParser(); | |
| const doc = parser.parseFromString(text, 'image/svg+xml'); | |
| const svg = doc.documentElement; | |
| // Check for parsing errors | |
| if (svg.querySelector('parsererror')) return; | |
| // Styling for selection | |
| svg.style.userSelect = 'text'; | |
| svg.style.cursor = 'text'; | |
| svg.querySelectorAll('text, tspan').forEach(t => { | |
| t.style.userSelect = 'text'; | |
| t.style.cursor = 'text'; | |
| }); | |
| // Find parent link to remove | |
| const parentLink = img.closest('a'); | |
| const targetToReplace = parentLink ? parentLink : img; | |
| targetToReplace.replaceWith(svg); | |
| } catch (e) { | |
| console.debug('SVG Conversion failed for:', img.src, e); | |
| // Revert attribute so we can retry if needed, or leave to ignore | |
| img.removeAttribute('data-svg-processed'); | |
| } | |
| }); | |
| } | |
| // Run on initial load | |
| convertSvgs(); | |
| // Run on GitHub Page Navigation (Turbo/Pjax events) | |
| document.addEventListener('turbo:load', convertSvgs); | |
| document.addEventListener('turbo:render', convertSvgs); | |
| // Observer for lazy-loaded images (e.g. inside long READMEs) | |
| const observer = new MutationObserver((mutations) => { | |
| let shouldRun = false; | |
| mutations.forEach(m => { | |
| if (m.addedNodes.length > 0) shouldRun = true; | |
| }); | |
| if (shouldRun) convertSvgs(); | |
| }); | |
| observer.observe(document.body, { childList: true, subtree: true }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment