From e4468b1f01a1e64a7bfb4c69d864603a88c73048 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Wed, 27 Nov 2019 21:34:27 +0800 Subject: [PATCH 1/5] scripts: generate icon index --- scripts/generate-file-icon-index.js | 62 ++++++ scripts/generate-folder-icon-index.js | 41 ++++ scripts/language-id-ext.json | 276 ++++++++++++++++++++++++++ 3 files changed, 379 insertions(+) create mode 100644 scripts/generate-file-icon-index.js create mode 100644 scripts/generate-folder-icon-index.js create mode 100644 scripts/language-id-ext.json diff --git a/scripts/generate-file-icon-index.js b/scripts/generate-file-icon-index.js new file mode 100644 index 0000000..a3fe1b3 --- /dev/null +++ b/scripts/generate-file-icon-index.js @@ -0,0 +1,62 @@ +const languageIds = require('./language-id-ext.json') + +const records = [] + +document.body + .querySelector('table') + .querySelectorAll('tbody tr') + .forEach(tr => { + const [name, id, dark, light] = Array.from(tr.querySelectorAll('td')) + const exts = [] + const names = [] + id.innerHTML + .replace(/|<\/sub>/g, '') + .split(', ') + .map(part => { + const match = part.match(/<(\w+)>(.*?)<\/\1>/) + if (match) { + const [, tag, content] = match + if (tag === 'strong') { + // filenames in bold + names.push(content) + } else if (tag === 'code') { + // language ids in code block + const map = Object.values(languageIds).find(({ ids }) => + (Array.isArray(ids) ? ids : [ids]).includes(content), + ) + if (map && map.exts) exts.push(map.exts) + } else { + console.warn(`Found unrecognized format`, part) // unknown + } + } else if (part) { + // extensions are in regular fonts + exts.push(part.replace(/^\./, '')) + } + }) + records.push({ + name: name.innerText, + exts, + names, + icon: getSrc(dark.querySelector('img')) || getSrc(light.querySelector('img')), + }) + }) + +function getSrc(img) { + return img && img.src +} + +const prepend = 'https://github.com/vscode-icons/vscode-icons/raw/master/icons/file_type_' +const append = '.svg?sanitize=true' +const separator = ':' +const csv = records + .map(({ name, names, exts, icon }) => + [ + name, + names.join(separator), + exts.join(separator), + // icon.replace(prepend, '').replace(append, ''), // assumption: name is equal to this + ].join(','), + ) + .join('\n') + +console.log(csv) diff --git a/scripts/generate-folder-icon-index.js b/scripts/generate-folder-icon-index.js new file mode 100644 index 0000000..8ddd743 --- /dev/null +++ b/scripts/generate-folder-icon-index.js @@ -0,0 +1,41 @@ +function parsePageContent() { + const records = [] + document.body + .querySelector('table') + .querySelectorAll('tbody tr') + .forEach(tr => { + const [name, folderNames, closed, open] = Array.from(tr.querySelectorAll('td')) + const names = folderNames.innerHTML.split(', ') + records.push({ + name: name.innerText, + names, + icon: { + closed: getSrc(closed.querySelector('img')), + open: getSrc(open.querySelector('img')), + }, + }) + }) + return records +} + +function getSrc(img) { + return img && img.src +} + +function generateCSV(records) { + const prepend = 'https://github.com/vscode-icons/vscode-icons/raw/master/icons/folder_type_' + const append = '.svg?sanitize=true' + const separator = ':' + const csv = records + .map(({ name, names, icon }) => + [ + name, + names.join(separator), + // icon.replace(prepend, '').replace(append, ''), // assumption: name is equal to this + ].join(','), + ) + .join('\n') + return csv +} + +console.log(generateCSV(parsePageContent())) diff --git a/scripts/language-id-ext.json b/scripts/language-id-ext.json new file mode 100644 index 0000000..b4254a5 --- /dev/null +++ b/scripts/language-id-ext.json @@ -0,0 +1,276 @@ +{ + "actionscript": { "ids": "nextgenas", "exts": "as" }, + "ada": { "ids": "ada", "exts": "ada" }, + "advpl": { "ids": "advpl", "exts": "prw" }, + "affectscript": { "ids": "affectscript", "exts": "affect" }, + "al": { "ids": "al", "exts": "al" }, + "ansible": { "ids": "ansible", "exts": "ansible" }, + "antlr": { "ids": "antlr", "exts": "g4" }, + "anyscript": { "ids": "anyscript", "exts": "any" }, + "apache": { "ids": "apacheconf", "exts": "htaccess" }, + "apex": { "ids": "apex", "exts": "cls" }, + "apib": { "ids": "apiblueprint", "exts": "apib" }, + "apl": { "ids": "apl", "exts": "apl" }, + "applescript": { "ids": "applescript", "exts": "applescript" }, + "asciidoc": { "ids": "asciidoc", "exts": "adoc" }, + "asp": { "ids": ["asp", "asp (html)"], "exts": "asp" }, + "assembly": { "ids": ["arm", "asm"], "exts": "asm" }, + "ats": { "ids": ["ats"], "exts": "ats" }, + "autohotkey": { "ids": "ahk", "exts": "ahk" }, + "autoit": { "ids": "autoit", "exts": "au3" }, + "avro": { "ids": "avro", "exts": "avcs" }, + "azcli": { "ids": "azcli", "exts": "azcli" }, + "azurepipelines": { + "ids": "azure-pipelines", + "exts": "azure-pipelines.yml" + }, + "ballerina": { "ids": "ballerina", "exts": "bal" }, + "bat": { "ids": "bat", "exts": "bat" }, + "bazel": { "ids": "bazel", "exts": "bzl" }, + "befunge": { "ids": ["befunge", "befunge98"], "exts": "bf" }, + "bibtex": { "ids": "bibtex", "exts": "bib" }, + "biml": { "ids": "biml", "exts": "biml" }, + "blade": { "ids": ["blade", "laravel-blade"], "exts": "blade.php" }, + "bolt": { "ids": "bolt", "exts": "bolt" }, + "c": { "ids": "c", "exts": "c" }, + "c_al": { "ids": "c-al", "exts": "cal" }, + "cabal": { "ids": "cabal", "exts": "cabal" }, + "caddyfile": { "ids": "caddyfile", "exts": "Caddyfile" }, + "ceylon": { "ids": "ceylon", "exts": "ceylon" }, + "cfc": { "ids": "cfc", "exts": "cfc" }, + "cfm": { "ids": "cfmhtml", "exts": "cfm" }, + "clojure": { "ids": "clojure", "exts": "clojure" }, + "clojurescript": { "ids": "clojurescript", "exts": "clojurescript" }, + "cmake": { "ids": "cmake", "exts": "cmake" }, + "cmakecache": { "ids": "cmake-cache", "exts": "CMakeCache.txt" }, + "cobol": { "ids": "cobol", "exts": "cbl" }, + "coffeescript": { "ids": "coffeescript", "exts": "coffee" }, + "coldfusion": { "ids": ["cfml", "lang-cfml"], "exts": "cfml" }, + "confluence": { "ids": ["confluence"], "exts": "confluence" }, + "cookbook": { "ids": "cookbook", "exts": "ckbk" }, + "cpp": { "ids": "cpp", "exts": "cpp" }, + "crystal": { "ids": "crystal", "exts": "cr" }, + "csharp": { "ids": "csharp", "exts": "cs" }, + "css": { "ids": "css", "exts": "css" }, + "cucumber": { "ids": "feature", "exts": "feature" }, + "cuda": { "ids": "cuda", "exts": "cu" }, + "cython": { "ids": "cython", "exts": "pyx" }, + "dal": { "ids": "dal", "exts": "dal" }, + "dart": { "ids": "dart", "exts": "dart" }, + "django": { "ids": ["django-html", "django-txt"], "exts": "html" }, + "diff": { "ids": "diff", "exts": "diff" }, + "dlang": { "ids": ["d", "dscript", "dml", "diet"], "exts": "d" }, + "dockerfile": { "ids": "dockerfile", "exts": "dockerfile" }, + "dockerignore": { "ids": "ignore", "exts": "dockerignore" }, + "doctex": { "ids": "doctex", "exts": "dtx" }, + "dotenv": { "ids": "dotenv", "exts": "env" }, + "dotjs": { "ids": "dotjs", "exts": "dot" }, + "doxygen": { "ids": "doxygen", "exts": "dox" }, + "drools": { "ids": "drools", "exts": "drl" }, + "dylanlang": { "ids": ["dylan", "dylan-lid"], "exts": "dylan" }, + "dustjs": { "ids": "dustjs", "exts": "dust" }, + "edge": { "ids": "edge", "exts": "edge" }, + "eex": { "ids": ["eex", "html-eex"], "exts": "eex" }, + "elastic": { "ids": "es", "exts": "es" }, + "elixir": { "ids": "elixir", "exts": "ex" }, + "elm": { "ids": "elm", "exts": "elm" }, + "erb": { "ids": "erb", "exts": "erb" }, + "erlang": { "ids": "erlang", "exts": "erl" }, + "falcon": { "ids": "falcon", "exts": "falcon" }, + "fortran": { + "ids": ["fortran", "fortran-modern", "FortranFreeForm", "fortran_fixed-form"], + "exts": "f" + }, + "freemarker": { "ids": "ftl", "exts": "ftl" }, + "fsharp": { "ids": "fsharp", "exts": "fs" }, + "galen": { "ids": "galen", "exts": "gspec" }, + "gamemaker": { "ids": "gml-gms", "exts": "gml" }, + "gamemaker2": { "ids": "gml-gms2", "exts": "gml" }, + "gamemaker81": { "ids": "gml-gm81", "exts": "gml" }, + "gcode": { "ids": "gcode", "exts": "gcode" }, + "git": { "ids": ["git-commit", "git-rebase"], "exts": "git" }, + "glsl": { "ids": "glsl", "exts": "glsl" }, + "go": { "ids": "go", "exts": "go" }, + "godot": { "ids": "gdscript", "exts": "gd" }, + "graphql": { "ids": "graphql", "exts": "gql" }, + "graphviz": { "ids": "dot", "exts": "gv" }, + "groovy": { "ids": "groovy", "exts": "groovy" }, + "haml": { "ids": "haml", "exts": "haml" }, + "handlebars": { "ids": "handlebars", "exts": "hbs" }, + "harbour": { "ids": "harbour", "exts": "prg" }, + "haskell": { "ids": "haskell", "exts": "hs" }, + "haxe": { "ids": ["haxe", "hxml", "Haxe AST dump"], "exts": "haxe" }, + "helm": { "ids": "helm", "exts": "helm.tpl" }, + "hjson": { "ids": "hjson", "exts": "hjson" }, + "hlsl": { "ids": "hlsl", "exts": "hlsl" }, + "homeassistant": { "ids": "home-assistant", "exts": "yaml" }, + "hosts": { "ids": "hosts", "exts": "hosts" }, + "html": { "ids": "html", "exts": "html" }, + "http": { "ids": "http", "exts": "http" }, + "hunspell": { "ids": ["hunspell.aff", "hunspell.dic"], "exts": "aff" }, + "icl": { "ids": "icl", "exts": "icl" }, + "imba": { "ids": "imba", "exts": "imba" }, + "informix": { "ids": "4GL", "exts": "4gl" }, + "ini": { "ids": "ini", "exts": "ini" }, + "ink": { "ids": "ink", "exts": "ink" }, + "innosetup": { "ids": "innosetup", "exts": "iss" }, + "io": { "ids": "io", "exts": "io" }, + "latex": { "ids": "latex", "exts": "tex" }, + "janet": { "ids": "janet", "exts": "janet" }, + "java": { "ids": "java", "exts": "java" }, + "javascript": { "ids": "javascript", "exts": "js" }, + "javascriptreact": { "ids": "javascriptreact", "exts": "jsx" }, + "jekyll": { "ids": "jekyll", "exts": "jekyll" }, + "jenkins": { + "ids": ["jenkins", "declarative", "jenkinsfile"], + "exts": "jenkins" + }, + "jinja": { "ids": "jinja", "exts": "jinja" }, + "json": { "ids": "json", "exts": "json" }, + "jsonc": { "ids": "jsonc", "exts": "jsonc" }, + "jsonnet": { "ids": "jsonnet", "exts": "jsonnet" }, + "json5": { "ids": "json5", "exts": "json5" }, + "julia": { "ids": ["julia", "juliamarkdown"], "exts": "jl" }, + "iodine": { "ids": "iodine", "exts": "id" }, + "kivy": { "ids": "kivy", "exts": "kv" }, + "kos": { "ids": "kos", "exts": "ks" }, + "kotlin": { "ids": "kotlin", "exts": "kt" }, + "less": { "ids": "less", "exts": "less" }, + "lisp": { "ids": "lisp", "exts": "lisp" }, + "literatehaskell": { "ids": ["literate haskell"], "exts": "lhs" }, + "lolcode": { "ids": "lolcode", "exts": "lol" }, + "lsl": { "ids": "lsl", "exts": "lsl" }, + "lua": { "ids": "lua", "exts": "lua" }, + "makefile": { "ids": "makefile", "exts": "mk" }, + "markdown": { "ids": "markdown", "exts": "md" }, + "marko": { "ids": "marko", "exts": "marko" }, + "matlab": { "ids": "matlab", "exts": "mat" }, + "maxscript": { "ids": "maxscript", "exts": "ms" }, + "mediawiki": { "ids": "mediawiki", "exts": "mediawiki" }, + "mel": { "ids": "mel", "exts": "mel" }, + "meson": { "ids": "meson", "exts": "meson.build" }, + "mjml": { "ids": "mjml", "exts": "mjml" }, + "mlang": { "ids": ["mlang", "powerquerymlanguage"], "exts": "pq" }, + "mojolicious": { "ids": "mojolicious", "exts": "ep" }, + "mongo": { "ids": "mongo", "exts": "mongo" }, + "mson": { "ids": "mson", "exts": "mson" }, + "nearley": { "ids": "nearley", "exts": "ne" }, + "nim": { "ids": ["nim", "nimble"], "exts": "nim" }, + "nsis": { "ids": ["nsis", "nfl", "nsl", "bridlensis"], "exts": "nsi" }, + "nunjucks": { "ids": "nunjucks", "exts": "nunjucks" }, + "objectivec": { "ids": "objective-c", "exts": "m" }, + "objectivecpp": { "ids": "objective-cpp", "exts": "mm" }, + "ocaml": { "ids": ["ocaml", "ocamllex", "menhir"], "exts": "ml" }, + "openEdge": { "ids": "abl", "exts": "w" }, + "openHAB": { "ids": "openhab", "exts": "things" }, + "pascal": { "ids": ["pascal", "objectpascal"], "exts": "pas" }, + "pddl": { "ids": "pddl", "exts": "pddl" }, + "pddlplan": { "ids": "plan", "exts": "plan" }, + "pddlhappenings": { "ids": "happenings", "exts": "happenings" }, + "perl": { "ids": "perl", "exts": "pl" }, + "perl6": { "ids": "perl6", "exts": "pl6" }, + "pgsql": { "ids": "pgsql", "exts": "pgsql" }, + "php": { "ids": "php", "exts": "php" }, + "pine": { "ids": "pine", "exts": "pine" }, + "pip": { "ids": "pip-requirements", "exts": "requirements.txt" }, + "plaintext": { "ids": "plaintext", "exts": "txt" }, + "platformio": { + "ids": ["platformio-debug.disassembly", "platformio-debug.memoryview", "platformio-debug.asm"], + "exts": "dbgasm" + }, + "plsql": { "ids": ["plsql", "oracle"], "exts": "ddl" }, + "polymer": { "ids": "polymer", "exts": "polymer" }, + "pony": { "ids": "pony", "exts": "pony" }, + "postcss": { "ids": "postcss", "exts": "pcss" }, + "powershell": { "ids": "powershell", "exts": "ps1" }, + "prisma": { "ids": "prisma", "exts": "prisma" }, + "processinglang": { "ids": "pde", "exts": "pde" }, + "prolog": { "ids": "prolog", "exts": "pro" }, + "prometheus": { "ids": "prometheus", "exts": "rules" }, + "properties": { "ids": "properties", "exts": "properties" }, + "protobuf": { "ids": ["proto3", "proto"], "exts": "proto" }, + "pug": { "ids": "jade", "exts": "pug" }, + "puppet": { "ids": "puppet", "exts": "pp" }, + "purescript": { "ids": "purescript", "exts": "purs" }, + "pyret": { "ids": "pyret", "exts": "arr" }, + "python": { "ids": "python", "exts": "py" }, + "qlik": { "ids": "qlik", "exts": "qvs" }, + "qml": { "ids": "qml", "exts": "qml" }, + "qsharp": { "ids": "qsharp", "exts": "qs" }, + "r": { "ids": "r", "exts": "r" }, + "racket": { "ids": "racket", "exts": "rkt" }, + "razor": { "ids": ["razor", "aspnetcorerazor"], "exts": "cshtml" }, + "raml": { "ids": "raml", "exts": "raml" }, + "reason": { "ids": "reason", "exts": "re" }, + "red": { "ids": "red", "exts": "red" }, + "restructuredtext": { "ids": "restructuredtext", "exts": "rst" }, + "riot": { "ids": "riot", "exts": "tag" }, + "robot": { "ids": "robot", "exts": "robot" }, + "ruby": { "ids": "ruby", "exts": "rb" }, + "rust": { "ids": "rust", "exts": "rs" }, + "san": { "ids": "san", "exts": "san" }, + "sbt": { "ids": "sbt", "exts": "sbt" }, + "scala": { "ids": "scala", "exts": "scala" }, + "scilab": { "ids": "scilab", "exts": "sce" }, + "scss": { "ids": "scss", "exts": "scss" }, + "sdlang": { "ids": "sdl", "exts": "sdl" }, + "shaderlab": { "ids": "shaderlab", "exts": "shader" }, + "shellscript": { "ids": "shellscript", "exts": "sh" }, + "slang": { "ids": "slang", "exts": "slang" }, + "slice": { "ids": ["slice"], "exts": "ice" }, + "slim": { "ids": ["slim"], "exts": "slim" }, + "silverstripe": { "ids": "silverstripe", "exts": "ss" }, + "skipper": { "ids": ["eskip"], "exts": "eskip" }, + "smarty": { "ids": ["smarty"], "exts": "tpl" }, + "snort": { "ids": ["snort"], "exts": "snort" }, + "solidity": { "ids": ["solidity"], "exts": "sol" }, + "sqf": { "ids": "sqf", "exts": "sqf" }, + "sql": { "ids": "sql", "exts": "sql" }, + "squirrel": { "ids": "squirrel", "exts": "nut" }, + "stan": { "ids": "stan", "exts": "stan" }, + "stata": { "ids": "stata", "exts": "do" }, + "stencil": { "ids": "stencil", "exts": "stencil" }, + "stencilhtml": { "ids": "stencil-html", "exts": "html.stencil" }, + "stylable": { "ids": "stylable", "exts": "st.css" }, + "styled": { "ids": "source.css.styled", "exts": "styled" }, + "stylus": { "ids": "stylus", "exts": "styl" }, + "svelte": { "ids": "svelte", "exts": "svelte" }, + "swagger": { "ids": ["Swagger", "swagger"], "exts": "swagger" }, + "swift": { "ids": "swift", "exts": "swift" }, + "swig": { "ids": "swig", "exts": "swig" }, + "systemd": { "ids": "systemd-unit-file", "exts": "link" }, + "systemverilog": { "ids": "systemverilog", "exts": "sv" }, + "t4": { "ids": "t4", "exts": "tt" }, + "templatetoolkit": { "ids": "tt", "exts": "tt3" }, + "tera": { "ids": "tera", "exts": "tera" }, + "terraform": { "ids": "terraform", "exts": "tf" }, + "tex": { "ids": "tex", "exts": "sty" }, + "textile": { "ids": "textile", "exts": "textile" }, + "textmatejson": { "ids": "json-tmlanguage", "exts": "JSON-tmLanguage" }, + "textmateyaml": { "ids": "yaml-tmlanguage", "exts": "YAML-tmLanguage" }, + "toml": { "ids": "toml", "exts": "toml" }, + "ttcn": { "ids": "ttcn", "exts": "ttcn3" }, + "twig": { "ids": "twig", "exts": "twig" }, + "typescript": { "ids": "typescript", "exts": "ts" }, + "typescriptreact": { "ids": "typescriptreact", "exts": "tsx" }, + "typo3": { "ids": "typoscript", "exts": "typoscript" }, + "vb": { "ids": "vb", "exts": "vb" }, + "vba": { "ids": "vba", "exts": "cls" }, + "vbscript": { "ids": "vbscript", "exts": "wsf" }, + "velocity": { "ids": "velocity", "exts": "vm" }, + "verilog": { "ids": "verilog", "exts": "v" }, + "vhdl": { "ids": "vhdl", "exts": "vhdl" }, + "viml": { "ids": "viml", "exts": "vim" }, + "vlang": { "ids": "v", "exts": "v" }, + "volt": { "ids": "volt", "exts": "volt" }, + "vue": { "ids": "vue", "exts": "vue" }, + "wasm": { "ids": ["wasm", "wat"], "exts": "wasm" }, + "wolfram": { "ids": "wolfram", "exts": "wl" }, + "wurst": { "ids": ["wurstlang", "wurst"], "exts": "wurst" }, + "wxml": { "ids": "wxml", "exts": "wxml" }, + "xml": { "ids": "xml", "exts": "xml" }, + "xquery": { "ids": "xquery", "exts": "xquery" }, + "xsl": { "ids": "xsl", "exts": "xsl" }, + "yaml": { "ids": "yaml", "exts": "yaml" }, + "yang": { "ids": "yang", "exts": "yang" } +} From 4ac447be2ebec4bce35facb7ca126f19e32d6a65 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Wed, 27 Nov 2019 21:33:33 +0800 Subject: [PATCH 2/5] feat: rich icons --- .gitignore | 1 + package.json | 1 + src/assets/icons/file-icons-index.csv | 648 ++++++++++++++++++++++++ src/assets/icons/folder-icons-index.csv | 125 +++++ src/components/Icon.tsx | 6 +- src/components/Node.tsx | 24 +- src/content.less | 15 +- src/global.d.ts | 5 + src/manifest.json | 19 +- src/utils/parseIconMapCSV.tsx | 67 +++ webpack.config.js | 8 + yarn.lock | 16 + 12 files changed, 915 insertions(+), 20 deletions(-) create mode 100644 src/assets/icons/file-icons-index.csv create mode 100644 src/assets/icons/folder-icons-index.csv create mode 100644 src/utils/parseIconMapCSV.tsx diff --git a/.gitignore b/.gitignore index 92bb6eb..c4ca72a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules tmp dist yarn-error.log +vscode-icons diff --git a/package.json b/package.json index b09af92..42da19c 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "json-loader": "^0.5.7", "less": "^3.9.0", "less-loader": "^4.0.5", + "raw-loader": "^4.0.0", "style-loader": "^0.23.1", "typescript": "^3.7.2", "uglifyjs-webpack-plugin": "^2.1.2", diff --git a/src/assets/icons/file-icons-index.csv b/src/assets/icons/file-icons-index.csv new file mode 100644 index 0000000..91d3c08 --- /dev/null +++ b/src/assets/icons/file-icons-index.csv @@ -0,0 +1,648 @@ +file,, +access,,accdb:accdt:mdb:accda:accdc:accde:accdp:accdr:accdu:ade:adp:laccdb:ldb:mam:maq:mdw +access2,,accdb:accdt:mdb:accda:accdc:accde:accdp:accdr:accdu:ade:adp:laccdb:ldb:mam:maq:mdw +actionscript,,as +actionscript2,,as +ada,,ada +advpl,,prw +ai,,ai +ai2,,ai +al,,al +affinitydesigner,,afdesign:affinitydesigner +affinityphoto,,afphoto:affinityphoto +affinitypublisher,,afpub:affinitypublisher +angular,.angular-cli.json:angular-cli.json:angular.json:.angular.json, +ng_component_dart,,component.dart +ng_component_ts,,component.ts +ng_component_js,,component.js +ng_controller_ts,,controller.ts +ng_controller_js,,controller.js +ng_directive_dart,,directive.dart +ng_directive_ts,,directive.ts +ng_directive_js,,directive.js +ng_guard_dart,,guard.dart +ng_guard_ts,,guard.ts +ng_guard_js,,guard.js +ng_module_dart,,module.dart +ng_module_ts,,module.ts +ng_module_js,,module.js +ng_pipe_dart,,pipe.dart +ng_pipe_ts,,pipe.ts +ng_pipe_js,,pipe.js +ng_routing_dart,,routing.dart +ng_routing_ts,,routing.ts +ng_routing_js,,routing.js +ng_routing_dart,app-routing.module.dart, +ng_routing_ts,app-routing.module.ts, +ng_routing_js,app-routing.module.js, +ng_smart_component_dart,,page.dart:container.dart +ng_smart_component_ts,,page.ts:container.ts +ng_smart_component_js,,page.js:container.js +ng_service_dart,,service.dart +ng_service_ts,,service.ts +ng_service_js,,service.js +ng_interceptor_dart,,interceptor.dart +ng_interceptor_ts,,interceptor.ts +ng_interceptor_js,,interceptor.js +ng_component_ts2,,component.ts +ng_component_js2,,component.js +ng_directive_ts2,,directive.ts +ng_directive_js2,,directive.js +ng_module_ts2,,module.ts +ng_module_js2,,module.js +ng_pipe_ts2,,pipe.ts +ng_pipe_js2,,pipe.js +ng_routing_ts2,,routing.ts +ng_routing_js2,,routing.js +ng_routing_ts2,app-routing.module.ts, +ng_routing_js2,app-routing.module.js, +ng_smart_component_ts2,,page.ts:container.ts +ng_smart_component_js2,,page.js:container.js +ng_service_ts2,,service.ts +ng_service_js2,,service.js +affectscript,,affect +ansible,,ansible +antlr,,g4 +anyscript,,any +apache,,htaccess +apex,,cls +apib,,apib +apl,,apl +applescript,,applescript +appveyor,appveyor.yml:.appveyor.yml, +arduino,,ino:pde +asciidoc,,adoc +asp,,asp:asp +aspx,,aspx:ascx +assembly,,asm:asm +ats,,ats +audio,,aac:act:aiff:amr:ape:au:dct:dss:dvf:flac:gsm:iklax:ivs:m4a:m4b:m4p:mmf:mogg:mp3:mpc:msv:oga:ogg:opus:ra:raw:tta:vox:wav:wma +aurelia,aurelia.json, +autohotkey,,ahk +autoit,,au3 +avro,,avcs +aws,, +azure,,azcli +azurepipelines,azure-pipelines.yml:.vsts-ci.yml,azure-pipelines.yml +babel,.babelrc:babelrc.js:.babelrc.js:babelrc.json:babel.config.js:.babelignore, +babel2,.babelrc:babelrc.js:.babelrc.js:babelrc.json:babel.config.js:.babelignore, +ballerina,,bal +bat,,bat +bazaar,.bzrignore, +bazel,.bazelrc:bazel.rc:bazel.bazelrc,bzl +befunge,,bf:bf +biml,,biml +binary,,a:app:bin:cmo:cmx:cma:cmxa:cmi:dll:exe:hl:ilk:lib:n:ndll:o:obj:pyc:pyd:pyo:pdb:scpt:scptd:so +bithound,.bithoundrc, +bitbucketpipeline,bitbucket-pipelines.yml, +blade,,blade.php:blade.php +bolt,,bolt +bower,.bowerrc:bower.json, +browserslist,.browserslistrc:browserslist, +buckbuild,.buckconfig, +bundler,,gemfile:gemfile.lock +bundler,gemfile:gemfile.lock, +c,,c +c2,,c +c3,,c +c_al,,cal +cabal,,cabal +caddy,,Caddyfile +cake,,cake +cakephp,, +capacitor,capacitor.config.json, +cargo,cargo.toml:cargo.lock, +cert,,csr:crt:cer:der:pfx:p12:p7b:p7r:src:crl:sst:stl +ceylon,,ceylon +cf,,lucee:cfml:cfml +cf2,,lucee:cfml:cfml +cfc,,cfc +cfc2,,cfc +cfm,,cfm +cfm2,,cfm +cheader,,h +chef,chefignore:berksfile:berksfile.lock:policyfile, +class,,class +circleci,circle.yml, +clojure,,cjm:cljc:clojure +clojurescript,,cljs:clojurescript +cloudfoundry,.cfignore, +cmake,,cmake:CMakeCache.txt +cobol,,cbl +codacy,.codacy.yml:.codacy.yaml, +codeclimate,.codeclimate.yml, +codecov,codecov.yml:.codecov.yml, +codekit,,kit +codekit,config.codekit:config.codekit2:config.codekit3:.config.codekit:.config.codekit2:.config.codekit3, +coffeelint,coffeelint.json:.coffeelintignore, +coffeescript,,coffee +conan,conanfile.txt:conanfile.py, +conda,.condarc, +config,,plist:properties:env +compass,, +composer,composer.json:composer.lock, +chef_cookbook,,ckbk +confluence,,confluence +coveralls,.coveralls.yml, +cpp,,cpp +cpp2,,cpp +cpp3,,cpp +cppheader,,hpp +crowdin,crowdin.yml, +crystal,,cr +csharp,,csx:cs +csharp2,,csx:cs +csproj,,csproj +css,,css +csscomb,.csscomb.json, +csslint,.csslintrc, +cssmap,,css.map +cucumber,,feature +cuda,,cu +cython,,pyx +cypress,cypress.json:cypress.env.json, +cvs,.cvsignore, +dal,,dal +darcs,.boringignore, +dartlang,,dart +db,,db +dependencies,dependencies.yml, +delphi,,pas:pas +django,,djt:html:html +dlang,,d:d:d:d +diff,,diff +docker,docker-compose.yml:docker-compose.ci-build.yml:docker-compose.override.yml:docker-compose.vs.debug.yml:docker-compose.vs.release.yml:docker-cloud.yml,dockerignore +docker2,docker-compose.yml:docker-compose.ci-build.yml:docker-compose.override.yml:docker-compose.vs.debug.yml:docker-compose.vs.release.yml:docker-cloud.yml,dockerignore +dockertest,docker-compose.test.yml, +dockertest2,docker-compose.test.yml, +docpad,,eco +docz,.doczrc:docz.js:docz.json:.docz.js:.docz.json:doczrc.js:doczrc.json:docz.config.js:docz.config.json, +dojo,.dojorc, +doxygen,,dox +drone,.drone.yml:.drone.yml.sig, +drools,,drl +dotjs,,dot +dustjs,,dust +dylan,,dylan:dylan +editorconfig,.editorconfig, +edge,,edge +edge2,,edge +eex,,eex:eex +ejs,,ejs +elastic,,es +elasticbeanstalk,, +elixir,,ex +elm,elm-package.json,elm +elm2,elm-package.json,elm +emacs,,el:elc +ember,.ember-cli, +ensime,,ensime +eps,,eps +erb,,erb +erlang,emakefile:.emakerfile,erl +erlang2,emakefile:.emakerfile,erl +eslint,.eslintrc:.eslintignore:.eslintcache:.eslintrc.js:.eslintrc.json:.eslintrc.yaml:.eslintrc.yml, +eslint2,.eslintrc:.eslintignore:.eslintcache:.eslintrc.js:.eslintrc.json:.eslintrc.yaml:.eslintrc.yml, +excel,,xls:xlsx:xlsm:ods:fods +excel2,,xls:xlsx:xlsm:ods:fods +falcon,,falcon +favicon,favicon.ico, +fbx,,fbx +firebase,.firebaserc, +firebasehosting,firebase.json, +firestore,firestore.rules:firestore.indexes.json, +flash,,swf:swc +fla,,fla +floobits,.flooignore, +flow,,js.flow +flow,.flowconfig, +flutter,.flutter-plugins:.metadata, +flutter_package,pubspec.lock:pubspec.yaml:.packages, +font,,woff:woff2:ttf:otf:eot:pfa:pfb:sfd +fortran,,f:f:f:f +fossa,.fossaignore, +fossil,ignore-glob, +fsharp,,fs +fsproj,,fsproj +freemarker,,ftl +fusebox,fuse.js, +galen,,gspec +galen2,,gspec +git,.gitattributes:.gitconfig:.gitignore:.gitmodules:.gitkeep:.mailmap,git:git +gamemaker,,gmx:gml +gamemaker2,,yy:yyp:gml +gamemaker81,,gml +gatsby,gatsby-config.js:gatsby-config.ts:gatsby-node.js:gatsby-node.ts:gatsby-browser.js:gatsby-browser.ts:gatsby-ssr.js:gatsby-ssr.ts, +gcode,,gcode +gitlab,.gitlab-ci.yml, +glide,glide.yml, +glsl,,glsl +go,,go +go_package,go.sum:go.mod, +godot,,gd +gradle,,gradle +graphql,.gqlconfig,gql +graphviz,,gv +greenkeeper,greenkeeper.json, +gridsome,gridsome.config.js:gridsome.config.ts:gridsome.server.js:gridsome.server.ts:gridsome.client.js:gridsome.client.ts, +groovy,,groovy +groovy2,,groovy +grunt,gruntfile.js:gruntfile.coffee:gruntfile.ts:gruntfile.babel.js:gruntfile.babel.coffee:gruntfile.babel.ts, +gulp,gulpfile.js:gulpfile.coffee:gulpfile.ts:gulpfile.babel.js:gulpfile.babel.coffee:gulpfile.babel.ts, +haml,,haml +handlebars,,hbs +handlebars2,,hbs +harbour,,prg +haskell,,hs:lhs +haskell2,,hs:lhs +haxe,haxelib.json,haxe:haxe:haxe +haxecheckstyle,checkstyle.json, +haxedevelop,,hxproj +helix,.p4ignore, +helm,,helm.tpl +hjson,,hjson +hlsl,,hlsl +homeassistant,,yaml +host,,hosts +html,,html +htmlhint,.htmlhintrc, +http,,http +hunspell,,aff:aff +husky,.huskyrc:.huskyrc.js:.huskyrc.json:.huskyrc.yaml:.huskyrc.yml, +icl,,icl +idris,,idr:lidr +idrisbin,,ibc +idrispkg,,ipkg +image,,jpeg:jpg:gif:png:bmp:tiff:ico +imba,,imba +inc,,inc:include +infopath,,infopathxml:xsn:xsf:xtp2 +informix,,4gl +ini,,ini +ink,,ink +innosetup,,iss +ionic,ionic.project:ionic.config.json, +jake,jakefile:jakefile.js, +janet,,janet +jar,,jar +java,,java +jbuilder,,jbuilder +jest,jest.config.js:jest.json:jest.config.json:.jestrc:.jestrc.js:.jestrc.json, +jest_snapshot,,js.snap:jsx.snap:ts.snap:tsx.snap +jekyll,,jekyll +jenkins,,jenkins:jenkins:jenkins +jinja,,jinja +jpm,.jpmignore, +js,,js +js_official,,js +jsbeautify,.jsbeautifyrc:jsbeautifyrc:.jsbeautify:jsbeautify, +jsconfig,jsconfig.json, +jshint,.jshintrc:.jshintignore, +jsmap,,js.map +json,,json:JSON-tmLanguage:jsonc +json_official,,json:JSON-tmLanguage:jsonc +json2,,json:JSON-tmLanguage:jsonc +jsonnet,,jsonnet +json5,,json5:json5 +jsonld,,jsonld:json-ld +jsp,,jsp +jss,,jss +julia,,jl:jl +julia2,,jl:jl +jupyter,,ipynb +io,,io +iodine,,id +karma,karma.conf.js:karma.conf.coffee:karma.conf.ts, +key,,key:pem +kite,.kiteignore, +kitchenci,.kitchen.yml, +kivy,,kv +kos,,ks +kotlin,,kt +layout,,master:layout.html:layout.htm +layout,layout.html:layout.htm, +lerna,lerna.json, +less,,less +license,,enc +license,license:licence:license.md:license.txt:licence.md:licence.txt, +lisp,,lisp +lime,,hxp +lime,include.xml, +lintstagedrc,.lintstagedrc:lint-staged.config.js:.lintstagedrc.js:.lintstagedrc.json:.lintstagedrc.yaml:.lintstagedrc.yml, +liquid,,liquid +livescript,,ls +locale,, +log,,log:tlg +lolcode,,lol +lsl,,lsl +lua,,lua +lync,,crec:ocrec +makefile,,makefile:mk +manifest,manifest, +manifest_skip,manifest.skip, +manifest_bak,manifest.bak, +map,,map +markdown,,mdown:markdown:md +markdownlint,.markdownlint.json, +marko,,marko +markojs,,marko.js +matlab,,fig:mex:mexn:mexrs6:mn:mum:mx:mx3:rwd:slx:slddc:smv:xvc:mat +maxscript,,ms +maven,maven.config:pom.xml:extensions.xml:settings.xml, +maya,,mel +mdx,,mdx +mediawiki,,mediawiki +mercurial,.hgignore, +meson,,meson.build +meteor,, +mjml,,mjml +mlang,,pq:pq +mocha,mocha.opts:.mocharc.js:.mocharc.json:.mocharc.jsonc:.mocharc.yaml:.mocharc.yml, +mojolicious,,ep +moleculer,moleculer.config.js:moleculer.config.json:moleculer.config.ts, +mongo,,mongo +monotone,.mtn-ignore, +mson,,mson +mustache,,mustache:mst +nearly,,ne +nestjs,.nest-cli.json:nest-cli.json:nestconfig.json:.nestconfig.json, +nest_adapter_js,,adapter.js +nest_adapter_ts,,adapter.ts +nest_controller_js,,controller.js +nest_controller_ts,,controller.ts +nest_decorator_js,,decorator.js +nest_decorator_ts,,decorator.ts +nest_filter_js,,filter.js +nest_filter_ts,,filter.ts +nest_gateway_js,,gateway.js +nest_gateway_ts,,gateway.ts +nest_guard_js,,guard.js +nest_guard_ts,,guard.ts +nest_interceptor_js,,interceptor.js +nest_interceptor_ts,,interceptor.ts +nest_middleware_js,,middleware.js +nest_middleware_ts,,middleware.ts +nest_module_js,,module.js +nest_module_ts,,module.ts +nest_pipe_js,,pipe.js +nest_pipe_ts,,pipe.ts +nest_service_js,,service.js +nest_service_ts,,service.ts +netlify,netlify.toml, +nginx,nginx.conf, +nim,,nim:nim +ninja,build.ninja, +njsproj,,njsproj +node,.node-version:.nvmrc, +node2,.node-version:.nvmrc, +nodemon,nodemon.json, +npm,.npmignore:.npmrc:package.json:package-lock.json:npm-shrinkwrap.json, +nsi,,nsi:nsi:nsi:nsi +nsri,.nsrirc:.nsriignore:.nsrirc.js:.nsrirc.json:.nsrirc.yaml:.nsrirc.yml:.nsrirc.config.js, +nsri-integrity,.integrity.json,,nsri-integrity +nuget,,nupkg:nuspec:psmdcp +nunjucks,,nunj:njs:nunjucks +nuxt,nuxt.config.js:nuxt.config.ts, +nyc,.nycrc:.nycrc.json, +objectivec,,m +objectivecpp,,mm +ocaml,.merlin,ml:ml:ml +onenote,,one:onepkg:onetoc:onetoc2:sig +opencl,,cl:opencl +openHAB,,things +org,,org +outlook,,pst:bcmx:otm:msg:oft +ovpn,,ovpn +package,,pkg +paket,paket.dependencies:paket.lock:paket.references:paket.template:paket.local, +patch,,patch +pcl,,pcd +pddl,,pddl +pddl_plan,,plan +pddl_happenings,,happenings +pdf,,pdf +pdf2,,pdf +perl,,pl +perl2,,pl +perl6,,pl6 +pgsql,,pgsql +photoshop,,psd +photoshop2,,psd +php,,php1:php2:php3:php4:php5:php6:phps:phpsa:phpt:phtml:phar:php +php2,,php1:php2:php3:php4:php5:php6:phps:phpsa:phpt:phtml:phar:php +php3,,php1:php2:php3:php4:php5:php6:phps:phpsa:phpt:phtml:phar:php +phpcsfixer,.php_cs:.php_cs.dist, +phpunit,phpunit:phpunit.xml:phpunit.xml.dist, +phraseapp,.phraseapp.yml, +pine,,pine +pip,pipfile:pipfile.lock,requirements.txt +platformio,platformio.ini,dbgasm:dbgasm:dbgasm +plantuml,,pu:plantuml:iuml:puml +plsql,,ddl:ddl +plsql_package,,pck +plsql_package_body,,pkb +plsql_package_header,,pkh +plsql_package_spec,,pks +poedit,,po:mo +polymer,,polymer +pony,,pony +postcss,,pcss +postcssconfig,.postcssrc:.postcssrc.json:.postcssrc.yml:.postcssrc.js:postcss.config.js, +powerpoint,,pot:potx:potm:pps:ppsx:ppsm:ppt:pptx:pptm:pa:ppa:ppam:sldm:sldx +powerpoint2,,pot:potx:potm:pps:ppsx:ppsm:ppt:pptx:pptm:pa:ppa:ppam:sldm:sldx +powershell,,ps1 +powershell_psm,,psm1 +powershell_psd,,psd1 +powershell_format,,format.ps1xml +powershell_types,,types.ps1xml +powershell2,,ps1 +powershell_psm2,,psm1 +powershell_psd2,,psd1 +precommit,.pre-commit-config.yaml, +prettier,.prettierrc:.prettierignore, +prettier,prettier.config.js:prettier.config.ts:prettier.config.coffee, +prettier,.prettierrc.js:.prettierrc.json:.prettierrc.yml:.prettierrc.yaml, +prisma,,prisma +processinglang,,pde +procfile,procfile, +progress,,w +prolog,,pro:P:pro +prometheus,,rules +protobuf,,proto:proto +protractor,protractor.conf.js:protractor.conf.coffee:protractor.conf.ts, +publisher,,pub:puz +puppet,,pp +pug,.jade-lintrc:.pug-lintrc:.jade-lint.json:.pug-lintrc.js:.pug-lintrc.json,pug +purescript,,purs +pyret,,arr +python,,py +pyup,.pyup:.pyup.yml, +q,,q +qbs,,qbs +qlikview,,qvd:qvw:qvs +qml,,qml +qmldir,qmldir, +qsharp,,qs +quasar,quasar.conf.js, +r,,r +racket,,rkt +rails,, +rake,,rake +rake,rakefile, +raml,,raml +razor,,cshtml:cshtml +razzle,razzle.config.js, +reactjs,,jsx +reacttemplate,,rt +reactts,,tsx +reason,,re +red,,red +registry,,reg +rehype,.rehyperc:.rehypeignore:.rehyperc.js:.rehyperc.json:.rehyperc.yml:.rehyperc.yaml, +remark,.remarkrc:.remarkignore:.remarkrc.js:.remarkrc.json:.remarkrc.yml:.remarkrc.yaml, +renovate,.renovaterc:renovate.json:.renovaterc.json, +rest,,rst +retext,.retextrc:.retextignore:.retextrc.js:.retextrc.json:.retextrc.yml:.retextrc.yaml, +riot,,tag +robotframework,,robot +robots,robots.txt, +rollup,rollup.config.js:rollup.config.mjs:rollup.config.coffee:rollup.config.ts:rollup.config.common.js:rollup.config.common.mjs:rollup.config.common.coffee:rollup.config.common.ts:rollup.config.dev.js:rollup.config.dev.mjs:rollup.config.dev.coffee:rollup.config.dev.ts:rollup.config.prod.js:rollup.config.prod.mjs:rollup.config.prod.coffee:rollup.config.prod.ts, +rproj,,rproj +rspec,.rspec, +rubocop,.rubocop.yml:.rubocop_todo.yml, +ruby,,rb +rust,,rs +saltstack,,sls +san,,san +sass,,sass +sbt,,sbt +scala,,scala +script,,wsf +scss,,scssm:scss +scilab,,sce +sdlang,,sdl +sentry,.sentryclirc, +serverless,serverless.yml, +sequelize,.sequelizerc:.sequelizerc.js:.sequelizerc.json, +shaderlab,,shader +shell,,fish:sh +sketch,,sketch +slang,,slang +slice,,ice +slim,,slim +sln,,sln +sln2,,sln +silverstripe,,ss +skipper,,eskip:eskip +smarty,,tpl +snapcraft,snapcraft.yaml, +snort,,snort +snyk,.snyk, +solidarity,.solidarity:.solidarity.json, +solidity,,sol +source,, +sqf,,sqf +sql,,sql +sqlite,,sqlite:sqlite3:db3 +squirrel,,nut +sss,,sss +stan,,stan +stata,,dta:do +stencil,,stencil:html.stencil +style,, +stylelint,.stylelintrc:.stylelintignore:.stylelintcache:stylelint.config.js:stylelint.config.json:stylelint.config.yaml:stylelint.config.yml:stylelint.config.ts:.stylelintrc.js:.stylelintrc.json:.stylelintrc.yaml:.stylelintrc.yml:.stylelintrc.ts, +stylable,,st.css +styled,,styled +stylus,,styl +storyboard,,storyboard +storybook,,story.js:story.jsx:story.ts:story.tsx:stories.js:stories.jsx:stories.ts:stories.tsx +subversion,.svnignore, +svelte,,svelte +svg,,svg +swagger,,swagger:swagger +swift,package.pins,swift +swig,,swig +symfony,symfony.lock, +systemd,,link +systemverilog,,sv +t4tt,,tt +tailwind,tailwind.js:tailwind.coffee:tailwind.ts:tailwind.config.js:tailwind.config.coffee:tailwind.config.ts, +tt,,tt2:tt3 +tcl,,tcl:exp +tera,,tera +terraform,,tfstate:tf +test,,tst +testjs,,test.js:test.jsx:test.mjs:spec.js:spec.jsx:spec.mjs +testts,,test.ts:test.tsx:spec.ts:spec.tsx:e2e-test.ts:e2e-test.tsx:e2e-spec.ts:e2e-spec.tsx +tex,,texi:tikz:sty:tex:bib:dtx +text,,csv:txt +textile,,textile +tfs,.tfignore, +todo,,todo +toml,,toml +tox,.ini, +travis,.travis.yml, +tsconfig,tsconfig.json:tsconfig.app.json:tsconfig.spec.json:tsconfig.e2e.json:tsconfig.base.json:tsconfig.common.json:tsconfig.dev.json:tsconfig.development.json:tsconfig.staging.json:tsconfig.test.json:tsconfig.prod.json:tsconfig.production.json, +tslint,tslint.json:tslint.yaml:tslint.yml, +ttcn,,ttcn3 +twig,,twig +typescript,,ts +typescript_official,,ts +typescriptdef,,d.ts +typescriptdef_official,,d.ts +typo3,,typoscript +unibeautify,.unibeautifyrc:unibeautify.config.js:.unibeautifyrc.js:.unibeautifyrc.json:.unibeautifyrc.yaml:.unibeautifyrc.yml, +vagrant,vagrantfile, +vala,,vala +vapi,,vapi +vash,,vash +vb,,vb +vba,,cls +vbhtml,,vbhtml +vbproj,,vbproj +vcxproj,,vcxproj +velocity,,vm +verilog,,v +vhdl,,vhdl +video,,3g2:3gp:asf:amv:avi:divx:qt:f4a:f4b:f4p:f4v:flv:m2v:m4v:mkv:mk3d:mov:mp2:mp4:mpe:mpeg:mpeg2:mpg:mpv:nsv:ogv:rm:rmvb:svi:vob:webm:wmv +view,, +vim,.vimrc:.gvimrc,vim +vlang,,v +volt,,volt +vscode,.vscodeignore:launch.json:tasks.json:vscodeignore.json, +vscode2,.vscodeignore:launch.json:tasks.json:vscodeignore.json, +vscode3,.vscodeignore:launch.json:tasks.json:vscodeignore.json, +vscode-insiders,.vscodeignore:launch.json:tasks.json:vscodeignore.json,,vscode-insiders +vsix,,vsix +vsixmanifest,,vsixmanifest +vue,,vue +vueconfig,.vuerc:vue.config.js, +wallaby,wallaby.json:wallaby.js:wallaby.ts:wallaby.coffee:wallaby.conf.json:wallaby.conf.js:wallaby.conf.ts:wallaby.conf.coffee:.wallaby.json:.wallaby.js:.wallaby.ts:.wallaby.coffee:.wallaby.conf.json:.wallaby.conf.js:.wallaby.conf.ts:.wallaby.conf.coffee, +watchmanconfig,.watchmanconfig, +wasm,,wasm:wasm:wasm +webp,,webp +webpack,webpack.base.conf.js:webpack.base.conf.coffee:webpack.base.conf.ts:webpack.common.js:webpack.common.coffee:webpack.common.ts:webpack.config.js:webpack.config.coffee:webpack.config.ts:webpack.config.base.js:webpack.config.base.coffee:webpack.config.base.ts:webpack.config.common.js:webpack.config.common.coffee:webpack.config.common.ts:webpack.config.dev.js:webpack.config.dev.coffee:webpack.config.dev.ts:webpack.config.development.js:webpack.config.development.coffee:webpack.config.development.ts:webpack.config.staging.js:webpack.config.staging.coffee:webpack.config.staging.ts:webpack.config.test.js:webpack.config.test.coffee:webpack.config.test.ts:webpack.config.prod.js:webpack.config.prod.coffee:webpack.config.prod.ts:webpack.config.production.js:webpack.config.production.coffee:webpack.config.production.ts:webpack.config.babel.js:webpack.config.babel.coffee:webpack.config.babel.ts:webpack.config.base.babel.js:webpack.config.base.babel.coffee:webpack.config.base.babel.ts:webpack.config.common.babel.js:webpack.config.common.babel.coffee:webpack.config.common.babel.ts:webpack.config.dev.babel.js:webpack.config.dev.babel.coffee:webpack.config.dev.babel.ts:webpack.config.development.babel.js:webpack.config.development.babel.coffee:webpack.config.development.babel.ts:webpack.config.staging.babel.js:webpack.config.staging.babel.coffee:webpack.config.staging.babel.ts:webpack.config.test.babel.js:webpack.config.test.babel.coffee:webpack.config.test.babel.ts:webpack.config.prod.babel.js:webpack.config.prod.babel.coffee:webpack.config.prod.babel.ts:webpack.config.production.babel.js:webpack.config.production.babel.coffee:webpack.config.production.babel.ts:webpack.dev.js:webpack.dev.coffee:webpack.dev.ts:webpack.dev.conf.js:webpack.dev.conf.coffee:webpack.dev.conf.ts:webpack.prod.js:webpack.prod.coffee:webpack.prod.ts:webpack.prod.conf.js:webpack.prod.conf.coffee:webpack.prod.conf.ts:webpack.mix.js:webpack.mix.coffee:webpack.mix.ts:webpack.test.conf.js:webpack.test.conf.coffee:webpack.test.conf.ts, +wercker,wercker.yml, +wolfram,,wl +word,,doc:docx:docm:dot:dotx:dotm:wll +word2,,doc:docx:docm:dot:dotx:dotm:wll +wpml,wpml-config.xml, +wurst,,wurst:wurst +wxml,,wxml +wxss,,wxss +xcode,,xcodeproj +xfl,,xfl +xib,,xib +xliff,,xliff:xlf +xml,,pex:tmlanguage:xml +xquery,,xquery +xsl,,xsl +yaml,,yaml:YAML-tmLanguage +yamllint,.yamllint, +yandex,.yaspellerrc:.yaspeller.json, +yang,,yang +yarn,yarn.lock:.yarnrc:.yarnclean:.yarn-integrity:.yarn-metadata.json:.yarnignore, +yeoman,.yo-rc.json, +zeit,now.json:.nowignore, +zip,,zip:rar:7z:tar:gz:bzip2:xz:bz2 +zip2,,zip:rar:7z:tar:gz:bzip2:xz:bz2 diff --git a/src/assets/icons/folder-icons-index.csv b/src/assets/icons/folder-icons-index.csv new file mode 100644 index 0000000..234657c --- /dev/null +++ b/src/assets/icons/folder-icons-index.csv @@ -0,0 +1,125 @@ +folder, +root_folder, +android,android +api,api:.api +app,app:.app +arangodb,arangodb:arango +asset,assets:.assets +aurelia,aurelia_project +audio,audio:.audio:audios:.audios:sound:.sound:sounds:.sounds +aws,aws:.aws +azure,azure:.azure +azurepipelines,azure-pipelines:.azure-pipelines +binary,bin:.bin +blueprint,blueprint:.blueprint:blueprints:.blueprints +bower,bower_components +buildkite,.buildkite +cake,cake:.cake +certificate,certificates:.certificates:certs:certs. +chef,chef:.chef +circleci,.circleci +controller,controllers:.controllers:handlers:.handlers +component,components:.components:widgets +composer,composer:.composer +cli,cli:cmd:command:commands:commandline:console +client,client +cmake,.cmake:cmake +config,config:.config:configs:.configs:configuration:.configuration:configurations:.configurations:setting:.setting:settings:.settings:ini:.ini:initializers:.initializers +coverage,coverage +css,css:_css +cypress,cypress +db,db:database:sql:data:repo:repository:repositories +debian,debian +dist,dist:dists:out:outs:export:exports:build:builds:release:releases:target:targets +docker,docker:.docker +docs,docs:doc +e2e,e2e +elasticbeanstalk,.elasticbeanstalk:.ebextensions +electron,electron +favicon,favicon:favicons +flow,flow:flow-typed +fonts,fonts:font:fnt +gcp,gcp:.gcp +git,.git:submodules:.submodules +github,.github +gitlab,.gitlab +gradle,gradle:.gradle +graphql,graphql +grunt,grunt +gulp,gulp:gulpfile.js:gulpfile.coffee:gulpfile.ts:gulpfile.babel.js:gulpfile.babel.coffee:gulpfile.babel.ts +haxelib,.haxelib:haxe_libraries +helper,helpers:.helpers +idea,.idea +images,images:image:img:icons:icon:ico:screenshot:screenshots:svg +include,include:includes:incl:inc:.include:.includes:.incl:.inc:_include:_includes:_incl:_inc +interfaces,interfaces +ios,ios +js,js +json,json +json_official,json +kubernetes,kubernetes:k8s:kube:kuber:.kubernetes:.k8s:.kube:.kuber +less,less:_less +library,lib:.lib:library +linux,linux +locale,lang:language:languages:locale:locales:_locale:_locales:internationalization:globalization:localization:i18n:g11n:l10n +log,log:logs +macos,macos:darwin +mariadb,mariadb:maria +maven,.mvn +memcached,memcached:.memcached +middleware,middleware +mjml,mjml:.mjml +minikube,minikube:minik8s:minikuber +mock,mocks:.mocks:__mocks__ +model,models:.models:entities:.entities +module,modules +mongodb,mongodb:mongo +mysql,mysqldb:mysql +nginx,nginx:conf.d +node,node_modules +notification,notification:notifications:event:events +nuget,.nuget +package,package:packages:.package:.packages:pkg +paket,.paket +php,php +platformio,.pio:.pioenvs +plugin,plugin:.plugin:plugins:.plugins:extension:.extension:extensions:.extensions +private,private:.private +public,public:.public +python,.venv:.virtualenv +redis,redis +ravendb,ravendb +route,route:routes:_route:_routes:routers +redux,redux +meteor,.meteor +sass,sass:scss:_sass:_scss +script,script:scripts +server,server +services,services +src,src:source:sources +sso,sso +story,stories:__stories__ +style,style:styles +test,tests:.tests:test:.test:__tests__:__test__:spec:.spec:specs:.specs +temp,temp:.temp:tmp:.tmp +template,template:.template:templates:.templates +theme,theme:themes +travis,.travis +tools,tools:.tools:util:utils +typescript,typescript:ts +typings,typings:@types +typings2,typings:@types +vagrant,vagrant:.vagrant +video,video:.video:videos:.videos +view,html:view:views:layout:layouts:page:pages:_view:_views:_layout:_layouts:_page:_pages +vs,.vs +vs2,.vs +vscode,.vscode:vscode +vscode2,.vscode:vscode +vscode3,.vscode:vscode +vscode_test,.vscode-test +vscode_test2,.vscode-test +vscode_test3,.vscode-test +webpack,webpack +windows,windows:win32 +www,www:wwwroot diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index 5ffd0e4..71499e5 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -1,5 +1,6 @@ import Octicon, { ChevronDown, + ChevronRight, File, FileCode, FileMedia, @@ -12,7 +13,6 @@ import Octicon, { Markdown, Octoface, Reply, - TriangleRight, X, } from '@primer/octicons-react' import * as React from 'react' @@ -57,8 +57,8 @@ function getSVGIconComponent( } case 'folder': return { - IconComponent: TriangleRight, - name: 'TriangleRight', + IconComponent: ChevronRight, + name: 'ChevronRight', } case 'go-to': return { diff --git a/src/components/Node.tsx b/src/components/Node.tsx index 943e9bc..f978e1b 100644 --- a/src/components/Node.tsx +++ b/src/components/Node.tsx @@ -1,8 +1,9 @@ -import { Icon } from 'components/Icon' import * as React from 'react' import { cx } from 'utils/cx' import { OperatingSystems, os } from 'utils/general' import { TreeNode } from 'utils/VisibleNodesGenerator' +import { getFileIconSrc, getFolderIconSrc } from '../utils/parseIconMapCSV' +import { Icon } from './Icon' function getIconType(node: TreeNode) { switch (node.type) { @@ -54,7 +55,7 @@ export function Node({ node, depth, expanded, focused, renderActions, style, onC style={{ paddingLeft: `${10 + 20 * depth}px` }} >
- + {name}
{renderActions &&
{renderActions(node)}
} @@ -63,3 +64,22 @@ export function Node({ node, depth, expanded, focused, renderActions, style, onC ) } + +const NodeItemIcon = React.memo(function NodeItemIcon({ + node, + open = false, +}: { + node: TreeNode + open?: boolean +}) { + const src = React.useMemo( + () => (node.type === 'tree' ? getFolderIconSrc(node, open) : getFileIconSrc(node)), + [open], + ) + return ( + <> + {node.type !== 'blob' && } + {node.name} + + ) +}) diff --git a/src/content.less b/src/content.less index dbea7de..ec998e8 100644 --- a/src/content.less +++ b/src/content.less @@ -358,8 +358,21 @@ transition: all 0.5s ease; white-space: nowrap; + &-icon { + width: 16px; + height: 16px; + object-fit: contain; + vertical-align: middle; + padding-left: 6px; + box-sizing: content-box; + + &.dim { + filter: sepia(1) hue-rotate(180deg); + } + } + // folder icon rotate when expand - &.expanded .octicon.TriangleRight { + &.expanded .octicon.ChevronRight { transform: rotate(90deg); } diff --git a/src/global.d.ts b/src/global.d.ts index fac9ed3..4c6539f 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -7,3 +7,8 @@ type PartialValSet = { val: T set: (val: Partial) => void } + +declare module '*.csv' { + const content: string + export default content +} diff --git a/src/manifest.json b/src/manifest.json index 3bab0e5..965775f 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -8,21 +8,12 @@ "128": "icons/Gitako-128x128.png" }, "homepage_url": "https://github.com/EnixCoda/Gitako", - "permissions": [ - "storage", - "*://*.github.com/*", - "*://*.sentry.io/*" - ], + "permissions": ["storage", "*://*.github.com/*", "*://*.sentry.io/*"], + "web_accessible_resources": ["icons/vscode/*"], "content_scripts": [ { - "matches": [ - "https://github.com/*" - ], - "js": [ - "firefox-shim.js", - "browser-polyfill.js", - "content.js" - ] + "matches": ["https://github.com/*"], + "js": ["firefox-shim.js", "browser-polyfill.js", "content.js"] } ] -} \ No newline at end of file +} diff --git a/src/utils/parseIconMapCSV.tsx b/src/utils/parseIconMapCSV.tsx new file mode 100644 index 0000000..28ce618 --- /dev/null +++ b/src/utils/parseIconMapCSV.tsx @@ -0,0 +1,67 @@ +import rawFileIconIndex from 'assets/icons/file-icons-index.csv' +import rawFolderIconIndex from 'assets/icons/folder-icons-index.csv' +import { TreeNode } from 'utils/VisibleNodesGenerator' + +function parseFileIconMapCSV() { + const filenameIndex = new Map() + const fileExtensionIndex = new Map() + rawFileIconIndex.split('\n').forEach(line => { + if (!line) return + const [name, names, exts] = line.split(',') + if (names) { + names.split(':').forEach(filename => { + if (!filename) return + filenameIndex.set(filename, name) + }) + } + if (exts) { + exts.split(':').forEach(ext => { + if (!ext) return + fileExtensionIndex.set(ext, name) + }) + } + }) + return { + filenameIndex, + fileExtensionIndex, + } +} + +function parseFolderIconMapCSV() { + const folderNameIndex = new Map() + rawFolderIconIndex.split('\n').forEach(line => { + if (!line) return + const [name, names] = line.split(',') + names.split(':').forEach(folderName => { + if (!folderName) return + folderNameIndex.set(folderName, name) + }) + }) + return { + folderNameIndex, + } +} + +const { folderNameIndex } = parseFolderIconMapCSV() + +export function getFolderIconSrc(node: TreeNode, open: boolean) { + const name = folderNameIndex.get(node.name.toLowerCase()) + return getIconSrc('folder', name, open) +} + +const { filenameIndex, fileExtensionIndex } = parseFileIconMapCSV() + +export function getFileIconSrc(node: TreeNode) { + const name = + filenameIndex.get(node.name.toLowerCase()) || + fileExtensionIndex.get((node.name.split('.').pop() as string).toLowerCase()) + return getIconSrc('file', name) +} + +export function getIconSrc(type: 'folder' | 'file', name: string = 'default', open?: boolean) { + const filename = + (name === 'default' ? 'default_' + type : type + '_type_' + name) + + (open ? '_opened' : '') + + '.svg' + return browser.runtime.getURL(`icons/vscode/${filename}`) +} diff --git a/webpack.config.js b/webpack.config.js index a3d34fd..bd7bdb0 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -18,6 +18,10 @@ const plugins = [ from: './src/assets/icons/*', to: 'icons/[name].[ext]', }, + { + from: './vscode-icons/icons/*', + to: 'icons/vscode/[name].[ext]', + }, { from: 'node_modules/webextension-polyfill/dist/browser-polyfill.js', to: 'browser-polyfill.js', @@ -79,6 +83,10 @@ module.exports = { resourceQuery: /inline/, loader: ['url-loader'], }, + { + test: /\.csv$/, + loader: ['raw-loader'], + }, { test: /\.json$/, loader: ['json-loader'], diff --git a/yarn.lock b/yarn.lock index 6e4f4f7..c32608c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6450,6 +6450,14 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +raw-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-4.0.0.tgz#d639c40fb9d72b5c7f8abc1fb2ddb25b29d3d540" + integrity sha512-iINUOYvl1cGEmfoaLjnZXt4bKfT2LJnZZib5N/LLyAphC+Dd11vNP9CNVb38j+SAJpFI1uo8j9frmih53ASy7Q== + dependencies: + loader-utils "^1.2.3" + schema-utils "^2.5.0" + rc@^1.2.7, rc@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -6948,6 +6956,14 @@ schema-utils@^1.0.0: ajv-errors "^1.0.0" ajv-keywords "^3.1.0" +schema-utils@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-2.5.0.tgz#8f254f618d402cc80257486213c8970edfd7c22f" + integrity sha512-32ISrwW2scPXHUSusP8qMg5dLUawKkyV+/qIEV9JdXKx+rsM6mi8vZY8khg2M69Qom16rtroWXD3Ybtiws38gQ== + dependencies: + ajv "^6.10.2" + ajv-keywords "^3.4.1" + screenfull@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.0.tgz#5c2010c0e84fd4157bf852877698f90b8cbe96f6" From 255aa7eb1d7ba31da913c497f790b1c699b37524 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 1 Dec 2019 21:39:09 +0800 Subject: [PATCH 3/5] refactor: align item with icon --- src/components/Icon.tsx | 5 ++++- src/components/Node.tsx | 4 ++-- src/content.less | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/components/Icon.tsx b/src/components/Icon.tsx index 71499e5..eaaf357 100644 --- a/src/components/Icon.tsx +++ b/src/components/Icon.tsx @@ -120,10 +120,12 @@ function getSVGIconComponent( type Props = { type: string className?: string + placeholder?: boolean onClick?: (event: React.MouseEvent) => void } -export function Icon({ type, className = undefined, ...otherProps }: Props) { +export function Icon({ type, className = undefined, placeholder, ...otherProps }: Props) { + if (placeholder) return
const { name, IconComponent } = getSVGIconComponent(type) const mergedClassName = cx('octicon', name) return ( @@ -131,6 +133,7 @@ export function Icon({ type, className = undefined, ...otherProps }: Props) { {React.createElement(Octicon, { icon: IconComponent, className: mergedClassName, + verticalAlign: 'middle', })}
) diff --git a/src/components/Node.tsx b/src/components/Node.tsx index f978e1b..d429ddf 100644 --- a/src/components/Node.tsx +++ b/src/components/Node.tsx @@ -78,8 +78,8 @@ const NodeItemIcon = React.memo(function NodeItemIcon({ ) return ( <> - {node.type !== 'blob' && } - {node.name} + + {node.type !== 'commit' && {node.name}} ) }) diff --git a/src/content.less b/src/content.less index ec998e8..6e34e52 100644 --- a/src/content.less +++ b/src/content.less @@ -363,7 +363,7 @@ height: 16px; object-fit: contain; vertical-align: middle; - padding-left: 6px; + padding-left: 4px; box-sizing: content-box; &.dim { From eab2790d038c90cc27ac50ace9173e90a369b68e Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 1 Dec 2019 21:59:54 +0800 Subject: [PATCH 4/5] refactor: destruct settings bar --- src/components/SettingsBar.tsx | 161 +++--------------- .../{MoreOption.tsx => SimpleToggleField.tsx} | 17 +- .../settings/AccessTokenSettings.tsx | 103 +++++++++++ src/components/settings/ShortcutSettings.tsx | 56 ++++++ 4 files changed, 183 insertions(+), 154 deletions(-) rename src/components/{MoreOption.tsx => SimpleToggleField.tsx} (73%) create mode 100644 src/components/settings/AccessTokenSettings.tsx create mode 100644 src/components/settings/ShortcutSettings.tsx diff --git a/src/components/SettingsBar.tsx b/src/components/SettingsBar.tsx index b9f461e..2c365b8 100644 --- a/src/components/SettingsBar.tsx +++ b/src/components/SettingsBar.tsx @@ -1,14 +1,14 @@ import { Icon } from 'components/Icon' -import { useConfigs } from 'containers/ConfigsContext' -import { oauth, VERSION } from 'env' +import { VERSION } from 'env' import * as React from 'react' -import { friendlyFormatShortcut } from 'utils/general' +import { Config } from 'utils/configHelper' import { useStates } from 'utils/hooks' -import * as keyHelper from 'utils/keyHelper' -import { SimpleField, SimpleFieldInput } from './MoreOption' +import { AccessTokenSettings } from './settings/AccessTokenSettings' +import { ShortcutSettings } from './settings/ShortcutSettings' +import { SimpleToggleField } from './SimpleToggleField' const WIKI_HOME_LINK = 'https://github.com/EnixCoda/Gitako/wiki' -const wikiLinks = { +export const wikiLinks = { compressSingletonFolder: `${WIKI_HOME_LINK}/Compress-Singleton-Folder`, changeLog: `${WIKI_HOME_LINK}/Change-Log`, copyFileButton: `${WIKI_HOME_LINK}/Copy-file-and-snippet`, @@ -16,13 +16,22 @@ const wikiLinks = { createAccessToken: `${WIKI_HOME_LINK}/How-to-create-access-token-for-Gitako%3F`, } -const ACCESS_TOKEN_REGEXP = /^[0-9a-f]{40}$/ - type Props = { activated: boolean toggleShowSettings: () => void } +export type SimpleField = { + key: keyof Config + label: string + wikiLink?: string + description?: string + overwrite?: { + value: (value: T) => boolean + onChange: (checked: boolean) => any + } +} + const moreFields: SimpleField[] = [ { key: 'compressSingletonFolder', @@ -51,149 +60,21 @@ const moreFields: SimpleField[] = [ ] function SettingsBarContent() { - const configContext = useConfigs() - const hasAccessToken = Boolean(configContext.val.access_token) - const useAccessToken = useStates('') - const useAccessTokenHint = useStates('') - const useShortcutHint = useStates('') - const useToggleShowSideBarShortcut = useStates(configContext.val.shortcut) const useReloadHint = useStates('') - - const { val: accessTokenHint } = useAccessTokenHint - const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut - const { val: shortcutHint } = useShortcutHint - const { val: accessToken } = useAccessToken const { val: reloadHint } = useReloadHint - React.useEffect(() => { - useToggleShowSideBarShortcut.set(configContext.val.shortcut) - }, [configContext.val.shortcut]) - - React.useEffect(() => { - // clear input when access token updates - useAccessToken.set('') - }, [configContext.val.access_token]) - - const onInputAccessToken = React.useCallback( - ({ currentTarget: { value } }: React.FormEvent) => { - useAccessToken.set(value) - useAccessTokenHint.set( - ACCESS_TOKEN_REGEXP.test(value) ? '' : 'This token is in unknown format.', - ) - }, - [], - ) - - const onPressAccessToken = React.useCallback(({ key }: React.KeyboardEvent) => { - if (key === 'Enter') saveToken() - }, []) - - const saveToken = React.useCallback( - async (hint?: typeof useAccessTokenHint.val) => { - if (accessToken) { - configContext.set({ access_token: accessToken }) - useAccessToken.set('') - useAccessTokenHint.set( - hint || ( - - window.location.reload()}> - Reload - {' '} - to activate! - - ), - ) - } - }, - [accessToken], - ) - - const saveShortcut = React.useCallback(async () => { - const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut - configContext.set({ shortcut: toggleShowSideBarShortcut }) - if (typeof toggleShowSideBarShortcut === 'string') { - useShortcutHint.set('Shortcut is saved!') - } - }, [useToggleShowSideBarShortcut.val]) - - const onShortCutInputKeyDown = React.useCallback((e: React.KeyboardEvent) => { - e.preventDefault() - e.stopPropagation() - // Clear shortcut with backspace - const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e) - useToggleShowSideBarShortcut.set(shortcut) - }, []) - return ( <>

Settings

-
-

- Access Token{' '} - - (?) - -

- {!hasAccessToken && ( - { - // use js here to make sure redirect_uri is latest url - const url = `https://github.com/login/oauth/authorize?client_id=${ - oauth.clientId - }&scope=repo&redirect_uri=${encodeURIComponent(window.location.href)}` - window.location.href = url - }} - > - Create with OAuth (recommended) - - )} -
- - {hasAccessToken && !accessToken ? ( - - ) : ( - - )} -
- {accessTokenHint && {accessTokenHint}} -
-
-

Toggle Shortcut

- Set a combination of keys for toggling Gitako sidebar. -
-
- - -
- {shortcutHint && {shortcutHint}} -
+ +
-

More Options

+

More

{moreFields.map(field => ( - +
))} diff --git a/src/components/MoreOption.tsx b/src/components/SimpleToggleField.tsx similarity index 73% rename from src/components/MoreOption.tsx rename to src/components/SimpleToggleField.tsx index 65a9d66..62aeeed 100644 --- a/src/components/MoreOption.tsx +++ b/src/components/SimpleToggleField.tsx @@ -1,25 +1,14 @@ import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' -import { Config } from 'utils/configHelper' - -export type SimpleField = { - key: keyof Config - label: string - wikiLink?: string - description?: string - overwrite?: Props['overwrite'] -} +import { SimpleField } from './SettingsBar' type Props = { field: SimpleField onChange?(): void - overwrite?: { - value: (value: T) => boolean - onChange: (checked: boolean) => any - } } -export function SimpleFieldInput({ field, overwrite, onChange }: Props) { +export function SimpleToggleField({ field, onChange }: Props) { + const { overwrite } = field const configContext = useConfigs() const value = configContext.val[field.key] return ( diff --git a/src/components/settings/AccessTokenSettings.tsx b/src/components/settings/AccessTokenSettings.tsx new file mode 100644 index 0000000..8aa9c2b --- /dev/null +++ b/src/components/settings/AccessTokenSettings.tsx @@ -0,0 +1,103 @@ +import { wikiLinks } from 'components/SettingsBar' +import { useConfigs } from 'containers/ConfigsContext' +import { oauth } from 'env' +import * as React from 'react' +import { useStates } from 'utils/hooks' + +const ACCESS_TOKEN_REGEXP = /^[0-9a-f]{40}$/ + +type Props = {} + +export function AccessTokenSettings(props: React.PropsWithChildren) { + const configContext = useConfigs() + const hasAccessToken = Boolean(configContext.val.access_token) + const useAccessToken = useStates('') + const useAccessTokenHint = useStates('') + + const { val: accessTokenHint } = useAccessTokenHint + const { val: accessToken } = useAccessToken + + React.useEffect(() => { + // clear input when access token updates + useAccessToken.set('') + }, [configContext.val.access_token]) + + const onInputAccessToken = React.useCallback( + ({ currentTarget: { value } }: React.FormEvent) => { + useAccessToken.set(value) + useAccessTokenHint.set( + ACCESS_TOKEN_REGEXP.test(value) ? '' : 'This token is in unknown format.', + ) + }, + [], + ) + + const onPressAccessToken = React.useCallback(({ key }: React.KeyboardEvent) => { + if (key === 'Enter') saveToken() + }, []) + + const saveToken = React.useCallback( + async (hint?: typeof useAccessTokenHint.val) => { + if (accessToken) { + configContext.set({ access_token: accessToken }) + useAccessToken.set('') + useAccessTokenHint.set( + hint || ( + + window.location.reload()}> + Reload + {' '} + to activate! + + ), + ) + } + }, + [accessToken], + ) + + return ( +
+

+ Access Token{' '} + + (?) + +

+ {!hasAccessToken && ( + { + // use js here to make sure redirect_uri is latest url + const url = `https://github.com/login/oauth/authorize?client_id=${ + oauth.clientId + }&scope=repo&redirect_uri=${encodeURIComponent(window.location.href)}` + window.location.href = url + }} + > + Create with OAuth (recommended) + + )} +
+ + {hasAccessToken && !accessToken ? ( + + ) : ( + + )} +
+ {accessTokenHint && {accessTokenHint}} +
+ ) +} diff --git a/src/components/settings/ShortcutSettings.tsx b/src/components/settings/ShortcutSettings.tsx new file mode 100644 index 0000000..f7454b0 --- /dev/null +++ b/src/components/settings/ShortcutSettings.tsx @@ -0,0 +1,56 @@ +import { useConfigs } from 'containers/ConfigsContext' +import * as React from 'react' +import { friendlyFormatShortcut } from 'utils/general' +import { useStates } from 'utils/hooks' +import * as keyHelper from 'utils/keyHelper' + +type Props = {} + +export function ShortcutSettings(props: React.PropsWithChildren) { + const configContext = useConfigs() + const useShortcutHint = useStates('') + const useToggleShowSideBarShortcut = useStates(configContext.val.shortcut) + const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut + const { val: shortcutHint } = useShortcutHint + + React.useEffect(() => { + useToggleShowSideBarShortcut.set(configContext.val.shortcut) + }, [configContext.val.shortcut]) + + const saveShortcut = React.useCallback(async () => { + const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut + configContext.set({ shortcut: toggleShowSideBarShortcut }) + if (typeof toggleShowSideBarShortcut === 'string') { + useShortcutHint.set('Shortcut is saved!') + } + }, [useToggleShowSideBarShortcut.val]) + + const onShortCutInputKeyDown = React.useCallback((e: React.KeyboardEvent) => { + e.preventDefault() + e.stopPropagation() + // Clear shortcut with backspace + const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e) + useToggleShowSideBarShortcut.set(shortcut) + }, []) + + return ( +
+

Toggle Shortcut

+ Set a combination of keys for toggling Gitako sidebar. +
+
+ + +
+ {shortcutHint && {shortcutHint}} +
+ ) +} From b5d9275e631b23bb9ff01a611e79cbeac6240d16 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Sun, 1 Dec 2019 22:32:03 +0800 Subject: [PATCH 5/5] feat: settings for icons --- src/components/Node.tsx | 14 ++++- src/components/SettingsBar.tsx | 2 + .../settings/FileTreeIconSettings.tsx | 56 +++++++++++++++++++ src/utils/configHelper.ts | 16 +++--- 4 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/components/settings/FileTreeIconSettings.tsx diff --git a/src/components/Node.tsx b/src/components/Node.tsx index d429ddf..ce178ed 100644 --- a/src/components/Node.tsx +++ b/src/components/Node.tsx @@ -1,3 +1,4 @@ +import { useConfigs } from 'containers/ConfigsContext' import * as React from 'react' import { cx } from 'utils/cx' import { OperatingSystems, os } from 'utils/general' @@ -72,14 +73,23 @@ const NodeItemIcon = React.memo(function NodeItemIcon({ node: TreeNode open?: boolean }) { + const { + val: { icons }, + } = useConfigs() + + if (icons === 'native') return const src = React.useMemo( () => (node.type === 'tree' ? getFolderIconSrc(node, open) : getFileIconSrc(node)), [open], ) return ( <> - - {node.type !== 'commit' && {node.name}} + + {node.type === 'commit' ? ( + + ) : ( + {node.name} + )} ) }) diff --git a/src/components/SettingsBar.tsx b/src/components/SettingsBar.tsx index 2c365b8..b77ccea 100644 --- a/src/components/SettingsBar.tsx +++ b/src/components/SettingsBar.tsx @@ -4,6 +4,7 @@ import * as React from 'react' import { Config } from 'utils/configHelper' import { useStates } from 'utils/hooks' import { AccessTokenSettings } from './settings/AccessTokenSettings' +import { FileTreeIconSettings } from './settings/FileTreeIconSettings' import { ShortcutSettings } from './settings/ShortcutSettings' import { SimpleToggleField } from './SimpleToggleField' @@ -70,6 +71,7 @@ function SettingsBarContent() {
+

More

{moreFields.map(field => ( diff --git a/src/components/settings/FileTreeIconSettings.tsx b/src/components/settings/FileTreeIconSettings.tsx new file mode 100644 index 0000000..53dd023 --- /dev/null +++ b/src/components/settings/FileTreeIconSettings.tsx @@ -0,0 +1,56 @@ +import { useConfigs } from 'containers/ConfigsContext' +import * as React from 'react' +import { Config } from 'utils/configHelper' + +const options: { + key: Config['icons'] + value: Config['icons'] + label: string +}[] = [ + { + key: 'rich', + value: 'rich', + label: `VSCode icons`, + }, + { + key: 'dim', + value: 'dim', + label: `VSCode icons (single color)`, + }, + { + key: 'native', + value: 'native', + label: `Native GitHub icons`, + }, +] + +type Props = {} + +export function FileTreeIconSettings(props: React.PropsWithChildren) { + const configContext = useConfigs() + return ( +
+

File Tree Icons

+ Icons can make a difference. +
+
+ +
+
+ ) +} diff --git a/src/utils/configHelper.ts b/src/utils/configHelper.ts index 470a005..61aab6f 100644 --- a/src/utils/configHelper.ts +++ b/src/utils/configHelper.ts @@ -8,6 +8,7 @@ export type Config = { copyFileButton: boolean copySnippetButton: boolean intelligentToggle: boolean | null // `null` stands for intelligent, boolean for sidebar open status + icons: 'rich' | 'dim' | 'native' } export enum configKeys { @@ -18,6 +19,7 @@ export enum configKeys { copyFileButton = 'copyFileButton', copySnippetButton = 'copySnippetButton', intelligentToggle = 'intelligentToggle', + icons = 'icons', } export const defaultConfigs: Config = { @@ -28,19 +30,17 @@ export const defaultConfigs: Config = { copyFileButton: true, copySnippetButton: true, intelligentToggle: null, + icons: 'rich', } const configKeyArray = Object.values(configKeys) function applyDefaultConfigs(configs: Config) { - return configKeyArray.reduce( - (applied, configKey) => { - const key = configKey as keyof Config - Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] }) - return applied - }, - {} as Config, - ) + return configKeyArray.reduce((applied, configKey) => { + const key = configKey as keyof Config + Object.assign(applied, { [key]: key in configs ? configs[key] : defaultConfigs[key] }) + return applied + }, {} as Config) } export async function get(): Promise {