// ==UserScript==
// @name GitHub Files Icon Replacement
// @name:vi Thay thế biểu tượng tệp GitHub
// @name:zh-cn GitHub 文件图标替换
// @name:zh-tw GitHub 文件圖標替換
// @name:ru Замена иконок файлов GitHub
// @namespace http://tampermonkey.net/
// @version 2024.12.24.1
// @description Replace GitHub file icons with material icons
// @description:vi Thay thế icon file trên GitHub bằng icon material
// @description:zh-cn 用更漂亮的图标替换 GitHub 文件图标
// @description:zh-tw 用更漂亮的圖標替換 GitHub 文件圖標
// @description:ru Замена иконок файлов GitHub на более красивые
// @author Yuusei
// @match https://github.com/*
// @icon https://github.githubassets.com/favicon.ico
// @grant none
// @run-at document-start
// @license GPL-3.0-only
// @compatible chrome
// @compatible firefox
// @compatible edge
// ==/UserScript==
(function () {
'use strict';
function replaceIcons() {
const fileElements = document.querySelectorAll('.react-directory-row-name-cell-large-screen');
fileElements.forEach(element => {
const filenameElement = element.querySelector('.react-directory-filename-cell');
if (filenameElement) {
const filename = filenameElement.textContent;
let iconName = '';
const iconMap = {
'.ts': 'typescript',
'.json': 'json',
'.yml': 'yaml',
'.yaml': 'yaml',
'.js': 'javascript',
'.html': 'html',
'.css': 'css',
'.py': 'python',
'.php': 'php',
'.md': 'markdown',
'.lua': 'lua',
'.npm': 'npm',
'.lock': 'npm',
'.svg': 'svg',
'.xml': 'xml',
'.txt': 'document',
'.vue': 'vue',
'.angular': 'angular',
'.gitignore': 'git',
'.git': 'git',
'.jsx': 'react',
'.tsx': 'react_ts',
'.scss': 'sass',
'.sass': 'sass',
'.less': 'less',
'.fish': 'shell',
'.c': 'c',
'.cpp': 'cpp',
'.cs': 'csharp',
'.go': 'go',
'.rs': 'rust',
'.rb': 'ruby',
'.java': 'java',
'.kt': 'kotlin',
'.kts': 'kotlin',
'.swift': 'swift',
'.dart': 'dart',
'.sql': 'database',
'.db': 'database',
'.env': 'tune',
'.docker': 'docker',
'.dockerfile': 'docker',
'.exe': 'exe',
'.png': 'image',
'.jpg': 'image',
'.jpeg': 'image',
'.gif': 'image',
'.ico': 'image',
'.webp': 'image',
'.bmp': 'image',
'.tiff': 'image',
'.mp3': 'audio',
'.wav': 'audio',
'.mp4': 'video',
'.mov': 'video',
'.avi': 'video',
'.ini': 'settings',
'.config': 'settings',
'.toml': 'settings',
'.gradle': 'gradle',
'.jar': 'java',
'.class': 'java',
'.properties': 'settings',
'.r': 'r',
'.rmd': 'r',
'.scala': 'scala',
'.groovy': 'groovy',
'.pl': 'perl',
'.pm': 'perl',
'.h': 'c',
'.hpp': 'cpp',
'.hxx': 'cpp',
'.m': 'objectivec',
'.mm': 'objectivec',
'.swift': 'swift',
'.f': 'fortran',
'.f90': 'fortran',
'.f95': 'fortran',
'.mat': 'matlab',
'.coffee': 'coffeescript',
'.litcoffee': 'coffeescript',
'.elm': 'elm',
'.ex': 'elixir',
'.exs': 'elixir',
'.erl': 'erlang',
'.hrl': 'erlang',
'.clj': 'clojure',
'.cljs': 'clojure',
'.fs': 'fsharp',
'.fsx': 'fsharp',
'.hs': 'haskell',
'.lhs': 'haskell',
'.ml': 'ocaml',
'.mli': 'ocaml',
'.pp': 'puppet',
'.tf': 'terraform',
'.tfvars': 'terraform',
'.sol': 'solidity',
'.proto': 'protobuf',
'.graphql': 'graphql',
'.haml': 'haml',
'.slim': 'slim',
'.erb': 'erb',
'.jade': 'pug',
'.pug': 'pug',
'.styl': 'stylus',
'.nix': 'nix',
'.vim': 'vim',
'.bat': 'console',
'.cmd': 'console',
'.dll': 'dll',
'.so': 'lib',
'.a': 'lib',
'.dylib': 'lib',
'.zip': 'zip',
'.rar': 'zip',
'.7z': 'zip',
'.tar': 'zip',
'.gz': 'zip',
'.bz2': 'zip',
'.xz': 'zip',
'.pdf': 'pdf',
'.doc': 'word',
'.docx': 'word',
'.ppt': 'powerpoint',
'.pptx': 'powerpoint',
'.odt': 'document',
'.fig': 'figma',
'.xd': 'xd',
'.ai': 'illustrator',
'.psd': 'photoshop',
'.blend': 'blender',
'.fbx': '3d',
'.obj': '3d',
'.stl': '3d',
'.3ds': '3d',
'.max': '3d',
'.maya': '3d',
'.shader': 'shader',
'.glsl': 'shader',
'.vert': 'shader',
'.frag': 'shader',
'.wasm': 'assembly',
'.wat': 'assembly',
'.asm': 'assembly',
'.s': 'assembly',
'.ko': 'linux',
'.deb': 'debian',
'.rpm': 'redhat',
'.apk': 'android',
'.ipa': 'apple',
'.dmg': 'apple',
'.pkg': 'apple',
'.app': 'apple',
'.pas': 'pascal',
'.cobol': 'cobol',
'.ada': 'ada',
'.lisp': 'lisp',
'.scm': 'scheme',
'.rkt': 'racket',
'.prolog': 'prolog',
'.forth': 'forth',
'.apl': 'apl',
'.basic': 'basic',
'.d': 'd',
'.nim': 'nim',
'.crystal': 'crystal',
'.julia': 'julia',
'.io': 'io',
'.tcl': 'tcl',
'.zig': 'zig',
'.v': 'v',
'.odin': 'odin',
'.haxe': 'haxe',
'.idl': 'idl',
'.hack': 'hack',
'.pike': 'pike',
'.eiffel': 'eiffel',
'.smalltalk': 'smalltalk',
'.modula': 'modula',
'.algol': 'algol',
'.bf': 'brainfuck',
'.awk': 'awk',
'.sed': 'sed',
'.perl6': 'perl6',
'.raku': 'perl6',
'.jl': 'julia',
'.cr': 'crystal',
'.factor': 'factor',
'.idr': 'idris',
'.agda': 'agda',
'.lean': 'lean',
'.curry': 'curry',
'.mercury': 'mercury',
'.clean': 'clean',
'.oz': 'oz',
'.sml': 'sml',
'.vhdl': 'vhdl',
'.verilog': 'verilog',
'.ceylon': 'ceylon',
'.red': 'red',
'.rebol': 'rebol',
'.io': 'io',
'.j': 'j',
'.k': 'k',
'.q': 'q',
'.pure': 'pure',
'.ur': 'ur',
'.fstar': 'fstar',
'.coq': 'coq',
'.isabelle': 'isabelle',
'.hol': 'hol',
'.mizar': 'mizar',
'.twelf': 'twelf',
'.maude': 'maude',
'.alloy': 'alloy',
'.tla': 'tla',
'.z3': 'z3',
'.smt': 'smt',
'.why3': 'why3',
'.acl2': 'acl2',
'.pvs': 'pvs',
'.nuprl': 'nuprl',
'.lego': 'lego',
'.ats': 'ats',
'.idris2': 'idris2',
'.dhall': 'dhall',
'.unison': 'unison',
'.koka': 'koka',
'.grain': 'grain',
'.gleam': 'gleam',
'.roc': 'roc',
'.vale': 'vale',
'.lobster': 'lobster',
'.wren': 'wren',
'.gravity': 'gravity',
'.virgil': 'virgil',
'.gluon': 'gluon',
'.felix': 'felix',
'.clay': 'clay',
'.kitten': 'kitten',
'.pony': 'pony',
'.reason': 'reason',
'.purescript': 'purescript',
'.elm': 'elm',
'.imba': 'imba',
'.mint': 'mint',
'.grain': 'grain',
'.beef': 'beef',
'.zig': 'zig',
'.vlang': 'vlang',
'.odin': 'odin',
'.carbon': 'carbon',
'.mojo': 'mojo',
'.val': 'val',
'.hare': 'hare',
'.ante': 'ante',
'.kind': 'kind',
'.dafny': 'dafny',
'.bosque': 'bosque',
'.keli': 'keli',
'.gno': 'gno',
'.jakt': 'jakt',
'.hylo': 'hylo',
'.inko': 'inko',
'.nickel': 'nickel',
'.pikelet': 'pikelet',
'.sixten': 'sixten',
'.skip': 'skip',
'.spiral': 'spiral',
'.verse': 'verse',
'.wyvern': 'wyvern',
'.zephyr': 'zephyr'
};
const specialFiles = {
'package.json': 'nodejs',
'README.md': 'markdown',
'LICENSE': 'certificate',
'.prettierignore': 'prettier',
'.prettierrc': 'prettier',
'.eslintignore': 'eslint',
'.eslintrc.cjs': 'eslint',
'.eslintrc.js': 'eslint',
'.eslintrc.json': 'eslint',
'.eslintrc.yml': 'eslint',
'docker-compose.yml': 'docker',
'Dockerfile': 'docker',
'.dockerignore': 'docker',
'.env.local': 'tune',
'.env.development': 'tune',
'.env.production': 'tune',
'.env.test': 'tune',
'.env.staging': 'tune',
'tsconfig.json': 'typescript',
'webpack.config.js': 'webpack',
'babel.config.js': 'babel',
'jest.config.js': 'jest',
'angular.json': 'angular',
'next.config.js': 'next',
'nuxt.config.js': 'nuxt',
'vite.config.js': 'vite',
'rollup.config.js': 'rollup',
'svelte.config.js': 'svelte',
'tailwind.config.js': 'tailwind',
'postcss.config.js': 'postcss',
'composer.json': 'composer',
'composer.lock': 'composer',
'Gemfile': 'ruby',
'Gemfile.lock': 'ruby',
'requirements.txt': 'python',
'poetry.lock': 'python',
'pyproject.toml': 'python',
'Cargo.toml': 'rust',
'Cargo.lock': 'rust',
'go.mod': 'go',
'go.sum': 'go',
'mix.exs': 'elixir',
'rebar.config': 'erlang',
'stack.yaml': 'haskell',
'cabal.project': 'haskell',
'dune-project': 'ocaml',
'opam': 'ocaml',
'Rakefile': 'ruby',
'Makefile': 'makefile',
'CMakeLists.txt': 'cmake',
'build.gradle': 'gradle',
'pom.xml': 'maven',
'build.sbt': 'sbt',
'mix.lock': 'elixir',
'elm.json': 'elm',
'browserslist': 'browserslist',
'.babelrc': 'babel',
'.travis.yml': 'travis',
'circle.yml': 'circleci',
'jenkins.yml': 'jenkins',
'kubernetes.yml': 'kubernetes',
'nginx.conf': 'nginx',
'apache.conf': 'apache',
'.gitattributes': 'git',
'.gitmodules': 'git',
'.gitlab-ci.yml': 'gitlab',
'bitbucket-pipelines.yml': 'bitbucket',
'azure-pipelines.yml': 'azure',
'Jenkinsfile': 'jenkins',
'sonar-project.properties': 'sonarqube',
'phpunit.xml': 'phpunit',
'karma.conf.js': 'karma',
'cypress.json': 'cypress',
'playwright.config.js': 'playwright',
'selenium.config.js': 'selenium',
'docker-compose.override.yml': 'docker',
'docker-compose.prod.yml': 'docker',
'docker-compose.dev.yml': 'docker',
'Procfile': 'heroku',
'vercel.json': 'vercel',
'netlify.toml': 'netlify',
'firebase.json': 'firebase',
'now.json': 'zeit',
'pm2.config.js': 'pm2',
'nodemon.json': 'nodemon',
'lerna.json': 'lerna',
'nx.json': 'nx',
'rush.json': 'rush',
'yarn.lock': 'yarn',
'pnpm-lock.yaml': 'pnpm',
'bun.lockb': 'bun',
'deno.json': 'deno',
'rome.json': 'rome',
'prettier.config.js': 'prettier',
'stylelint.config.js': 'stylelint',
'commitlint.config.js': 'commitlint',
'lint-staged.config.js': 'lint-staged',
'husky.config.js': 'husky',
'.huskyrc': 'husky',
'.lintstagedrc': 'lint-staged',
'.commitlintrc': 'commitlint',
'.stylelintrc': 'stylelint',
'.prettierrc.js': 'prettier',
'.eslintrc': 'eslint',
'.browserslistrc': 'browserslist',
'.npmrc': 'npm',
'.yarnrc': 'yarn',
'.nvmrc': 'nodejs',
'.node-version': 'nodejs',
'.ruby-version': 'ruby',
'.python-version': 'python',
'.tool-versions': 'asdf',
'.editorconfig': 'editorconfig',
'.mailmap': 'email',
'.gitmessage': 'git',
'.gitkeep': 'git',
'brainfuck.config': 'brainfuck',
'awk.config': 'awk',
'sed.config': 'sed',
'perl6.config': 'perl6',
'raku.config': 'perl6',
'julia.config': 'julia',
'crystal.config': 'crystal',
'factor.config': 'factor',
'idris.config': 'idris',
'agda.config': 'agda',
'lean.config': 'lean',
'curry.config': 'curry',
'mercury.config': 'mercury',
'clean.config': 'clean',
'oz.config': 'oz',
'sml.config': 'sml',
'vhdl.config': 'vhdl',
'verilog.config': 'verilog',
'ceylon.config': 'ceylon',
'red.config': 'red',
'rebol.config': 'rebol',
'io.config': 'io',
'j.config': 'j',
'k.config': 'k',
'q.config': 'q',
'pure.config': 'pure',
'ur.config': 'ur',
'fstar.config': 'fstar',
'coq.config': 'coq',
'isabelle.config': 'isabelle',
'hol.config': 'hol',
'mizar.config': 'mizar',
'twelf.config': 'twelf',
'maude.config': 'maude',
'alloy.config': 'alloy',
'tla.config': 'tla',
'z3.config': 'z3',
'smt.config': 'smt',
'why3.config': 'why3',
'acl2.config': 'acl2',
'pvs.config': 'pvs',
'nuprl.config': 'nuprl',
'lego.config': 'lego',
'ats.config': 'ats',
'idris2.config': 'idris2',
'dhall.config': 'dhall',
'unison.config': 'unison',
'koka.config': 'koka',
'grain.config': 'grain',
'gleam.config': 'gleam',
'roc.config': 'roc',
'vale.config': 'vale',
'lobster.config': 'lobster',
'wren.config': 'wren',
'gravity.config': 'gravity',
'virgil.config': 'virgil',
'gluon.config': 'gluon',
'felix.config': 'felix',
'clay.config': 'clay',
'kitten.config': 'kitten',
'pony.config': 'pony',
'reason.config': 'reason',
'purescript.config': 'purescript',
'elm.config': 'elm',
'imba.config': 'imba',
'mint.config': 'mint',
'grain.config': 'grain',
'beef.config': 'beef',
'zig.config': 'zig',
'vlang.config': 'vlang',
'odin.config': 'odin',
'carbon.config': 'carbon',
'mojo.config': 'mojo',
'val.config': 'val',
'hare.config': 'hare',
'ante.config': 'ante',
'kind.config': 'kind',
'dafny.config': 'dafny',
'bosque.config': 'bosque',
'keli.config': 'keli',
'gno.config': 'gno',
'jakt.config': 'jakt',
'hylo.config': 'hylo',
'inko.config': 'inko',
'nickel.config': 'nickel',
'pikelet.config': 'pikelet',
'sixten.config': 'sixten',
'skip.config': 'skip',
'spiral.config': 'spiral',
'verse.config': 'verse',
'wyvern.config': 'wyvern',
'zephyr.config': 'zephyr'
};
iconName = specialFiles[filename] || Object.entries(iconMap).find(([ext]) => filename.toLowerCase().endsWith(ext))?.[1];
if (iconName) {
const oldSvg = element.querySelector('svg');
if (oldSvg) {
const newIcon = document.createElement('img');
newIcon.src = `https://raw.githubusercontent.com/material-extensions/vscode-material-icon-theme/refs/heads/main/icons/${iconName}.svg`;
newIcon.style.cssText = 'width:20px;height:20px;vertical-align:text-bottom;margin-right:4px';
oldSvg.parentNode.replaceChild(newIcon, oldSvg);
}
}
}
});
}
replaceIcons();
const observer = new MutationObserver(replaceIcons);
observer.observe(document.body, {
childList: true,
subtree: true,
});
})();