Last active
May 30, 2021 01:44
-
-
Save TheEpicFace007/9d88c08eee2c9681d2dc86350a1d6b97 to your computer and use it in GitHub Desktop.
Add some quality of life improvement feature on npm
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 NPM Quality of life changes | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Add some quality of life improvenet to npm | |
// @author You | |
// @match http**://www.npmjs.com/** | |
// @grant none | |
// ==/UserScript== | |
function showNotif(notifText) { | |
const copyNotifHTML = `<div class="ts-copy-notif ee9e731a pa3 ph5-ns bb b--black-10 tl pointer z-999 w-100 flex flex-row justify-between d76ab310"> | |
<p class="ma0">${notifText}</p> | |
<p aria-label="Close notification" class="_545224b8 ma0 f3 fw6">×</p> | |
</div>`; | |
const notifSpot = document.querySelector("#app > div > div:nth-child(1) > ul") | |
notifSpot.insertAdjacentHTML("beforeend", copyNotifHTML); | |
setTimeout(() => { | |
notifSpot.lastChild.remove() | |
}, 1500) | |
} | |
if (document.location.pathname.search("package") >= 0) { | |
setTimeout(() => { | |
'use strict'; | |
const $ = document.querySelector; | |
// if the page is a pakcage | |
if (document.location.pathname.search("package") >= 0) { | |
// If it has definitly type typedef | |
const hasDefinitlyTypedTypedef = | |
document.querySelector("#top > div.w-100.ph0-l.ph3.ph4-m > h2 > div > a > img") ? true : false; | |
const hasTypescrptTypedefIncluded = | |
document.querySelector("#top > div.w-100.ph0-l.ph3.ph4-m > h2 > div > img") ? true : false; | |
const packageName = document.querySelector("#top > div.w-100.ph0-l.ph3.ph4-m > h2 > span").innerText; | |
const packageInfo = document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0"); | |
// change the text of the license so u know if it has license or not | |
if (!document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > div:nth-child(5) > h3") && | |
document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > div:nth-child(5) > p")) | |
throw new ReferenceError("Couldn't find the required text to change the license text") | |
document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > div:nth-child(5) > h3").innerText = | |
"Typescript compatible?"; | |
document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > div:nth-child(5) > p").innerText = | |
hasDefinitlyTypedTypedef || hasTypescrptTypedefIncluded ? "✔️" : "❌"; | |
const installPackageText = document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > p > code > span").innerText; | |
document.querySelector("#top > div.fdbf4038.w-third-l.mt3.w-100.ph3.ph4-m.pv3.pv0-l.order-1-ns.order-0 > p > code > span").innerText | |
= installPackageText.replace("npm i", "yarn add") | |
if (hasDefinitlyTypedTypedef) { | |
const copyButtonHtml = `<p id="copy-typedef-cmd" class="d767adf4 lh-copy ts-copy truncate ph0 mb3 black-80 b5be2af6 f6 flex flex-row"><svg viewBox="0 0 12.32 9.33"> | |
<g> | |
<line class="st1" x1="7.6" y1="8.9" x2="7.6" y2="6.9"></line> | |
<rect width="1.9" height="1.9"></rect> | |
<rect x="1.9" y="1.9" width="1.9" height="1.9"></rect> | |
<rect x="3.7" y="3.7" width="1.9" height="1.9"></rect> | |
<rect x="1.9" y="5.6" width="1.9" height="1.9"></rect> | |
<rect y="7.5" width="1.9" height="1.9"></rect> | |
</g> | |
</svg><code class="flex-auto truncate db" title="Copy Command to Clipboard"><span>yarn add --dev @types/${packageName}</span></code><svg | |
aria-hidden="true" focusable="false" data-prefix="far" data-icon="copy" role="img" | |
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"> | |
<path | |
d="M433.941 65.941l-51.882-51.882A48 48 0 0 0 348.118 0H176c-26.51 0-48 21.49-48 48v48H48c-26.51 0-48 21.49-48 48v320c0 26.51 21.49 48 48 48h224c26.51 0 48-21.49 48-48v-48h80c26.51 0 48-21.49 48-48V99.882a48 48 0 0 0-14.059-33.941zM266 464H54a6 6 0 0 1-6-6V150a6 6 0 0 1 6-6h74v224c0 26.51 21.49 48 48 48h96v42a6 6 0 0 1-6 6zm128-96H182a6 6 0 0 1-6-6V54a6 6 0 0 1 6-6h106v88c0 13.255 10.745 24 24 24h88v202a6 6 0 0 1-6 6zm6-256h-64V48h9.632c1.591 0 3.117.632 4.243 1.757l48.368 48.368a6 6 0 0 1 1.757 4.243V112z"> | |
</path> | |
</svg></p>` | |
const copyTypedef = packageInfo.lastElementChild; | |
packageInfo.insertAdjacentHTML("afterBegin", copyButtonHtml); | |
document.getElementById("copy-typedef-cmd").onclick = () => { | |
navigator.clipboard.writeText(`yarn add --dev @types/${packageName}`); | |
showNotif("✔ Copied to clipboard!") | |
} | |
packageInfo.insertAdjacentHTML("afterbegin", '<h3 class="c84e15be f5 mt2 pt2 mb0">Install type definition</h3>') | |
} | |
} | |
document.body.insertAdjacentHTML("afterBegin", ` | |
<style> | |
.ts-copy:hover { | |
border-color: rgb(0, 122, 204) !important; | |
background-color: #007acc15 !important; | |
} | |
</style> | |
`) | |
}, 200); | |
} | |
else if (document.location.pathname == "/search") { | |
setTimeout(() => { | |
document.querySelector("#search > div > fieldset > div:nth-child(4)").insertAdjacentHTML("afterend", | |
`<label for="search_ranking_typescript" class="_9d16cd42 lh-copy"><input type="radio" class="_128f502f mr2" | |
aria-label="Sort Packages Typescript" name="ranking" id="search_ranking_typescript" value="typescript"> | |
<div><b>Typescript</b><br></div> | |
</label>`); | |
const typescriptSorter = document.querySelector("._9390ec46 label[for='search_ranking_typescript'] ") | |
let iteration = 1n; | |
typescriptSorter.addEventListener("click", () => { | |
if (iteration % 2n !== 0n) { | |
typescriptSorter.classList.toggle("selected") | |
console.log('typescriptSorter.classList.contains("selected")', typescriptSorter.classList.contains("selected")) | |
if (typescriptSorter.classList.contains("selected")) { | |
showNotif("\u2026 Filtering out all non typescript compatible package") | |
filterSearchResult("typescript") | |
.then(() => showNotif("\u2713 Finished filtering the non typescript comptabile package")) | |
.catch(() => showNotif("\u2718 Error while filtering the non typescript package"));; | |
} | |
else { | |
showNotif("\u2026 Showing all packages") | |
filterSearchResult("all") | |
.then(() => showNotif("\u2713 Finished showing all package")) | |
.catch(() => showNotif("\u2718 Error while showing all package")) | |
} | |
} | |
iteration++; | |
}) | |
document.body.insertAdjacentHTML("afterbegin", ` | |
<style> | |
._9390ec46 label[for='search_ranking_typescript'] { | |
animation: all 0.5s linear; | |
border-bottom: 1.5px solid #007ACC; | |
} | |
._9390ec46 label[for='search_ranking_typescript'].selected { | |
color: black; | |
animation: all 0.5s linear; | |
} | |
.show { | |
transition: opacity 400ms; | |
} | |
.hide { | |
opacity: 0; | |
} | |
</style> | |
`) | |
}, 100); | |
let hedElement = []; | |
/** | |
* @param {"all" | "typescript"} filter | |
*/ | |
async function filterSearchResult(filter) { | |
const fadeInDuration = 600; | |
if (filter == "typescript") { | |
const promises = [] | |
for (let i = 0; i <= 20; i++) { | |
const module = document.querySelector("#main > div._23fffac0.w-100.mw9.ph5-ns.ph3-l.ph1-m.mh3-ns.center.center-ns.flex.flex-column.flex-row-l.justify-between > div > section:nth-child(" + i + ")"); | |
if (module) { | |
/** @type {string} */ | |
const moduleLink = module.firstElementChild.firstElementChild.href ?? module.firstElementChild.firstElementChild.firstElementChild.href; | |
fetch(moduleLink).then(async (res) => { | |
const text = await res.text(); | |
if (text.search("TypeScript") < 0) { | |
fadeOut(module, fadeInDuration) | |
hedElement.push(module) | |
console.log("Hiding non typescript module") | |
} | |
else { | |
console.log("Keeping the typescript module") | |
} | |
}) | |
.catch(console.error); | |
} | |
} | |
} | |
else { | |
for (const element of hedElement) { | |
fadeIn(element, fadeInDuration) | |
} | |
hedElement = []; | |
} | |
} | |
} | |
function fadeIn(elem, ms) { | |
if (!elem) | |
return; | |
elem.style.opacity = 0; | |
elem.style.filter = "alpha(opacity=0)"; | |
elem.style.display = "" | |
if (ms) { | |
var opacity = 0; | |
var timer = setInterval(function () { | |
opacity += 50 / ms; | |
if (opacity >= 1) { | |
clearInterval(timer); | |
opacity = 1; | |
} | |
elem.style.opacity = opacity; | |
elem.style.filter = "alpha(opacity=" + opacity * 100 + ")"; | |
}, 50); | |
} | |
else { | |
elem.style.opacity = 1; | |
elem.style.filter = "alpha(opacity=1)"; | |
} | |
} | |
function fadeOut(elem, ms) { | |
if (!elem) | |
return; | |
if (ms) { | |
var opacity = 1; | |
var timer = setInterval(function () { | |
opacity -= 50 / ms; | |
if (opacity <= 0) { | |
clearInterval(timer); | |
opacity = 0; | |
elem.style.display = "none"; | |
} | |
elem.style.opacity = opacity; | |
elem.style.filter = "alpha(opacity=" + opacity * 100 + ")"; | |
}, 50); | |
} | |
else { | |
elem.style.opacity = 0; | |
elem.style.filter = "alpha(opacity=0)"; | |
elem.style.display = "none"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment