├── .firebase └── hosting.ZGlzdC90ZWNoc3RhY2s.cache ├── .firebaserc ├── .github └── workflows │ └── firebase-hosting-merge.yml ├── .gitignore ├── LICENSE ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.json ├── firebase.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── .DS_Store ├── app │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── components │ │ └── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ ├── header.component.spec.ts │ │ │ ├── header.component.ts │ │ │ └── social-links │ │ │ ├── social-links.component.html │ │ │ ├── social-links.component.scss │ │ │ ├── social-links.component.spec.ts │ │ │ └── social-links.component.ts │ ├── data │ │ ├── logos.data.ts │ │ └── sampleInput.data.ts │ ├── utility │ │ └── fuzzyMatch.function.ts │ └── validators │ │ └── json.function.ts ├── assets │ ├── .gitkeep │ ├── heart.svg │ ├── stack-white.svg │ └── stack.svg ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json └── tslint.json /.firebase/hosting.ZGlzdC90ZWNoc3RhY2s.cache: -------------------------------------------------------------------------------- 1 | favicon.ico,1608797730739,a2aee5309d0b59b9b66384ccc3969a07fab1b320d0bf76f1b25047a051d7f774 2 | index.html,1608797730843,10655e26a3cc29f52aad8f8f30387fa53d076c551a338b2fbe0e5ac8cb899fd7 3 | main-es2015.js,1608797714126,11b6735fe5c161a6248637c83cbb49675314f800d500d8a67285670653fdf4d8 4 | main-es2015.js.map,1608797714121,38f790d77a1ae538412a9701d84613a49f06883f47725a0da722d22228fb74a1 5 | main-es5.js,1608797714116,3c1e4cff9fe09bafc27021d7f47e07af6c10b2398a142048f1a37bbb013c9cc6 6 | main-es5.js.map,1608797714096,4e13d77eb245941c29d48fba4793bd6ae35f804d0d8dfea1eb1aeee6043f8162 7 | polyfills-es2015.js,1608797712936,24ee89387d661b5c07a040b8db94737d84e9ee656b09394eddcc0bccfc76f26b 8 | polyfills-es2015.js.map,1608797712931,7a90acd7fdf04c2eaa4b0438fc59d3d11f31f342eedc4490e3de0d05f4291d2c 9 | polyfills-es5.js,1608797716894,4f2206bb7a2b1b913ebf1884dacc413390cd51bb320923f8d06ebb5c8f183129 10 | polyfills-es5.js.map,1608797716887,46b00d33b6800a161d94c549cb218df893c390c58a9521eaee0099030160cf32 11 | runtime-es2015.js,1608797712935,3c6481a763756f40130007348f0215b932db73049f163b5cd2217d26927a10bd 12 | runtime-es2015.js.map,1608797712931,955ede695ba643da7c5f77c3d59af7b4add94ac5655beec83eabed61e7a0e779 13 | runtime-es5.js,1608797712942,6bce5c16afb79d3454b1cab29d76354a2a4a7f5f8e6c460893abe89d2caf4559 14 | runtime-es5.js.map,1608797712940,e9372288cf2b6bb1485cd7578084452727f92c37d75c4b3898bcb2daaff6f557 15 | styles.css,1608797711867,71f833603cd63cb892b0dcabdead0fab05b169e3ae60d16d7b5be879065e1a28 16 | styles.css.map,1608797711867,8b290194d455c262d6798001259f651a8f18523cc84dccf76841c63ebd7df52b 17 | vendor-es2015.js,1608797730695,90c7641608a8f7ea883157d04502ce5d2527d081b26c1a5c777febfcfff57b0f 18 | vendor-es2015.js.map,1608797730654,dd43d24e5ac5e310ae451a80a68a7f788edcda810f62db2e50c51379a53c3f53 19 | vendor-es5.js,1608797730595,c6aaa3f977162566010e3d9e23652ca851462b411bf3517d018d924db99e8824 20 | vendor-es5.js.map,1608797730543,83328fcea49660de11bda4ab6f3b463b83aa65becf0d323f224edfb8297e5363 21 | assets/heart.svg,1608797730793,6f68d41f27dcdc2001431861aefef37620ef1dbcf747953119195ae69ccc8820 22 | assets/stack.svg,1608797730794,e862b8092a20a5d0de6c8e0cb3d07670ce1a6f468df7476a645b189fcda68e48 23 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "projects": { 3 | "default": "techstack-logos" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.github/workflows/firebase-hosting-merge.yml: -------------------------------------------------------------------------------- 1 | # This file was auto-generated by the Firebase CLI 2 | # https://github.com/firebase/firebase-tools 3 | 4 | name: Deploy to Firebase Hosting on merge 5 | "on": 6 | push: 7 | branches: 8 | - main 9 | jobs: 10 | build_and_deploy: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Use Node 12.x 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: "12.x" 18 | - name: Build 19 | run: npm ci && npm install && npm run build 20 | - uses: FirebaseExtended/action-hosting-deploy@v0 21 | with: 22 | repoToken: "${{ secrets.GITHUB_TOKEN }}" 23 | firebaseServiceAccount: "${{ secrets.FIREBASE_SERVICE_ACCOUNT_TECHSTACK_LOGOS }}" 24 | channelId: live 25 | projectId: techstack-logos 26 | env: 27 | FIREBASE_CLI_PREVIEWS: hostingchannels 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # compiled output 3 | /dist 4 | /tmp 5 | /out-tsc 6 | # Only exists if Bazel was run 7 | /bazel-out 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # profiling files 13 | chrome-profiler-events*.json 14 | speed-measure-plugin*.json 15 | 16 | # IDEs and editors 17 | /.idea 18 | .project 19 | .classpath 20 | .c9/ 21 | *.launch 22 | .settings/ 23 | *.sublime-workspace 24 | 25 | # IDE - VSCode 26 | .vscode/* 27 | !.vscode/settings.json 28 | !.vscode/tasks.json 29 | !.vscode/launch.json 30 | !.vscode/extensions.json 31 | .history/* 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | yarn-error.log 40 | testem.log 41 | /typings 42 | 43 | # System Files 44 | .DS_Store 45 | Thumbs.db 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Eric Angeles 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | stacklogo 3 | 4 | TechStack

5 | 6 |
7 | 8 |

9 | [LIVE APP] 10 |

11 | 12 | ## ⚡️BreakDown 13 | TechStack is an easy way to visualize your tech stack by simply pasting your package.json file and having it generate a beautiful bar of tech logos from your dependancies which you can then use in your README.md file. Logos provided by Logos. 14 | 15 | ## Development server 16 | 17 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 18 | 19 | ## Code scaffolding 20 | 21 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 22 | 23 | ## Build 24 | 25 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 26 | 27 | ## Running unit tests 28 | 29 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 30 | 31 | ## Running end-to-end tests 32 | 33 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 34 | 35 | ## Further help 36 | 37 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 38 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "techstack": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "inlineTemplate": true, 11 | "inlineStyle": true, 12 | "style": "sass" 13 | }, 14 | "@schematics/angular:application": { 15 | "strict": true 16 | } 17 | }, 18 | "root": "", 19 | "sourceRoot": "src", 20 | "prefix": "app", 21 | "architect": { 22 | "build": { 23 | "builder": "@angular-devkit/build-angular:browser", 24 | "options": { 25 | "outputPath": "dist/techstack", 26 | "index": "src/index.html", 27 | "main": "src/main.ts", 28 | "polyfills": "src/polyfills.ts", 29 | "tsConfig": "tsconfig.app.json", 30 | "aot": true, 31 | "assets": [ 32 | "src/favicon.ico", 33 | "src/assets" 34 | ], 35 | "styles": [ 36 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 37 | "src/styles.scss" 38 | ], 39 | "scripts": [] 40 | }, 41 | "configurations": { 42 | "production": { 43 | "fileReplacements": [ 44 | { 45 | "replace": "src/environments/environment.ts", 46 | "with": "src/environments/environment.prod.ts" 47 | } 48 | ], 49 | "optimization": true, 50 | "outputHashing": "all", 51 | "sourceMap": false, 52 | "namedChunks": false, 53 | "extractLicenses": true, 54 | "vendorChunk": false, 55 | "buildOptimizer": true, 56 | "budgets": [ 57 | { 58 | "type": "initial", 59 | "maximumWarning": "500kb", 60 | "maximumError": "1mb" 61 | }, 62 | { 63 | "type": "anyComponentStyle", 64 | "maximumWarning": "2kb", 65 | "maximumError": "4kb" 66 | } 67 | ] 68 | } 69 | } 70 | }, 71 | "serve": { 72 | "builder": "@angular-devkit/build-angular:dev-server", 73 | "options": { 74 | "browserTarget": "techstack:build" 75 | }, 76 | "configurations": { 77 | "production": { 78 | "browserTarget": "techstack:build:production" 79 | } 80 | } 81 | }, 82 | "extract-i18n": { 83 | "builder": "@angular-devkit/build-angular:extract-i18n", 84 | "options": { 85 | "browserTarget": "techstack:build" 86 | } 87 | }, 88 | "test": { 89 | "builder": "@angular-devkit/build-angular:karma", 90 | "options": { 91 | "main": "src/test.ts", 92 | "polyfills": "src/polyfills.ts", 93 | "tsConfig": "tsconfig.spec.json", 94 | "karmaConfig": "karma.conf.js", 95 | "assets": [ 96 | "src/favicon.ico", 97 | "src/assets" 98 | ], 99 | "styles": [ 100 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 101 | "src/styles.sass" 102 | ], 103 | "scripts": [] 104 | } 105 | }, 106 | "lint": { 107 | "builder": "@angular-devkit/build-angular:tslint", 108 | "options": { 109 | "tsConfig": [ 110 | "tsconfig.app.json", 111 | "tsconfig.spec.json", 112 | "e2e/tsconfig.json" 113 | ], 114 | "exclude": [ 115 | "**/node_modules/**" 116 | ] 117 | } 118 | }, 119 | "e2e": { 120 | "builder": "@angular-devkit/build-angular:protractor", 121 | "options": { 122 | "protractorConfig": "e2e/protractor.conf.js", 123 | "devServerTarget": "techstack:serve" 124 | }, 125 | "configurations": { 126 | "production": { 127 | "devServerTarget": "techstack:serve:production" 128 | } 129 | } 130 | } 131 | } 132 | } 133 | }, 134 | "defaultProject": "techstack", 135 | "schematics": { 136 | "@schematics/angular:component": { 137 | "styleext": "scss" 138 | } 139 | } 140 | } -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter, StacktraceOption } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | SELENIUM_PROMISE_MANAGER: false, 20 | baseUrl: 'http://localhost:4200/', 21 | framework: 'jasmine', 22 | jasmineNodeOpts: { 23 | showColors: true, 24 | defaultTimeoutInterval: 30000, 25 | print: function() {} 26 | }, 27 | onPrepare() { 28 | require('ts-node').register({ 29 | project: require('path').join(__dirname, './tsconfig.json') 30 | }); 31 | jasmine.getEnv().addReporter(new SpecReporter({ 32 | spec: { 33 | displayStacktrace: StacktraceOption.PRETTY 34 | } 35 | })); 36 | } 37 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', async () => { 12 | await page.navigateTo(); 13 | expect(await page.getTitleText()).toEqual('techstack app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | async navigateTo(): Promise { 5 | return browser.get(browser.baseUrl); 6 | } 7 | 8 | async getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "../tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "../out-tsc/e2e", 6 | "module": "commonjs", 7 | "target": "es2018", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "public": "./dist/techstack", 4 | "ignore": [ 5 | "firebase.json", 6 | "**/.*", 7 | "**/node_modules/**" 8 | ], 9 | "rewrites": [ 10 | { 11 | "source": "**", 12 | "destination": "index.html" 13 | } 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | jasmineHtmlReporter: { 19 | suppressAll: true // removes the duplicated traces 20 | }, 21 | coverageReporter: { 22 | dir: require('path').join(__dirname, './coverage/techstack'), 23 | subdir: '.', 24 | reporters: [ 25 | { type: 'html' }, 26 | { type: 'text-summary' } 27 | ] 28 | }, 29 | reporters: ['progress', 'kjhtml'], 30 | port: 9876, 31 | colors: true, 32 | logLevel: config.LOG_INFO, 33 | autoWatch: true, 34 | browsers: ['Chrome'], 35 | singleRun: false, 36 | restartOnFileChange: true 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "techstack", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "postinstall": "ngcc" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~11.0.1", 16 | "@angular/cdk": "^11.0.3", 17 | "@angular/common": "~11.0.1", 18 | "@angular/compiler": "~11.0.1", 19 | "@angular/core": "~11.0.1", 20 | "@angular/forms": "~11.0.1", 21 | "@angular/localize": "~11.0.1", 22 | "@angular/material": "^11.0.3", 23 | "@angular/platform-browser": "~11.0.1", 24 | "@angular/platform-browser-dynamic": "~11.0.1", 25 | "@angular/router": "~11.0.1", 26 | "@ctrl/ngx-codemirror": "^4.1.0", 27 | "bootstrap": "^4.5.0", 28 | "codemirror": "^5.58.3", 29 | "rxjs": "~6.6.0", 30 | "tslib": "^2.0.0", 31 | "zone.js": "~0.10.2" 32 | }, 33 | "devDependencies": { 34 | "@angular-devkit/build-angular": "~0.1100.2", 35 | "@angular/cli": "~11.0.2", 36 | "@angular/compiler-cli": "~11.0.1", 37 | "@types/jasmine": "~3.6.0", 38 | "prettier": "2.1.2", 39 | "@types/node": "^12.11.1", 40 | "codelyzer": "^6.0.0", 41 | "jasmine-core": "~3.6.0", 42 | "jasmine-spec-reporter": "~5.0.0", 43 | "karma": "~5.1.0", 44 | "karma-chrome-launcher": "~3.1.0", 45 | "karma-coverage": "~2.0.3", 46 | "karma-jasmine": "~4.0.0", 47 | "karma-jasmine-html-reporter": "^1.5.0", 48 | "protractor": "~7.0.0", 49 | "ts-node": "~8.3.0", 50 | "tslint": "~6.1.0", 51 | "typescript": "~4.0.2" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erangeles/techstack/7cf85a0f1e4603e0de7dab42748d5ca310b0b63a/src/.DS_Store -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | const routes: Routes = []; 5 | 6 | @NgModule({ 7 | imports: [RouterModule.forRoot(routes)], 8 | exports: [RouterModule] 9 | }) 10 | export class AppRoutingModule { } 11 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |
5 | 6 |

7 | TechStack is an easy way to visualize your techstack in your 8 | README.md file. Logos provided by 9 | SVG Logos. 10 |

11 |
    12 |
  • 13 | Paste your package.json below 14 |
  • 15 |
  • 16 | Verify your logos are correct, delete the ones that don't apply (tip: 17 | hover over the logos to see the name) 18 |
  • 19 |
  • 20 | Copy the markdown and add it to your 21 | Readme.md file 22 |
  • 23 |
24 |
25 | 26 |
27 |
28 | 34 | 35 | 36 | Invalid JSON syntax. 37 | 38 |
39 | 42 |
43 |
44 | 45 |
46 |
47 |
48 |
49 | 58 | 59 |

{{ img.name }}

60 |
61 |
62 | 67 | 68 | 77 |
78 |
79 |
80 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | .list { 2 | margin-left: 2.5vw; 3 | } 4 | 5 | .error { 6 | color: red; 7 | } 8 | 9 | .bg-dark { 10 | background-color: #313131; 11 | } 12 | 13 | .flexbox { 14 | display: flex; 15 | flex-wrap: wrap; 16 | padding: 2vh 2.5vw; 17 | align-items: center; 18 | justify-content: center; 19 | 20 | @media screen and (max-width: 720px) { 21 | flex-direction: column; 22 | } 23 | } 24 | 25 | .col-flex { 26 | display: flex; 27 | flex-flow: column wrap; 28 | } 29 | 30 | .my-2 { 31 | margin: 2em auto; 32 | } 33 | 34 | .mw-45 { 35 | max-width: 45vw; 36 | 37 | @media screen and (max-width: 720px) { 38 | max-width: 80vw; 39 | } 40 | } 41 | 42 | .min-h-90 { 43 | min-height: 90vh; 44 | } 45 | 46 | .logo-output { 47 | display: flex; 48 | flex-wrap: wrap; 49 | border-radius: 4px; 50 | padding: 2vh 2.5vw; 51 | align-items: center; 52 | justify-content: center; 53 | background-color: white; 54 | div { 55 | padding: 0.25em 1em; 56 | 57 | img { 58 | width: 55px; 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'techstack'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('techstack'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement; 33 | expect(compiled.querySelector('.content span').textContent).toContain('techstack app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | import { FormBuilder, FormGroup } from "@angular/forms"; 3 | import { MatSnackBar } from "@angular/material/snack-bar"; 4 | import { logos } from "./data/logos.data"; 5 | import { samplePackageJson } from "./data/sampleInput.data"; 6 | import { fuzzyMatch } from "./utility/fuzzyMatch.function"; 7 | import { validateJSON } from "./validators/json.function"; 8 | 9 | @Component({ 10 | selector: "app-root", 11 | templateUrl: "./app.component.html", 12 | styleUrls: ["./app.component.scss"], 13 | }) 14 | export class AppComponent implements OnInit { 15 | public baseCodeMirrorRules: any = { 16 | mode: "application/json", 17 | theme: "material", 18 | lineWrapping: true, 19 | foldGutter: true, 20 | gutters: ["CodeMirror-foldgutter"], 21 | autoCloseBrackets: true, 22 | matchBrackets: true, 23 | }; 24 | 25 | public packageJsonEditor: any = { 26 | ...this.baseCodeMirrorRules, 27 | mode: "application/json", 28 | }; 29 | 30 | public markDownEditor = { 31 | ...this.baseCodeMirrorRules, 32 | mode: "gfm", 33 | }; 34 | 35 | public form: FormGroup; 36 | public techStack: any[] = []; 37 | public markdown: string; 38 | 39 | constructor( 40 | private formBuilder: FormBuilder, 41 | private snackBar: MatSnackBar 42 | ) {} 43 | 44 | ngOnInit() { 45 | this.form = this.formBuilder.group({ 46 | dependancies: [samplePackageJson, validateJSON], 47 | }); 48 | 49 | this.extractLogos(); 50 | this.form 51 | .get("dependancies") 52 | .valueChanges.subscribe(() => this.extractLogos()); 53 | } 54 | 55 | deleteLogo(imagePath: string) { 56 | const index = this.techStack.indexOf(imagePath); 57 | if (index > -1) { 58 | this.techStack.splice(index, 1); 59 | } 60 | this.createMarkdown(); 61 | } 62 | 63 | extractLogos() { 64 | if ( 65 | !this.form.get("dependancies").value || 66 | this.form.get("dependancies").invalid 67 | ) { 68 | return; 69 | } 70 | this.techStack = []; 71 | let s = Object.keys( 72 | JSON.parse(this.form.get("dependancies").value).devDependencies 73 | ).concat( 74 | Object.keys(JSON.parse(this.form.get("dependancies").value).dependencies) 75 | ); 76 | 77 | logos.forEach((element: string) => { 78 | s.filter((d) => { 79 | if (fuzzyMatch(d, element) > 0.5) { 80 | this.techStack.push({ 81 | path: `https://raw.githubusercontent.com/gilbarbara/logos/master/logos/${element}.svg`, 82 | name: element, 83 | }); 84 | } 85 | }); 86 | }); 87 | this.createMarkdown(); 88 | } 89 | 90 | showToast() { 91 | this.snackBar.open("Copied to clipboard", null, { 92 | duration: 3000, 93 | }); 94 | } 95 | 96 | createMarkdown() { 97 | this.markdown = ""; 98 | this.markdown = '
'; 99 | this.techStack.forEach((element: any) => { 100 | this.markdown += ``; 101 | }); 102 | this.markdown += "
"; 103 | } 104 | 105 | clear() { 106 | this.form.get("dependancies").patchValue(""); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { ClipboardModule } from '@angular/cdk/clipboard'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 4 | import { MatButtonModule } from '@angular/material/button'; 5 | import { MatGridListModule } from '@angular/material/grid-list'; 6 | import { MatIconModule } from '@angular/material/icon'; 7 | import { MatToolbarModule } from '@angular/material/toolbar'; 8 | import { BrowserModule } from '@angular/platform-browser'; 9 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 10 | import { CodemirrorModule } from '@ctrl/ngx-codemirror'; 11 | import { AppRoutingModule } from './app-routing.module'; 12 | import { AppComponent } from './app.component'; 13 | import {MatSnackBarModule} from '@angular/material/snack-bar'; 14 | import {MatCardModule} from '@angular/material/card'; 15 | import { HeaderComponent } from './components/header/header.component'; 16 | import { SocialLinksComponent } from './components/header/social-links/social-links.component'; 17 | 18 | @NgModule({ 19 | declarations: [AppComponent, HeaderComponent, SocialLinksComponent], 20 | imports: [ 21 | BrowserModule, 22 | MatCardModule, 23 | MatSnackBarModule, 24 | MatIconModule, 25 | MatButtonModule, 26 | MatGridListModule, 27 | ClipboardModule, 28 | AppRoutingModule, 29 | FormsModule, 30 | CodemirrorModule, 31 | ReactiveFormsModule, 32 | MatToolbarModule, 33 | BrowserAnimationsModule 34 | ], 35 | providers: [], 36 | bootstrap: [AppComponent] 37 | }) 38 | export class AppModule {} 39 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 | 9 |
10 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.scss: -------------------------------------------------------------------------------- 1 | header > nav { 2 | display: flex; 3 | flex-wrap: wrap; 4 | padding: 0.5em 5%; 5 | align-items: center; 6 | justify-content: flex-end; 7 | 8 | background-color: #1f1f1f; 9 | 10 | .logo { 11 | margin-right: auto; 12 | 13 | img { 14 | width: 2.5em; 15 | } 16 | 17 | .brand { 18 | display: inline-block; 19 | color: white; 20 | } 21 | 22 | @media screen and (max-width: 720px) { 23 | margin: 0 auto; 24 | } 25 | } 26 | 27 | @media screen and (max-width: 720px) { 28 | flex-direction: column; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HeaderComponent } from './header.component'; 4 | 5 | describe('HeaderComponent', () => { 6 | let component: HeaderComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ HeaderComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(HeaderComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-header', 5 | templateUrl: "./header.component.html", 6 | styleUrls: ["./header.component.scss"] 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/components/header/social-links/social-links.component.html: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/app/components/header/social-links/social-links.component.scss: -------------------------------------------------------------------------------- 1 | .no-decoration { 2 | list-style: none; 3 | 4 | li { 5 | padding: 0 1em; 6 | font-weight: 500; 7 | display: inline-block; 8 | transition: all 0.3s ease-in-out; 9 | 10 | &:hover { 11 | transform: scale(1.25); 12 | } 13 | 14 | a { 15 | text-decoration: none; 16 | } 17 | } 18 | } 19 | 20 | .linkedin, .github, .twitter { 21 | color: white; 22 | } 23 | 24 | .linkedin:hover { 25 | color: #0e76a8; 26 | } 27 | 28 | .github:hover { 29 | color: #707070; 30 | } 31 | 32 | .twitter:hover { 33 | color: #1da1f2; 34 | } 35 | -------------------------------------------------------------------------------- /src/app/components/header/social-links/social-links.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SocialLinksComponent } from './social-links.component'; 4 | 5 | describe('SocialLinksComponent', () => { 6 | let component: SocialLinksComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | declarations: [ SocialLinksComponent ] 12 | }) 13 | .compileComponents(); 14 | }); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SocialLinksComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/components/header/social-links/social-links.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-social-links', 5 | templateUrl: "./social-links.component.html", 6 | styleUrls: ["./social-links.component.scss"] 7 | }) 8 | export class SocialLinksComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit(): void { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/data/logos.data.ts: -------------------------------------------------------------------------------- 1 | export const logos: string[] = [ 2 | '100tb', 3 | '500px', 4 | '6px', 5 | 'admob', 6 | 'adroll', 7 | 'adyen', 8 | 'aerospike', 9 | 'airbnb', 10 | 'airbrake', 11 | 'airflow', 12 | 'airtable', 13 | 'akamai', 14 | 'akka', 15 | 'alfresco', 16 | 'algolia', 17 | 'altair', 18 | 'amazon-chime', 19 | 'amazon-connect', 20 | 'amex', 21 | 'ampersand', 22 | 'android-icon', 23 | 'android', 24 | 'angellist', 25 | 'angular-icon', 26 | 'angular', 27 | 'ansible', 28 | 'ant-design', 29 | 'apache-camel', 30 | 'apache', 31 | 'apache_cloudstack', 32 | 'api-ai', 33 | 'apiary', 34 | 'apigee', 35 | 'apitools', 36 | 'apollostack', 37 | 'appbase', 38 | 'appcelerator', 39 | 'appcircle-icon', 40 | 'appcircle', 41 | 'appcode', 42 | 'appdynamics', 43 | 'appfog', 44 | 'apphub', 45 | 'appium', 46 | 'apple-app-store', 47 | 'apple-pay', 48 | 'apple', 49 | 'appmaker', 50 | 'apportable', 51 | 'appsignal-icon', 52 | 'appsignal', 53 | 'apptentive', 54 | 'appveyor', 55 | 'arangodb', 56 | 'archlinux', 57 | 'arduino', 58 | 'armory', 59 | 'asana', 60 | 'asciidoctor', 61 | 'astronomer', 62 | 'atlassian', 63 | 'atom', 64 | 'atomic', 65 | 'aurelia', 66 | 'aurora', 67 | 'aurous', 68 | 'auth0', 69 | 'authy', 70 | 'autocode', 71 | 'autoit', 72 | 'autoprefixer', 73 | 'ava', 74 | 'awesome', 75 | 'aws-api-gateway', 76 | 'aws-cloudformation', 77 | 'aws-cloudfront', 78 | 'aws-cloudsearch', 79 | 'aws-cloudwatch', 80 | 'aws-codedeploy', 81 | 'aws-cognito', 82 | 'aws-dynamodb', 83 | 'aws-ec2', 84 | 'aws-elastic-cache', 85 | 'aws-glacier', 86 | 'aws-iam', 87 | 'aws-kinesis', 88 | 'aws-lambda', 89 | 'aws-mobilehub', 90 | 'aws-opsworks', 91 | 'aws-quicksight', 92 | 'aws-rds', 93 | 'aws-route53', 94 | 'aws-s3', 95 | 'aws-ses', 96 | 'aws-sns', 97 | 'aws-sqs', 98 | 'aws-waf', 99 | 'aws', 100 | 'azure-icon', 101 | 'azure', 102 | 'babel', 103 | 'backbone-icon', 104 | 'backbone', 105 | 'backerkit', 106 | 'baker-street', 107 | 'balena', 108 | 'bamboo', 109 | 'basecamp', 110 | 'basekit', 111 | 'bash-icon', 112 | 'bash', 113 | 'batch', 114 | 'beats', 115 | 'behance', 116 | 'bem-2', 117 | 'bem', 118 | 'bigpanda', 119 | 'bing', 120 | 'bitballoon', 121 | 'bitbucket', 122 | 'bitcoin', 123 | 'bitnami', 124 | 'bitrise-icon', 125 | 'bitrise', 126 | 'blocs', 127 | 'blogger', 128 | 'blossom', 129 | 'bluemix', 130 | 'blueprint', 131 | 'bluetooth', 132 | 'bootstrap', 133 | 'bosun', 134 | 'botanalytics', 135 | 'bourbon', 136 | 'bower', 137 | 'bowtie', 138 | 'box', 139 | 'brackets', 140 | 'branch', 141 | 'brandfolder-icon', 142 | 'brandfolder', 143 | 'brave', 144 | 'braze', 145 | 'broccoli', 146 | 'brotli', 147 | 'browserify-icon', 148 | 'browserify', 149 | 'browserling', 150 | 'browserslist', 151 | 'browserstack', 152 | 'browsersync', 153 | 'brunch', 154 | 'buck', 155 | 'buddy', 156 | 'buffer', 157 | 'bugherd', 158 | 'bugsee', 159 | 'bugsnag', 160 | 'bulma', 161 | 'c-plusplus', 162 | 'c-sharp', 163 | 'c', 164 | 'cachet', 165 | 'caffe2', 166 | 'cakephp', 167 | 'campaignmonitor-icon', 168 | 'campaignmonitor', 169 | 'campfire', 170 | 'canjs', 171 | 'capistrano', 172 | 'carbide', 173 | 'cassandra', 174 | 'celluloid', 175 | 'centos-icon', 176 | 'centos', 177 | 'certbot', 178 | 'chai', 179 | 'chalk', 180 | 'changetip', 181 | 'chargebee-icon', 182 | 'chargebee', 183 | 'chartblocks', 184 | 'chef', 185 | 'chevereto', 186 | 'chromatic-icon', 187 | 'chromatic', 188 | 'chrome', 189 | 'circleci', 190 | 'cirrus', 191 | 'clickdeploy', 192 | 'clion', 193 | 'cljs', 194 | 'clojure', 195 | 'close', 196 | 'cloud9', 197 | 'cloudacademy', 198 | 'cloudant', 199 | 'cloudcraft', 200 | 'cloudera', 201 | 'cloudflare', 202 | 'cloudinary', 203 | 'cloudlinux', 204 | 'clusterhq', 205 | 'cobalt', 206 | 'cockpit', 207 | 'cocoapods', 208 | 'codacy', 209 | 'codebase', 210 | 'codebeat', 211 | 'codecademy', 212 | 'codeception', 213 | 'codeclimate', 214 | 'codecov', 215 | 'codefactor', 216 | 'codefund-icon', 217 | 'codefund', 218 | 'codeigniter', 219 | 'codepen-icon', 220 | 'codepen', 221 | 'codepicnic', 222 | 'codepush', 223 | 'coderwall', 224 | 'codesandbox', 225 | 'codeschool', 226 | 'codeship', 227 | 'codio', 228 | 'codrops', 229 | 'coffeescript', 230 | 'compass', 231 | 'component', 232 | 'componentkit', 233 | 'compose', 234 | 'composer', 235 | 'conan-io', 236 | 'concourse', 237 | 'concrete5', 238 | 'confluence', 239 | 'consul', 240 | 'containership', 241 | 'contentful', 242 | 'convox', 243 | 'copyleft-pirate', 244 | 'copyleft', 245 | 'cordova', 246 | 'coreos-icon', 247 | 'coreos', 248 | 'couchbase', 249 | 'couchdb-icon', 250 | 'couchdb', 251 | 'coursera', 252 | 'coveralls', 253 | 'cpanel', 254 | 'craftcms', 255 | 'crashlytics', 256 | 'crateio', 257 | 'createjs', 258 | 'cross-browser-testing', 259 | 'crucible', 260 | 'crystal', 261 | 'css-3', 262 | 'css-3_official', 263 | 'cssnext', 264 | 'cucumber', 265 | 'customerio', 266 | 'cyclejs', 267 | 'cypress', 268 | 'd3', 269 | 'dapulse', 270 | 'dart', 271 | 'dashlane', 272 | 'dat', 273 | 'database-labs', 274 | 'datocms-icon', 275 | 'datocms', 276 | 'dcos', 277 | 'debian', 278 | 'delicious', 279 | 'delighted', 280 | 'deno', 281 | 'dependencyci', 282 | 'deploy', 283 | 'deppbot', 284 | 'derby', 285 | 'designernews', 286 | 'desk', 287 | 'deviantart', 288 | 'digital-ocean', 289 | 'dimer', 290 | 'dinersclub', 291 | 'discord', 292 | 'discover', 293 | 'disqus', 294 | 'django', 295 | 'dockbit', 296 | 'docker-icon', 297 | 'docker', 298 | 'doctrine', 299 | 'docusaurus', 300 | 'dojo-icon', 301 | 'dojo-toolkit', 302 | 'dojo', 303 | 'dotnet', 304 | 'doubleclick', 305 | 'dreamfactory', 306 | 'dreamhost', 307 | 'dribbble-icon', 308 | 'dribbble', 309 | 'drift', 310 | 'drip', 311 | 'drone', 312 | 'dropbox', 313 | 'dropmark', 314 | 'dropzone', 315 | 'drupal-icon', 316 | 'drupal', 317 | 'duckduckgo', 318 | 'dyndns', 319 | 'eager', 320 | 'ebanx', 321 | 'eclipse', 322 | 'egghead', 323 | 'elasticbox', 324 | 'elasticsearch', 325 | 'electron', 326 | 'element', 327 | 'elemental-ui', 328 | 'elementary', 329 | 'ello', 330 | 'elm', 331 | 'elo', 332 | 'emacs', 333 | 'embedly', 334 | 'ember-tomster', 335 | 'ember', 336 | 'emmet', 337 | 'engine-yard', 338 | 'envato', 339 | 'envoyer', 340 | 'enyo', 341 | 'erlang', 342 | 'es6', 343 | 'esdoc', 344 | 'eslint-old', 345 | 'eslint', 346 | 'eta-lang', 347 | 'etcd', 348 | 'ethereum', 349 | 'ethnio', 350 | 'eventbrite-icon', 351 | 'eventbrite', 352 | 'eventsentry', 353 | 'evergreen-icon', 354 | 'evergreen', 355 | 'expo', 356 | 'exponent', 357 | 'express', 358 | 'fabric', 359 | 'fabric_io', 360 | 'facebook', 361 | 'falcor', 362 | 'fastlane', 363 | 'fastly', 364 | 'feathersjs', 365 | 'fedora', 366 | 'figma', 367 | 'firebase', 368 | 'firefox', 369 | 'flannel', 370 | 'flarum', 371 | 'flask', 372 | 'flat-ui', 373 | 'flattr', 374 | 'fleep', 375 | 'flexible-gs', 376 | 'flickr', 377 | 'flight', 378 | 'flocker', 379 | 'floodio', 380 | 'flow', 381 | 'flowxo', 382 | 'floydhub', 383 | 'flutter', 384 | 'flux', 385 | 'fluxxor', 386 | 'fly', 387 | 'flyjs', 388 | 'fomo', 389 | 'font-awesome', 390 | 'forest', 391 | 'forever', 392 | 'formkeep', 393 | 'foundation', 394 | 'framework7', 395 | 'freebsd', 396 | 'freedcamp-icon', 397 | 'freedcamp', 398 | 'freedomdefined', 399 | 'frontapp', 400 | 'fsharp', 401 | 'fuchsia', 402 | 'galliumos', 403 | 'game-analytics', 404 | 'gatsby', 405 | 'gaugeio', 406 | 'geekbot', 407 | 'get-satisfaction', 408 | 'ghost', 409 | 'giantswarm', 410 | 'git-icon', 411 | 'git', 412 | 'gitboard', 413 | 'github-icon', 414 | 'github-octocat', 415 | 'github', 416 | 'gitkraken', 417 | 'gitlab', 418 | 'gitter', 419 | 'gitup', 420 | 'glamorous', 421 | 'gleam', 422 | 'glimmerjs', 423 | 'glint', 424 | 'gnu', 425 | 'go', 426 | 'gocd', 427 | 'gohorse', 428 | 'gomix', 429 | 'google-2014', 430 | 'google-360suite', 431 | 'google-ads', 432 | 'google-adsense', 433 | 'google-adwords', 434 | 'google-analytics', 435 | 'google-calendar', 436 | 'google-cloud-functions', 437 | 'google-cloud-platform', 438 | 'google-cloud-run', 439 | 'google-cloud', 440 | 'google-data-studio', 441 | 'google-developers-icon', 442 | 'google-developers', 443 | 'google-drive', 444 | 'google-gmail', 445 | 'google-gsuite', 446 | 'google-icon', 447 | 'google-inbox', 448 | 'google-marketing-platform', 449 | 'google-meet', 450 | 'google-optimize', 451 | 'google-pay', 452 | 'google-photos', 453 | 'google-play-icon', 454 | 'google-play', 455 | 'google-plus', 456 | 'google-tag-manager', 457 | 'google-wallet', 458 | 'google', 459 | 'gopher', 460 | 'gordon', 461 | 'gradle', 462 | 'grafana', 463 | 'grails', 464 | 'grape', 465 | 'graphcool', 466 | 'graphene', 467 | 'graphql', 468 | 'gratipay', 469 | 'grav', 470 | 'gravatar', 471 | 'graylog', 472 | 'gridsome-icon', 473 | 'gridsome', 474 | 'grommet', 475 | 'groovehq', 476 | 'grove', 477 | 'grunt', 478 | 'gulp', 479 | 'gunicorn', 480 | 'gusto', 481 | 'gwt', 482 | 'hack', 483 | 'hacker-one', 484 | 'hadoop', 485 | 'haiku', 486 | 'haml', 487 | 'hanami', 488 | 'handlebars', 489 | 'hapi', 490 | 'harrow', 491 | 'hashnode', 492 | 'haskell-icon', 493 | 'haskell', 494 | 'hasura', 495 | 'haxe', 496 | 'haxl', 497 | 'hbase', 498 | 'heap', 499 | 'helpscout', 500 | 'heroku-icon', 501 | 'heroku-redis', 502 | 'heroku', 503 | 'heron', 504 | 'hexo', 505 | 'hhvm', 506 | 'hibernate', 507 | 'highcharts', 508 | 'hipercard', 509 | 'hoa', 510 | 'hoodie', 511 | 'horizon', 512 | 'hosted-graphite', 513 | 'hostgator', 514 | 'houndci', 515 | 'html-5', 516 | 'html5-boilerplate', 517 | 'hubspot', 518 | 'hugo', 519 | 'humongous', 520 | 'hyper', 521 | 'hyperapp', 522 | 'ibm', 523 | 'ieee', 524 | 'ifttt', 525 | 'imagemin', 526 | 'immutable', 527 | 'impala', 528 | 'importio', 529 | 'infer', 530 | 'inferno', 531 | 'influxdb', 532 | 'ink', 533 | 'instagram-icon', 534 | 'instagram', 535 | 'intellij-idea', 536 | 'intercom', 537 | 'internetexplorer', 538 | 'invision', 539 | 'io', 540 | 'ionic', 541 | 'ios', 542 | 'iron-icon', 543 | 'iron', 544 | 'itsalive', 545 | 'jade', 546 | 'jamstack', 547 | 'jasmine', 548 | 'java', 549 | 'javascript', 550 | 'jcb', 551 | 'jekyll', 552 | 'jelastic', 553 | 'jenkins', 554 | 'jest', 555 | 'jetbrains', 556 | 'jhipster', 557 | 'jira', 558 | 'joomla', 559 | 'jquery-mobile', 560 | 'jquery', 561 | 'jruby', 562 | 'jsbin', 563 | 'jsdelivr', 564 | 'jsdom', 565 | 'jsfiddle', 566 | 'json', 567 | 'jspm', 568 | 'jss', 569 | 'juju', 570 | 'julia', 571 | 'jupyter', 572 | 'kafka-icon', 573 | 'kafka', 574 | 'kaios', 575 | 'kallithea', 576 | 'karma', 577 | 'keen', 578 | 'kemal', 579 | 'keycdn', 580 | 'keystonejs', 581 | 'khan_academy', 582 | 'kibana', 583 | 'kickstarter', 584 | 'kinto', 585 | 'kinvey', 586 | 'kirby', 587 | 'kissmetrics', 588 | 'kitematic', 589 | 'kloudless', 590 | 'knex', 591 | 'knockout', 592 | 'koa', 593 | 'kong', 594 | 'kontena', 595 | 'kops', 596 | 'kore', 597 | 'koreio', 598 | 'kotlin', 599 | 'kraken', 600 | 'krakenjs', 601 | 'kubernetes', 602 | 'kustomer', 603 | 'laravel', 604 | 'lastfm', 605 | 'lateral', 606 | 'launchkit', 607 | 'launchrock', 608 | 'leafjet', 609 | 'leankit-icon', 610 | 'leankit', 611 | 'less', 612 | 'lets-cloud', 613 | 'letsencrypt', 614 | 'leveldb', 615 | 'librato', 616 | 'liftweb', 617 | 'lighttpd', 618 | 'linkedin', 619 | 'linkerd', 620 | 'linode', 621 | 'linux-mint', 622 | 'linux-tux', 623 | 'list', 624 | 'litmus', 625 | 'loader', 626 | 'locent', 627 | 'lodash', 628 | 'logentries', 629 | 'loggly', 630 | 'logmatic', 631 | 'logstash', 632 | 'lookback', 633 | 'looker', 634 | 'loom', 635 | 'loopback-icon', 636 | 'loopback', 637 | 'losant', 638 | 'lua', 639 | 'lucene.net', 640 | 'lucene', 641 | 'lumen', 642 | 'lynda', 643 | 'macOS', 644 | 'madge', 645 | 'maestro', 646 | 'mageia', 647 | 'magento', 648 | 'magneto', 649 | 'mailchimp-freddie', 650 | 'mailchimp', 651 | 'maildeveloper', 652 | 'mailgun-icon', 653 | 'mailgun', 654 | 'mandrill-shield', 655 | 'mandrill', 656 | 'manifoldjs', 657 | 'mantl', 658 | 'manuscript', 659 | 'mapbox', 660 | 'maps-me', 661 | 'mapzen', 662 | 'mariadb-icon', 663 | 'mariadb', 664 | 'marionette', 665 | 'markdown', 666 | 'marko', 667 | 'marvel', 668 | 'mastercard', 669 | 'material-ui', 670 | 'materializecss', 671 | 'mattermost', 672 | 'maxcdn', 673 | 'mdn', 674 | 'mdx', 675 | 'medium', 676 | 'memcached', 677 | 'memsql-icon', 678 | 'memsql', 679 | 'mention', 680 | 'mercurial', 681 | 'mern', 682 | 'mesos', 683 | 'mesosphere', 684 | 'metabase', 685 | 'meteor-icon', 686 | 'meteor', 687 | 'microcosm', 688 | 'microsoft-edge', 689 | 'microsoft-windows', 690 | 'microsoft', 691 | 'middleman', 692 | 'milligram', 693 | 'mio', 694 | 'mist', 695 | 'mithril', 696 | 'mixmax', 697 | 'mixpanel', 698 | 'mlab', 699 | 'mobx', 700 | 'mocha', 701 | 'mockflow', 702 | 'modernizr', 703 | 'modx', 704 | 'moltin-icon', 705 | 'moltin', 706 | 'momentjs', 707 | 'monero', 708 | 'mongodb', 709 | 'mono', 710 | 'moon', 711 | 'mootools', 712 | 'morpheus', 713 | 'mozilla', 714 | 'mparticle', 715 | 'mysql', 716 | 'myth', 717 | 'namecheap', 718 | 'nanonets', 719 | 'nativescript', 720 | 'neat', 721 | 'neo4j', 722 | 'neonmetrics', 723 | 'neovim', 724 | 'nestjs', 725 | 'netbeans', 726 | 'netflix-icon', 727 | 'netflix', 728 | 'netlify', 729 | 'netuitive', 730 | 'new-relic', 731 | 'nextjs', 732 | 'nginx', 733 | 'nightwatch', 734 | 'nodal', 735 | 'node-sass', 736 | 'nodebots', 737 | 'nodejitsu', 738 | 'nodejs-icon', 739 | 'nodejs', 740 | 'nodemon', 741 | 'nodeos', 742 | 'nodewebkit', 743 | 'nomad', 744 | 'now', 745 | 'noysi', 746 | 'npm-icon', 747 | 'npm', 748 | 'nuclide', 749 | 'nuodb', 750 | 'nuxt-icon', 751 | 'nuxt', 752 | 'oauth', 753 | 'ocaml', 754 | 'octodns', 755 | 'octopus-deploy', 756 | 'olapic', 757 | 'olark', 758 | 'onesignal', 759 | 'opbeat', 760 | 'open-graph', 761 | 'opencart', 762 | 'opencollective', 763 | 'opencv', 764 | 'opengl', 765 | 'openlayers', 766 | 'openshift', 767 | 'opensource', 768 | 'openstack', 769 | 'opera', 770 | 'opsee', 771 | 'opsgenie', 772 | 'optimizely', 773 | 'oracle', 774 | 'oreilly', 775 | 'origami', 776 | 'origin', 777 | 'oshw', 778 | 'osquery', 779 | 'otto', 780 | 'packer', 781 | 'pagekit', 782 | 'pagekite', 783 | 'panda', 784 | 'parse', 785 | 'parsehub', 786 | 'passbolt', 787 | 'passport', 788 | 'patreon', 789 | 'paypal', 790 | 'peer5', 791 | 'pepperoni', 792 | 'percona', 793 | 'percy', 794 | 'perf-rocks', 795 | 'periscope', 796 | 'perl', 797 | 'phalcon', 798 | 'phoenix', 799 | 'phonegap-bot', 800 | 'phonegap', 801 | 'php', 802 | 'phpstorm', 803 | 'picasa', 804 | 'pingdom', 805 | 'pingy', 806 | 'pinterest', 807 | 'pipedrive', 808 | 'pipefy', 809 | 'pivotal_tracker', 810 | 'pixate', 811 | 'pkg', 812 | 'planless', 813 | 'plastic-scm', 814 | 'platformio', 815 | 'play', 816 | 'pm2', 817 | 'podio', 818 | 'poeditor', 819 | 'polymer', 820 | 'positionly', 821 | 'postcss', 822 | 'postgresql', 823 | 'postman', 824 | 'pouchdb', 825 | 'preact', 826 | 'precursor', 827 | 'prestashop', 828 | 'presto', 829 | 'prettier', 830 | 'prisma', 831 | 'prismic-icon', 832 | 'prismic', 833 | 'processwire-icon', 834 | 'processwire', 835 | 'productboard', 836 | 'producthunt', 837 | 'progress', 838 | 'prometheus', 839 | 'promises', 840 | 'proofy', 841 | 'prospect', 842 | 'protactor', 843 | 'protoio', 844 | 'protonet', 845 | 'prott', 846 | 'pug', 847 | 'pumpkindb', 848 | 'puppet-icon', 849 | 'puppet', 850 | 'puppeteer', 851 | 'puppy-linux', 852 | 'pushbullet', 853 | 'pusher', 854 | 'pycharm', 855 | 'python', 856 | 'pytorch', 857 | 'pyup', 858 | 'q', 859 | 'qordoba', 860 | 'qt', 861 | 'quay', 862 | 'quobyte', 863 | 'quora', 864 | 'r-lang', 865 | 'rabbitmq', 866 | 'rackspace', 867 | 'rails', 868 | 'ramda', 869 | 'raml', 870 | 'rancher', 871 | 'raphael', 872 | 'raspberry-pi', 873 | 'rax', 874 | 'react-router', 875 | 'react-styleguidist', 876 | 'react', 877 | 'reactivex', 878 | 'realm', 879 | 'reapp', 880 | 'reasonml-icon', 881 | 'reasonml', 882 | 'recast.ai', 883 | 'reddit-icon', 884 | 'reddit', 885 | 'redhat', 886 | 'redis', 887 | 'redsmin', 888 | 'redspread', 889 | 'redux-observable', 890 | 'redux-saga', 891 | 'redux', 892 | 'refactor', 893 | 'reindex', 894 | 'relay', 895 | 'remergr', 896 | 'require', 897 | 'rest-li', 898 | 'rest', 899 | 'rethinkdb', 900 | 'riak', 901 | 'riot', 902 | 'rkt', 903 | 'rocket-chat', 904 | 'rocksdb', 905 | 'rollbar', 906 | 'rollup', 907 | 'rollupjs', 908 | 'rsa', 909 | 'rsmq', 910 | 'rubocop', 911 | 'ruby', 912 | 'rubygems', 913 | 'rubymine', 914 | 'rum', 915 | 'run-above', 916 | 'runnable', 917 | 'runscope', 918 | 'rust', 919 | 'rxdb', 920 | 'safari', 921 | 'sagui', 922 | 'sails', 923 | 'salesforce', 924 | 'saltstack', 925 | 'sameroom', 926 | 'sanity', 927 | 'sass-doc', 928 | 'sass', 929 | 'saucelabs', 930 | 'scala', 931 | 'scaledrone', 932 | 'scaphold', 933 | 'scribd', 934 | 'sectionio', 935 | 'segment', 936 | 'selenium', 937 | 'semantic-ui', 938 | 'semantic-web', 939 | 'semaphore', 940 | 'sencha', 941 | 'sendgrid', 942 | 'seneca', 943 | 'sensu', 944 | 'sentry', 945 | 'sequelize', 946 | 'serveless', 947 | 'serverless', 948 | 'sherlock', 949 | 'shields', 950 | 'shipit', 951 | 'shippable', 952 | 'shogun', 953 | 'shopify', 954 | 'sidekick', 955 | 'sidekiq', 956 | 'signal', 957 | 'sinatra', 958 | 'siphon', 959 | 'sitepoint', 960 | 'sketch', 961 | 'sketchapp', 962 | 'skylight', 963 | 'skype', 964 | 'slack-icon', 965 | 'slack', 966 | 'slides', 967 | 'slim', 968 | 'smartling', 969 | 'smashingmagazine', 970 | 'snap-svg', 971 | 'sninnaker', 972 | 'snupps', 973 | 'snyk', 974 | 'socket.io', 975 | 'solid', 976 | 'solr', 977 | 'sonarqube', 978 | 'soundcloud', 979 | 'sourcegraph', 980 | 'sourcetrail', 981 | 'sourcetree', 982 | 'spark', 983 | 'sparkcentral', 984 | 'sparkpost', 985 | 'speakerdeck', 986 | 'speedcurve', 987 | 'spinnaker', 988 | 'spree', 989 | 'spring', 990 | 'sqldep', 991 | 'sqlite', 992 | 'square', 993 | 'squarespace', 994 | 'stackbit-icon', 995 | 'stackbit', 996 | 'stackoverflow-icon', 997 | 'stackoverflow', 998 | 'stackshare', 999 | 'stacksmith', 1000 | 'statuspage', 1001 | 'steam', 1002 | 'steroids', 1003 | 'stetho', 1004 | 'stickermule', 1005 | 'stitch', 1006 | 'stoplight', 1007 | 'stormpath', 1008 | 'storybook-icon', 1009 | 'storybook', 1010 | 'strapi-icon', 1011 | 'strapi', 1012 | 'strider', 1013 | 'stripe', 1014 | 'struts', 1015 | 'styleci', 1016 | 'stylefmt', 1017 | 'stylelint', 1018 | 'stylus', 1019 | 'subversion', 1020 | 'sugarss', 1021 | 'supergiant', 1022 | 'supersonic', 1023 | 'supportkit', 1024 | 'surge', 1025 | 'survicate', 1026 | 'suse', 1027 | 'susy', 1028 | 'svelte-icon', 1029 | 'svelte', 1030 | 'svg', 1031 | 'svgator', 1032 | 'swagger', 1033 | 'swift', 1034 | 'swiftype', 1035 | 'symfony', 1036 | 'sysdig', 1037 | 't3', 1038 | 'taiga', 1039 | 'tailwindcss-icon', 1040 | 'tailwindcss', 1041 | 'tapcart', 1042 | 'targetprocess', 1043 | 'tastejs', 1044 | 'tealium', 1045 | 'teamgrid', 1046 | 'teamwork-icon', 1047 | 'teamwork', 1048 | 'tectonic', 1049 | 'telegram', 1050 | 'tensorflow', 1051 | 'terminal', 1052 | 'terraform', 1053 | 'testlodge', 1054 | 'testmunk', 1055 | 'thimble', 1056 | 'titon', 1057 | 'tnw', 1058 | 'todoist-icon', 1059 | 'todoist', 1060 | 'todomvc', 1061 | 'tomcat', 1062 | 'torus', 1063 | 'traackr', 1064 | 'trac', 1065 | 'travis-ci-monochrome', 1066 | 'travis-ci', 1067 | 'treasuredata', 1068 | 'treehouse', 1069 | 'trello', 1070 | 'tsu', 1071 | 'tsuru', 1072 | 'tumblr-icon', 1073 | 'tumblr', 1074 | 'tunein', 1075 | 'turret', 1076 | 'tutsplus', 1077 | 'tutum', 1078 | 'tux', 1079 | 'twilio', 1080 | 'twitch', 1081 | 'twitter', 1082 | 'typeform-icon', 1083 | 'typeform', 1084 | 'typescript-icon', 1085 | 'typescript', 1086 | 'ubuntu', 1087 | 'udacity', 1088 | 'udemy', 1089 | 'uikit', 1090 | 'umu', 1091 | 'unbounce', 1092 | 'undertow', 1093 | 'unionpay', 1094 | 'unitjs', 1095 | 'unito', 1096 | 'unity', 1097 | 'upcase', 1098 | 'upwork', 1099 | 'user-testing', 1100 | 'uservoice', 1101 | 'uwsgi', 1102 | 'v8-ignition', 1103 | 'v8-turbofan', 1104 | 'v8', 1105 | 'vaadin', 1106 | 'vaddy', 1107 | 'vagrant', 1108 | 'vault', 1109 | 'vector-timber', 1110 | 'vernemq', 1111 | 'victorops', 1112 | 'vim', 1113 | 'vimeo-icon', 1114 | 'vimeo', 1115 | 'vine', 1116 | 'visa', 1117 | 'visaelectron', 1118 | 'visual-studio-code', 1119 | 'visual-studio', 1120 | 'visual_website_optimizer', 1121 | 'vivaldi', 1122 | 'void', 1123 | 'vue', 1124 | 'vuetifyjs', 1125 | 'vulkan', 1126 | 'vultr', 1127 | 'w3c', 1128 | 'waffle', 1129 | 'wagtail', 1130 | 'wakatime', 1131 | 'watchman', 1132 | 'weave', 1133 | 'webassembly', 1134 | 'webcomponents', 1135 | 'webflow', 1136 | 'webhooks', 1137 | 'webmin', 1138 | 'webpack', 1139 | 'webplatform', 1140 | 'webrtc', 1141 | 'websocket', 1142 | 'webstorm', 1143 | 'webtask', 1144 | 'webtorrent', 1145 | 'weebly', 1146 | 'wercker', 1147 | 'whalar', 1148 | 'whatsapp', 1149 | 'whatwg', 1150 | 'wicket-icon', 1151 | 'wicket', 1152 | 'wifi', 1153 | 'wire', 1154 | 'wiredtree', 1155 | 'wix', 1156 | 'woocommerce', 1157 | 'woopra', 1158 | 'wordpress-icon', 1159 | 'wordpress', 1160 | 'workboard', 1161 | 'wpengine', 1162 | 'wufoo', 1163 | 'x-ray-goggles', 1164 | 'xamarin', 1165 | 'xampp', 1166 | 'xcart', 1167 | 'xero', 1168 | 'xplenty', 1169 | 'xtend', 1170 | 'xwiki', 1171 | 'yahoo', 1172 | 'yammer', 1173 | 'yandex-ru', 1174 | 'yarn', 1175 | 'ycombinator', 1176 | 'yeoman', 1177 | 'yii', 1178 | 'youtrack', 1179 | 'youtube', 1180 | 'zapier', 1181 | 'zeit-icon', 1182 | 'zeit', 1183 | 'zend-framework', 1184 | 'zendesk', 1185 | 'zenhub', 1186 | 'zeplin', 1187 | 'zest', 1188 | 'zigbee', 1189 | 'zoho', 1190 | 'zube', 1191 | 'zulip', 1192 | 'zwave' 1193 | ]; 1194 | -------------------------------------------------------------------------------- /src/app/data/sampleInput.data.ts: -------------------------------------------------------------------------------- 1 | export const samplePackageJson = `{ 2 | "name": "techstack", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "postinstall": "ngcc" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~11.0.1", 16 | "@angular/cdk": "^11.0.3", 17 | "@angular/common": "~11.0.1", 18 | "@angular/compiler": "~11.0.1", 19 | "@angular/core": "~11.0.1", 20 | "@angular/forms": "~11.0.1", 21 | "@angular/localize": "~11.0.1", 22 | "@angular/material": "^11.0.3", 23 | "@angular/platform-browser": "~11.0.1", 24 | "@angular/platform-browser-dynamic": "~11.0.1", 25 | "@angular/router": "~11.0.1", 26 | "@ctrl/ngx-codemirror": "^4.1.0", 27 | "bootstrap": "^4.5.0", 28 | "codemirror": "^5.58.3", 29 | "rxjs": "~6.6.0", 30 | "tslib": "^2.0.0", 31 | "zone.js": "~0.10.2" 32 | }, 33 | "devDependencies": { 34 | "@angular-devkit/build-angular": "~0.1100.2", 35 | "@angular/cli": "~11.0.2", 36 | "@angular/compiler-cli": "~11.0.1", 37 | "@types/jasmine": "~3.6.0", 38 | "prettier": "2.1.2", 39 | "@types/node": "^12.11.1", 40 | "codelyzer": "^6.0.0", 41 | "jasmine-core": "~3.6.0", 42 | "jasmine-spec-reporter": "~5.0.0", 43 | "karma": "~5.1.0", 44 | "karma-chrome-launcher": "~3.1.0", 45 | "karma-coverage": "~2.0.3", 46 | "karma-jasmine": "~4.0.0", 47 | "karma-jasmine-html-reporter": "^1.5.0", 48 | "protractor": "~7.0.0", 49 | "ts-node": "~8.3.0", 50 | "tslint": "~6.1.0", 51 | "typescript": "~4.0.2" 52 | } 53 | } 54 | `; 55 | -------------------------------------------------------------------------------- /src/app/utility/fuzzyMatch.function.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Compares the similarity between two strings using an n-gram comparison method. 3 | * The grams default to length 2. 4 | * @param str1 The first string to compare. 5 | * @param str2 The second string to compare. 6 | * @param gramSize The size of the grams. Defaults to length 2. 7 | */ 8 | export function fuzzyMatch(str1: string, str2: string, gramSize: number = 2) { 9 | function getNGrams(s: string, len: number) { 10 | s = ' '.repeat(len - 1) + s.toLowerCase() + ' '.repeat(len - 1); 11 | const v = new Array(s.length - len + 1); 12 | for (let i = 0; i < v.length; i++) { 13 | v[i] = s.slice(i, i + len); 14 | } 15 | return v; 16 | } 17 | 18 | if (!str1?.length || !str2?.length) { 19 | return 0.0; 20 | } 21 | 22 | // Order the strings by length so the order they're passed in doesn't matter 23 | // and so the smaller string's ngrams are always the ones in the set 24 | const s1 = str1.length < str2.length ? str1 : str2; 25 | const s2 = str1.length < str2.length ? str2 : str1; 26 | 27 | const pairs1 = getNGrams(s1, gramSize); 28 | const pairs2 = getNGrams(s2, gramSize); 29 | const set = new Set(pairs1); 30 | 31 | const total = pairs2.length; 32 | let hits = 0; 33 | for (const item of pairs2) { 34 | if (set.delete(item)) { 35 | hits++; 36 | } 37 | } 38 | return hits / total; 39 | } -------------------------------------------------------------------------------- /src/app/validators/json.function.ts: -------------------------------------------------------------------------------- 1 | export function validateJSON(control: any) { 2 | const value = control.value?.toString()?.trim(); 3 | 4 | try { 5 | if (value && value.length > 0) { 6 | JSON.parse(control.value); 7 | } 8 | return null; 9 | } catch { 10 | return { error: 'invalid JSON' }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erangeles/techstack/7cf85a0f1e4603e0de7dab42748d5ca310b0b63a/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/heart.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/assets/stack-white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | background 5 | 6 | 7 | 8 | Layer 1 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/assets/stack.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erangeles/techstack/7cf85a0f1e4603e0de7dab42748d5ca310b0b63a/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TechStack 6 | 7 | 8 | 9 | 13 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | import 'codemirror/mode/javascript/javascript'; 4 | import 'codemirror/mode/markdown/markdown'; 5 | import { AppModule } from './app/app.module'; 6 | import { environment } from './environments/environment'; 7 | 8 | 9 | if (environment.production) { 10 | enableProdMode(); 11 | } 12 | 13 | platformBrowserDynamic().bootstrapModule(AppModule) 14 | .catch(err => console.error(err)); 15 | 16 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /*************************************************************************************************** 2 | * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. 3 | */ 4 | import '@angular/localize/init'; 5 | /** 6 | * This file includes polyfills needed by Angular and is loaded before the app. 7 | * You can add your own extra polyfills to this file. 8 | * 9 | * This file is divided into 2 sections: 10 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 11 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 12 | * file. 13 | * 14 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 15 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 16 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 17 | * 18 | * Learn more in https://angular.io/guide/browser-support 19 | */ 20 | 21 | /*************************************************************************************************** 22 | * BROWSER POLYFILLS 23 | */ 24 | 25 | /** IE11 requires the following for NgClass support on SVG elements */ 26 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 27 | 28 | /** 29 | * Web Animations `@angular/platform-browser/animations` 30 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 31 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 32 | */ 33 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 34 | 35 | /** 36 | * By default, zone.js will patch all possible macroTask and DomEvents 37 | * user can disable parts of macroTask/DomEvents patch by setting following flags 38 | * because those flags need to be set before `zone.js` being loaded, and webpack 39 | * will put import in the top of bundle, so user need to create a separate file 40 | * in this directory (for example: zone-flags.ts), and put the following flags 41 | * into that file, and then add the following code before importing zone.js. 42 | * import './zone-flags'; 43 | * 44 | * The flags allowed in zone-flags.ts are listed here. 45 | * 46 | * The following flags will work for all browsers. 47 | * 48 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 49 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 50 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 51 | * 52 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 53 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 54 | * 55 | * (window as any).__Zone_enable_cross_context_check = true; 56 | * 57 | */ 58 | 59 | /*************************************************************************************************** 60 | * Zone JS is required by default for Angular itself. 61 | */ 62 | import 'zone.js/dist/zone'; // Included with Angular CLI. 63 | 64 | 65 | /*************************************************************************************************** 66 | * APPLICATION IMPORTS 67 | */ 68 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import "~codemirror/lib/codemirror"; 3 | @import "~codemirror/theme/material"; 4 | 5 | * { 6 | margin: 0; 7 | padding: 0; 8 | } 9 | 10 | .all-wrap { 11 | min-height: 100vh; // same height as browser window height 12 | } 13 | 14 | .page-wrap { 15 | display: flex; 16 | flex-direction: column; 17 | min-height: 100vh; // same height as browser window height 18 | } 19 | 20 | .content { 21 | flex: 1; // child will set to an equal size inside the container 22 | } 23 | 24 | mat-grid-list { 25 | background-color: #383838; 26 | } 27 | 28 | /* 29 | * Make the component injected by full height: 30 | */ 31 | 32 | main { 33 | display: flex; 34 | flex-direction: column; 35 | 36 | // Select all direct descendants only of the
element 37 | // that are not elements: 38 | > *:not(router-outlet) { 39 | flex: 1; // child will set to an equal size inside the container 40 | display: block; 41 | } 42 | } 43 | 44 | html, 45 | body { 46 | max-width: 100%; 47 | overflow-x: hidden; 48 | } 49 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts", 10 | "src/polyfills.ts" 11 | ], 12 | "include": [ 13 | "src/**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitReturns": true, 10 | "noFallthroughCasesInSwitch": true, 11 | "sourceMap": true, 12 | "declaration": false, 13 | "downlevelIteration": true, 14 | "experimentalDecorators": true, 15 | "strictNullChecks": false, 16 | "moduleResolution": "node", 17 | "importHelpers": true, 18 | "target": "es2015", 19 | "module": "es2020", 20 | "lib": [ 21 | "es2018", 22 | "dom" 23 | ] 24 | }, 25 | "angularCompilerOptions": { 26 | "strictInjectionParameters": true, 27 | "strictInputAccessModifiers": true, 28 | "strictTemplates": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rulesDirectory": [ 4 | "codelyzer" 5 | ], 6 | "rules": { 7 | "align": { 8 | "options": [ 9 | "parameters", 10 | "statements" 11 | ] 12 | }, 13 | "array-type": false, 14 | "arrow-return-shorthand": true, 15 | "curly": true, 16 | "deprecation": { 17 | "severity": "warning" 18 | }, 19 | "eofline": true, 20 | "import-blacklist": [ 21 | true, 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": { 26 | "options": [ 27 | "spaces" 28 | ] 29 | }, 30 | "max-classes-per-file": false, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-ordering": [ 36 | true, 37 | { 38 | "order": [ 39 | "static-field", 40 | "instance-field", 41 | "static-method", 42 | "instance-method" 43 | ] 44 | } 45 | ], 46 | "no-console": [ 47 | true, 48 | "debug", 49 | "info", 50 | "time", 51 | "timeEnd", 52 | "trace" 53 | ], 54 | "no-empty": false, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-non-null-assertion": true, 60 | "no-redundant-jsdoc": true, 61 | "no-switch-case-fall-through": true, 62 | "no-var-requires": false, 63 | "object-literal-key-quotes": [ 64 | true, 65 | "as-needed" 66 | ], 67 | "quotemark": [ 68 | true, 69 | "single" 70 | ], 71 | "semicolon": { 72 | "options": [ 73 | "always" 74 | ] 75 | }, 76 | "space-before-function-paren": { 77 | "options": { 78 | "anonymous": "never", 79 | "asyncArrow": "always", 80 | "constructor": "never", 81 | "method": "never", 82 | "named": "never" 83 | } 84 | }, 85 | "typedef": [ 86 | false, 87 | "call-signature" 88 | ], 89 | "typedef-whitespace": { 90 | "options": [ 91 | { 92 | "call-signature": "nospace", 93 | "index-signature": "nospace", 94 | "parameter": "nospace", 95 | "property-declaration": "nospace", 96 | "variable-declaration": "nospace" 97 | }, 98 | { 99 | "call-signature": "onespace", 100 | "index-signature": "onespace", 101 | "parameter": "onespace", 102 | "property-declaration": "onespace", 103 | "variable-declaration": "onespace" 104 | } 105 | ] 106 | }, 107 | "variable-name": { 108 | "options": [ 109 | "ban-keywords", 110 | "check-format", 111 | "allow-pascal-case" 112 | ] 113 | }, 114 | "whitespace": { 115 | "options": [ 116 | "check-branch", 117 | "check-decl", 118 | "check-operator", 119 | "check-separator", 120 | "check-type", 121 | "check-typecast" 122 | ] 123 | }, 124 | "component-class-suffix": true, 125 | "contextual-lifecycle": true, 126 | "directive-class-suffix": true, 127 | "no-conflicting-lifecycle": true, 128 | "no-host-metadata-property": true, 129 | "no-input-rename": true, 130 | "no-inputs-metadata-property": true, 131 | "no-output-native": true, 132 | "no-output-on-prefix": true, 133 | "no-output-rename": true, 134 | "no-outputs-metadata-property": true, 135 | "template-banana-in-box": true, 136 | "template-no-negated-async": true, 137 | "use-lifecycle-interface": true, 138 | "use-pipe-transform-interface": true, 139 | "directive-selector": [ 140 | true, 141 | "attribute", 142 | "app", 143 | "camelCase" 144 | ], 145 | "component-selector": [ 146 | true, 147 | "element", 148 | "app", 149 | "kebab-case" 150 | ] 151 | } 152 | } 153 | --------------------------------------------------------------------------------