Created
December 23, 2024 05:30
-
-
Save Mariven/e76b52f8614a13ef6a941da9b29d147a 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 Boilerplate File Shrinker | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description try to take over the world! | |
// @author Mariven | |
// @match https://github.com/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=github.com | |
// @grant none | |
// ==/UserScript== | |
( function() { 'use strict'; | |
let paths = {}; | |
const // configurables | |
blacklist = [ | |
// forbidden js files | |
/\.(conf|config)\.js$/i, | |
// forbidden filename prefixes | |
/^(tsconfig|gradle|build|mypy|pyright|pytest|jenkinsfile|gradlew?).*?\./i, | |
// forbidden dot prefixes | |
/^\.(vscode|aws|DS_Store|env|circleci|mailmap|cloudflare|nix|zed|cursor|.*?\.json)/i, | |
// forbidden folders | |
/^(target|build|dist|deploy|enterprise|node[-_]modules|tests|legal|nix|test|crates|tooling|jenkinsfile|gradlew|CVS|ci[-_]cd|db[-_]scripts|enterprise)(\/|$)/i, | |
// forbidden extensions | |
/\.(lock|toml|properties|example|plist|nix|yml|yaml|prisma|.*?lint)$/i, | |
// forbidden dot infixes | |
/^\..*?(ignore|rc|[-_](version|ci|cd)|config|git|flake|yarn|container|cargo|compose|workflow|pipeline|package|gradle|husky|mvn|svn|idea)/i, | |
// forbidden config files | |
/^(yarn|composer|tsconfig|livekit|renovate|azure-pipelines|github-workflows|docker-compose|appveyor|vercel|pom|mvn|settings|coverage|tox|Desktop|package(-lock)?)\.(lock|json|yaml|yml|xml|ini)$/i, | |
// forbidden config dotfiles | |
/^\.(travis|bitrise)\.(lock|json|yaml|yml)$/i, | |
// other | |
/^(?:CODE.?OF.?CONDUCT|LICENSE(.?MODEL)?|SECURITY|CONTRIBUTING|COPYING|MANIFEST|NOTICE|Makefile)(?:(\.|-)[a-zA-Z]+)?(?:(\.|-)[a-zA-Z]+)?$/i, | |
/^(docker|p(ip|roc)|gem)-?(file-?)?/i, | |
/^(thumbs|requirements)\.(db|txt)$/i, | |
].map(rx => new RegExp(rx)), | |
selectors = { | |
row: "tr[id^='folder-row'], table[aria-labelledby='folders-and-files']>tbody>tr", | |
title: ".react-directory-filename-cell", | |
icons: ".react-directory-filename-column svg", | |
blocks: ".react-directory-filename-column", | |
contents: ".react-directory-filename-column cell", | |
}, | |
config = { | |
styles: { | |
row: {height: "20px", opacity: "0.5", fontSize: "0.7em"}, | |
blocks: {height: "20px"}, | |
icons: {scale: "0.8", height: "20px"}, | |
title: {fontSize: "0.8em"} | |
}, | |
hideCompletely: false, | |
}; | |
const // utilities | |
get = (sel, el = document) => el.querySelector(sel), | |
getAll = (sel, el = document) => Array.from(el.querySelectorAll(sel)), | |
text = (sel, el = document) => el.querySelector(sel)?.innerText, | |
hyphenize = (str) => str.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase(), | |
setStyleAttr = (el, key, val, important = false) => { | |
el.style.setProperty(hyphenize(key), val, important ? "important" : null); | |
el.style.cssText += `${hyphenize(key)}:${val}${important ? '!important' : ''};`; | |
}, | |
forceStyle = (el, styleParams) => Object.entries(styleParams).forEach(([k, v]) => setStyleAttr(el, k, v, true)), | |
forceStyleSystem = (baseEl, styleTree) => { | |
styleTree.forEach(item => { | |
let els = item.selector | |
? (item.all ? getAll : (s,e)=>[get(s,e)])(item.selector, baseEl) | |
: [baseEl]; | |
els.forEach(el => forceStyle(el, item.style)); | |
}); | |
}, | |
isIgnorable = row => blacklist.some(rx => text(selectors.title, row)?.match(rx)), | |
processRow = row => forceStyleSystem(row, [ | |
{selector: null , all: false, style: config.styles.row }, | |
{selector: selectors.blocks, all: true , style: config.styles.blocks }, | |
{selector: selectors.icons , all: true , style: config.styles.icons }, | |
{selector: selectors.title , all: true , style: config.styles.title }, | |
]); | |
function addStyles() { | |
// do the thing | |
getAll(selectors.row).filter(isIgnorable).forEach(processRow); | |
paths[window.location.pathname] = true; | |
} | |
function waitForContent(retries=10) { | |
// try { if (paths[window.location.pathname]) return; } catch{} | |
if (document.querySelector(selectors.row)) { | |
addStyles(); | |
} else { | |
setTimeout(()=>waitForContent(retries-1), 250); | |
} | |
}; | |
// set up observer | |
const observer = new MutationObserver(mutations => { | |
mutations.forEach(mutation => { | |
setTimeout(()=>waitForContent(10), 250); | |
}); | |
}); | |
observer.observe(document.body, { | |
childList: true, | |
subtree: true | |
}); | |
waitForContent(); | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment