├── .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 |
3 |
4 | TechStack
5 |
6 |
7 |
8 |
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 |
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 |
4 |
--------------------------------------------------------------------------------
/src/assets/stack-white.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/assets/stack.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 |
--------------------------------------------------------------------------------