Material design icons (beta)

Adds file Icons to GitHub

  1. // ==UserScript==
  2. // @name Material design icons (beta)
  3. // @namespace mailto:explosionscratch@gmail.com
  4. // @version 0.1
  5. // @description Adds file Icons to GitHub
  6. // @author Explosion-Scratch
  7. // @match *://github.com/*
  8. // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
  9. // @grant GM_getResourceText
  10. // @resource language_map https://gist.githubusercontent.com/Explosion-Scratch/ee1b9316ddb9389959697a00304bc57b/raw/4038781f76d14557d36e3ff2996a847437dc574e/map.json
  11. // @require https://unpkg.com/selector-set@1.1.5/selector-set.js
  12. // @require https://unpkg.com/selector-observer@2.1.6/dist/index.umd.js
  13. // @license MIT
  14. // @run-at document-start
  15. // ==/UserScript==
  16.  
  17. (async () => {
  18. //Requires SelectorSet
  19. SelectorObserver.observe('.js-navigation-container > .js-navigation-item', {
  20. add: icons
  21. });
  22.  
  23. function icons(item) {
  24. let map = JSON.parse(GM_getResourceText("language_map"));
  25. console.log(map);
  26. //Item is '.js-navigation-container > .js-navigation-item' that changed
  27. const isFile = item.querySelector('.octicon-file');
  28. const name = item.querySelector('.js-navigation-open').textContent;
  29. const ext = name.split(".").slice(-1)[0];
  30. let icon = map.icons.find(i => i.fileNames?.includes(name)) || map.moreExtensions.fileNames[name] ||
  31. map.icons.find(i => i.fileExtensions?.includes(ext)) ||
  32. map.icons.find(i => i.name === ext) || map.moreExtensions.fileExtensions[ext] || map.defaultIcon;
  33. if (typeof icon === "string"){
  34. icon = map.icons.find(i => i.name === icon);
  35. }
  36. if (!isFile){
  37. icon = map.folders.icons.find(i => i.folderNames?.includes(name)) || map.folders.defaultIcon;
  38. }
  39. if (!icon?.name){return console.log("No icon", {ext, icon, isFile})}
  40. fetch(`https://raw.githubusercontent.com/PKief/vscode-material-icon-theme/main/icons/${icon.name}.svg`)
  41. .then(res => res.text())
  42. .then((svg) => (svg.startsWith("<svg") && item.querySelector("svg").replaceWith(createElement(svg))))
  43. }
  44. function createElement(htmlString) {
  45. var div = document.createElement('div');
  46. div.innerHTML = htmlString.trim();
  47.  
  48. // Change this to div.childNodes to support multiple top-level nodes.
  49. return div.firstChild;
  50. }
  51. function loadFonts(fonts){
  52. let promises = [];
  53. for (let [fontName, url] of Object.entries(fonts)){
  54. promises.push(fetch(url)
  55. .then(resp => resp.arrayBuffer())
  56. .then(font => {
  57. const fontFace = new FontFace(fontName, font);
  58. document.fonts.add(fontFace);
  59. }))
  60. }
  61. return Promise.all(promises);
  62. }
  63. })();
  64.  
  65. //Memoize fetch
  66. ((window) => {
  67. var _fetch = window.fetch; //Get the original fetch functionm
  68.  
  69. window.fetch = (url, opts = {}) => {
  70. if (!window.FETCH_CACHE) {
  71. window.FETCH_CACHE = {};
  72. }
  73. return new Promise((resolve) => {
  74. /*
  75. Generate a sort of unique key about this fetch request.
  76. GET requests will have `opts.method` and `opts.body` as
  77. undefined, which will be removed by JSON.stringify.
  78.  
  79. For a fetch call such as this:
  80.  
  81. fetch("https://apis.explosionscratc.repl.co/google?q=dogs")
  82.  
  83. the key would be:
  84. "{url: 'https://apis.explosionscratc.repl.co'}"
  85. For a POST/DELETE/PUT request however, the key would also have the opts.method and opts.body (and possibly headers).
  86. */
  87.  
  88. var key = JSON.stringify({
  89. url,
  90. method: opts.method,
  91. body: opts.body,
  92. headers: JSON.stringify(opts.headers),
  93. });
  94.  
  95. //First check for existing cache entries:
  96. if (window.FETCH_CACHE[key]) {
  97. //Important to re-clone the response, otherwise we can't fetch something more than once!
  98. resolve(window.FETCH_CACHE[key].clone());
  99. console.log("Fetched from cache");
  100. return; //Important so we don't fetch anyways!
  101. }
  102.  
  103. _fetch(url, opts).then((res) => {
  104. window.FETCH_CACHE[key] = res.clone(); //Store the response in the cache
  105. resolve(res); //Respond with the response of the fetch.
  106. console.log("Fetched new version");
  107. });
  108. });
  109. };
  110. })(globalThis);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址