├── .editorconfig
├── .gitignore
├── .vscode
└── settings.json
├── LICENSE.md
├── README.md
├── angular.json
├── e2e
├── protractor.conf.js
├── src
│ ├── app.e2e-spec.ts
│ └── app.po.ts
└── tsconfig.e2e.json
├── main.js
├── package-lock.json
├── package.json
├── src
├── app
│ ├── app.component.css
│ ├── app.component.html
│ ├── app.component.spec.ts
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── file.service.spec.ts
│ ├── file.service.ts
│ ├── md-viewer
│ │ ├── md-viewer.component.css
│ │ ├── md-viewer.component.html
│ │ ├── md-viewer.component.spec.ts
│ │ └── md-viewer.component.ts
│ ├── modulebar
│ │ ├── modulebar.component.css
│ │ ├── modulebar.component.html
│ │ ├── modulebar.component.spec.ts
│ │ └── modulebar.component.ts
│ └── projectbar
│ │ ├── projectbar.component.css
│ │ ├── projectbar.component.html
│ │ ├── projectbar.component.spec.ts
│ │ └── projectbar.component.ts
├── assets
│ ├── .gitkeep
│ ├── README.md
│ ├── down.png
│ ├── github-markdown.css
│ ├── logo.icns
│ └── moddoc.svg
├── browserslist
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── karma.conf.js
├── main.ts
├── polyfills.ts
├── styles.css
├── test.ts
├── tsconfig.app.json
├── tsconfig.spec.json
└── tslint.json
├── tsconfig.json
└── tslint.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /dist
5 | /tmp
6 | /out-tsc
7 | /release-builds
8 |
9 | # dependencies
10 | /node_modules
11 | # IDEs and editors
12 | /.idea
13 | .project
14 | .classpath
15 | .c9/
16 | *.launch
17 | .settings/
18 | *.sublime-workspace
19 |
20 | # IDE - VSCode
21 | .vscode/*
22 | !.vscode/settings.json
23 | !.vscode/tasks.json
24 | !.vscode/launch.json
25 | !.vscode/extensions.json
26 |
27 | # misc
28 | /.sass-cache
29 | /connect.lock
30 | /coverage
31 | /libpeerconnection.log
32 | npm-debug.log
33 | yarn-error.log
34 | testem.log
35 | /typings
36 |
37 | # System Files
38 | .DS_Store
39 | Thumbs.db
40 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "workbench.colorCustomizations": {
3 | "titleBar.activeBackground": "#b52e31",
4 | "titleBar.inactiveBackground": "#b52e3199",
5 | "titleBar.activeForeground": "#e7e7e7",
6 | "titleBar.inactiveForeground": "#e7e7e799"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2019 Moddoc
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 | ## Moddoc
4 |
5 | 🐶 Best way to see the Documentation of Node Modules in your Project.
6 |
7 | 
8 |
9 |
10 |
11 | ## Prerequisites
12 |
13 | Before running this locally you must have these installed
14 |
15 | + Node
16 | + Electron
17 |
18 | ## Installing
19 |
20 | It's built in electron so the process to start this is really easy
21 |
22 | 1. `npm install`
23 | 2. `npm install electron -g`
24 | 3. `npm run electron-tsc`
25 |
26 | That's it.
27 |
28 | ## Features
29 |
30 | ***1. Open multiple projects at a time***
31 |
32 | ***2. Shows both dependencies and dev dependencies***
33 |
34 | ***3. Quick copy widget***
35 |
36 | ***4. In-app browser for external links***
37 |
38 | ***5. Offline access to Documentation***
39 |
40 | ## Contributing
41 |
42 | Feel free to contribute to this project and treat it like your own. 😊
43 |
44 | ## License
45 |
46 | MIT License
47 |
48 | ## Author
49 |
50 | [Sarthak Sharma](https://twitter.com/sarthology)
51 |
52 | ## Acknowledgments
53 |
54 | Icons used from [flaticon](https://flaticon.com)
55 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "moddoc": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {},
12 | "architect": {
13 | "build": {
14 | "builder": "@angular-devkit/build-angular:browser",
15 | "options": {
16 | "outputPath": "dist",
17 | "index": "src/index.html",
18 | "main": "src/main.ts",
19 | "polyfills": "src/polyfills.ts",
20 | "tsConfig": "src/tsconfig.app.json",
21 | "assets": [
22 | "src/favicon.ico",
23 | "src/assets"
24 | ],
25 | "styles": [
26 | "src/styles.css"
27 | ],
28 | "scripts": []
29 | },
30 | "configurations": {
31 | "production": {
32 | "fileReplacements": [
33 | {
34 | "replace": "src/environments/environment.ts",
35 | "with": "src/environments/environment.prod.ts"
36 | }
37 | ],
38 | "optimization": true,
39 | "outputHashing": "all",
40 | "sourceMap": false,
41 | "extractCss": true,
42 | "namedChunks": false,
43 | "aot": true,
44 | "extractLicenses": true,
45 | "vendorChunk": false,
46 | "buildOptimizer": true
47 | }
48 | }
49 | },
50 | "serve": {
51 | "builder": "@angular-devkit/build-angular:dev-server",
52 | "options": {
53 | "browserTarget": "moddoc:build"
54 | },
55 | "configurations": {
56 | "production": {
57 | "browserTarget": "moddoc:build:production"
58 | }
59 | }
60 | },
61 | "extract-i18n": {
62 | "builder": "@angular-devkit/build-angular:extract-i18n",
63 | "options": {
64 | "browserTarget": "moddoc:build"
65 | }
66 | },
67 | "test": {
68 | "builder": "@angular-devkit/build-angular:karma",
69 | "options": {
70 | "main": "src/test.ts",
71 | "polyfills": "src/polyfills.ts",
72 | "tsConfig": "src/tsconfig.spec.json",
73 | "karmaConfig": "src/karma.conf.js",
74 | "styles": [
75 | "src/styles.css"
76 | ],
77 | "scripts": [],
78 | "assets": [
79 | "src/favicon.ico",
80 | "src/assets"
81 | ]
82 | }
83 | },
84 | "lint": {
85 | "builder": "@angular-devkit/build-angular:tslint",
86 | "options": {
87 | "tsConfig": [
88 | "src/tsconfig.app.json",
89 | "src/tsconfig.spec.json"
90 | ],
91 | "exclude": [
92 | "**/node_modules/**"
93 | ]
94 | }
95 | }
96 | }
97 | },
98 | "moddoc-e2e": {
99 | "root": "e2e/",
100 | "projectType": "application",
101 | "architect": {
102 | "e2e": {
103 | "builder": "@angular-devkit/build-angular:protractor",
104 | "options": {
105 | "protractorConfig": "e2e/protractor.conf.js",
106 | "devServerTarget": "moddoc:serve"
107 | },
108 | "configurations": {
109 | "production": {
110 | "devServerTarget": "moddoc:serve:production"
111 | }
112 | }
113 | },
114 | "lint": {
115 | "builder": "@angular-devkit/build-angular:tslint",
116 | "options": {
117 | "tsConfig": "e2e/tsconfig.e2e.json",
118 | "exclude": [
119 | "**/node_modules/**"
120 | ]
121 | }
122 | }
123 | }
124 | }
125 | },
126 | "defaultProject": "moddoc"
127 | }
--------------------------------------------------------------------------------
/e2e/protractor.conf.js:
--------------------------------------------------------------------------------
1 | // Protractor configuration file, see link for more information
2 | // https://github.com/angular/protractor/blob/master/lib/config.ts
3 |
4 | const { SpecReporter } = require('jasmine-spec-reporter');
5 |
6 | exports.config = {
7 | allScriptsTimeout: 11000,
8 | specs: [
9 | './src/**/*.e2e-spec.ts'
10 | ],
11 | capabilities: {
12 | 'browserName': 'chrome'
13 | },
14 | directConnect: true,
15 | baseUrl: 'http://localhost:4200/',
16 | framework: 'jasmine',
17 | jasmineNodeOpts: {
18 | showColors: true,
19 | defaultTimeoutInterval: 30000,
20 | print: function() {}
21 | },
22 | onPrepare() {
23 | require('ts-node').register({
24 | project: require('path').join(__dirname, './tsconfig.e2e.json')
25 | });
26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
27 | }
28 | };
--------------------------------------------------------------------------------
/e2e/src/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { AppPage } from './app.po';
2 |
3 | describe('workspace-project App', () => {
4 | let page: AppPage;
5 |
6 | beforeEach(() => {
7 | page = new AppPage();
8 | });
9 |
10 | it('should display welcome message', () => {
11 | page.navigateTo();
12 | expect(page.getParagraphText()).toEqual('Welcome to moddoc!');
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/e2e/src/app.po.ts:
--------------------------------------------------------------------------------
1 | import { browser, by, element } from 'protractor';
2 |
3 | export class AppPage {
4 | navigateTo() {
5 | return browser.get('/');
6 | }
7 |
8 | getParagraphText() {
9 | return element(by.css('app-root h1')).getText();
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/e2e/tsconfig.e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../out-tsc/app",
5 | "module": "commonjs",
6 | "target": "es5",
7 | "types": [
8 | "jasmine",
9 | "jasminewd2",
10 | "node"
11 | ]
12 | }
13 | }
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const {
4 | app,
5 | BrowserWindow,
6 | ipcMain,
7 | dialog,
8 | clipboard,
9 | Menu,
10 | MenuItem
11 | } = require('electron');
12 | const path = require('path');
13 | const url = require('url');
14 | const fs = require('fs');
15 | const os = require('os');
16 | const { autoUpdater } = require('electron-updater');
17 | const macAddress = require('macaddress');
18 | const pJSON = require('./package.json');
19 |
20 | let win, initialData;
21 | const menu = new Menu();
22 | menu.append(
23 | new MenuItem({
24 | label: 'Remove',
25 | click() {
26 | BrowserWindow.getFocusedWindow().webContents.send('removeProject');
27 | }
28 | })
29 | );
30 |
31 | const isPackaged = !process.defaultApp;
32 |
33 | const input = isPackaged ? process.argv[1] : process.argv.splice(2)[0];
34 |
35 | function createWindow() {
36 | win = new BrowserWindow();
37 |
38 | win.maximize();
39 |
40 | // load the dist folder from Angular
41 | win.loadURL(
42 | url.format({
43 | pathname: path.join(__dirname, '/dist/index.html'),
44 | protocol: 'file:',
45 | slashes: true
46 | })
47 | );
48 |
49 | // The following is optional and will open the DevTools:
50 |
51 | win.on('closed', () => {
52 | win = null;
53 | });
54 | }
55 |
56 | function addAnalytics() {
57 | macAddress.one(function(err, mac) {
58 | BrowserWindow.getFocusedWindow().webContents.send('addAnalytics', {
59 | macAddress: mac,
60 | os: os.platform(),
61 | version: pJSON.version
62 | });
63 | });
64 | }
65 |
66 | app.on('ready', () => {
67 | createWindow();
68 | autoUpdater.checkForUpdates();
69 | if (input) {
70 | initialData = addProject(input);
71 | }
72 | });
73 |
74 | ipcMain.on('getFiles', (event, arg) => {
75 | if (initialData && input) {
76 | initialData
77 | ? (initialData = { file: input, ...initialData })
78 | : (initialData = null);
79 | win.webContents.send('getFilesResponse', initialData);
80 | initialData = null;
81 | } else {
82 | dialog.showOpenDialog({ properties: ['openDirectory'] }, filePaths => {
83 | if (filePaths) {
84 | let data = addProject(filePaths[0]);
85 | data ? (data = { file: filePaths[0], ...data }) : (data = null);
86 | win.webContents.send('getFilesResponse', data);
87 | } else win.webContents.send('getFilesResponse', null);
88 | });
89 | }
90 | });
91 |
92 | ipcMain.on('copyCode', (event, code) => {
93 | clipboard.writeText(code);
94 | });
95 |
96 | ipcMain.on('onFileError', event => {
97 | dialog.showErrorBox('No Readme', "This package don't have a readme file.");
98 | });
99 |
100 | ipcMain.on('onAlreadyExist', event => {
101 | dialog.showErrorBox(
102 | 'Duplicate Project',
103 | 'This package already being added. Add another.'
104 | );
105 | });
106 |
107 | ipcMain.on('openMenu', event => {
108 | menu.popup();
109 | });
110 |
111 | // on macOS, closing the window doesn't quit the app
112 | app.on('window-all-closed', () => {
113 | if (process.platform !== 'darwin') {
114 | app.quit();
115 | }
116 | });
117 |
118 | // initialize the app's main window
119 | app.on('activate', () => {
120 | if (win === null) {
121 | createWindow();
122 | }
123 | });
124 |
125 | let addProject = filePath => {
126 | if (fs.existsSync(filePath + '/package.json')) {
127 | data = fs.readFileSync(filePath + '/package.json', 'utf8');
128 | addAnalytics();
129 | return JSON.parse(data);
130 | } else {
131 | dialog.showMessageBox({
132 | type: 'info',
133 | message: 'Your Project is not node based.',
134 | buttons: ['ok']
135 | });
136 | return null;
137 | }
138 | };
139 |
140 | autoUpdater.on('update-available', () => {
141 | dialog.showMessageBox(
142 | {
143 | type: 'info',
144 | title: 'Found Updates',
145 | message: 'Found updates, do you want update now?',
146 | buttons: ['Sure', 'No']
147 | },
148 | buttonIndex => {
149 | if (buttonIndex === 0) {
150 | autoUpdater.downloadUpdate();
151 |
152 | dialog.showMessageBox({
153 | type: 'info',
154 | title: 'Downloading',
155 | message: 'Updates are downloading, will notify once done.'
156 | });
157 | }
158 | }
159 | );
160 | });
161 |
162 | autoUpdater.on('update-downloaded', () => {
163 | dialog.showMessageBox(
164 | {
165 | title: 'Install Updates',
166 | message: 'Updates downloaded, application will be quit for update...'
167 | },
168 | () => {
169 | setImmediate(() => autoUpdater.quitAndInstall());
170 | }
171 | );
172 | });
173 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "moddoc",
3 | "description": "A new way to read Documentation of Node Modules",
4 | "version": "0.0.1",
5 | "main": "main.js",
6 | "scripts": {
7 | "ng": "ng",
8 | "start": "ng serve",
9 | "build": "ng build --prod --base-href ./",
10 | "test": "ng test",
11 | "lint": "ng lint",
12 | "e2e": "ng e2e",
13 | "electron-tsc": "ng build --base-href ./ && electron .",
14 | "build:mac": "npm run build && build --linux",
15 | "build:linux": "npm run build && build --linux",
16 | "ship": "build --mac -p always"
17 | },
18 | "build": {
19 | "appId": "com.github.sarthak.moddoc",
20 | "productName": "moddoc",
21 | "files": [
22 | "**/*",
23 | "dist/**/*"
24 | ],
25 | "directories": {
26 | "output": "release",
27 | "buildResources": "dist"
28 | },
29 | "linux": {
30 | "category": "Utility",
31 | "target": [
32 | {
33 | "target": "deb",
34 | "arch": [
35 | "x64"
36 | ]
37 | }
38 | ]
39 | }
40 | },
41 | "author": "Sarthology ",
42 | "license": "MIT",
43 | "private": true,
44 | "dependencies": {
45 | "@angular/animations": "^6.1.0",
46 | "@angular/common": "^6.1.0",
47 | "@angular/compiler": "^6.1.0",
48 | "@angular/core": "^6.1.0",
49 | "@angular/forms": "^6.1.0",
50 | "@angular/http": "^6.1.0",
51 | "@angular/platform-browser": "^6.1.0",
52 | "@angular/platform-browser-dynamic": "^6.1.0",
53 | "@angular/router": "^6.1.0",
54 | "core-js": "^2.5.4",
55 | "electron-store": "^3.2.0",
56 | "electron-updater": "^4.0.6",
57 | "github-markdown-css": "^3.0.1",
58 | "macaddress": "^0.2.9",
59 | "ngx-electron": "^2.1.1",
60 | "ngx-markdown": "^7.1.4",
61 | "rxjs": "~6.2.0",
62 | "zone.js": "~0.8.26"
63 | },
64 | "devDependencies": {
65 | "@angular-devkit/build-angular": "~0.8.0",
66 | "@angular/cli": "~6.2.3",
67 | "@angular/compiler-cli": "^6.1.0",
68 | "@angular/language-service": "^6.1.0",
69 | "@types/jasmine": "~2.8.8",
70 | "@types/jasminewd2": "~2.0.3",
71 | "@types/node": "^8.9.5",
72 | "codelyzer": "~4.3.0",
73 | "electron": "^4.0.1",
74 | "electron-builder": "^20.39.0",
75 | "jasmine-core": "~2.99.1",
76 | "jasmine-spec-reporter": "~4.2.1",
77 | "karma": "~3.0.0",
78 | "karma-chrome-launcher": "~2.2.0",
79 | "karma-coverage-istanbul-reporter": "~2.0.1",
80 | "karma-jasmine": "~1.1.2",
81 | "karma-jasmine-html-reporter": "^0.2.2",
82 | "protractor": "~5.4.0",
83 | "ts-node": "~7.0.0",
84 | "tslint": "~5.11.0",
85 | "typescript": "~2.9.2"
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/app/app.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/app.component.css
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/app/app.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed, async } from '@angular/core/testing';
2 | import { AppComponent } from './app.component';
3 | describe('AppComponent', () => {
4 | beforeEach(async(() => {
5 | TestBed.configureTestingModule({
6 | declarations: [
7 | AppComponent
8 | ],
9 | }).compileComponents();
10 | }));
11 | it('should create the app', async(() => {
12 | const fixture = TestBed.createComponent(AppComponent);
13 | const app = fixture.debugElement.componentInstance;
14 | expect(app).toBeTruthy();
15 | }));
16 | it(`should have as title 'moddoc'`, async(() => {
17 | const fixture = TestBed.createComponent(AppComponent);
18 | const app = fixture.debugElement.componentInstance;
19 | expect(app.title).toEqual('moddoc');
20 | }));
21 | it('should render title in a h1 tag', async(() => {
22 | const fixture = TestBed.createComponent(AppComponent);
23 | fixture.detectChanges();
24 | const compiled = fixture.debugElement.nativeElement;
25 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to moddoc!');
26 | }));
27 | });
28 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component} from '@angular/core';
2 |
3 | @Component({
4 | selector: 'app-root',
5 | templateUrl: './app.component.html',
6 | styleUrls: ['./app.component.css']
7 | })
8 | export class AppComponent {
9 | title = 'moddoc';
10 | public src:string;
11 | public project:object;
12 |
13 | constructor(){
14 |
15 | }
16 |
17 | receiveModule($event) {
18 | this.src = $event
19 | }
20 |
21 | receiveProject($event) {
22 | console.log($event);
23 |
24 | this.project = $event
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule, CUSTOM_ELEMENTS_SCHEMA, NO_ERRORS_SCHEMA } from '@angular/core';
3 | import { MarkdownModule } from 'ngx-markdown';
4 |
5 | import { AppComponent } from './app.component';
6 | import { HttpClientModule, HttpClient } from '@angular/common/http';
7 | import { MdViewerComponent } from './md-viewer/md-viewer.component';
8 | import { ProjectbarComponent } from './projectbar/projectbar.component';
9 | import { ModulebarComponent } from './modulebar/modulebar.component';
10 | import { NgxElectronModule } from 'ngx-electron';
11 |
12 | @NgModule({
13 | declarations: [
14 | AppComponent,
15 | MdViewerComponent,
16 | ProjectbarComponent,
17 | ModulebarComponent
18 | ],
19 | imports: [
20 | BrowserModule,
21 | HttpClientModule,
22 | MarkdownModule.forRoot({ loader: HttpClient }),
23 | NgxElectronModule
24 | ],
25 | providers: [],
26 | bootstrap: [AppComponent],
27 | schemas: [NO_ERRORS_SCHEMA,CUSTOM_ELEMENTS_SCHEMA]
28 | })
29 | export class AppModule { }
30 |
--------------------------------------------------------------------------------
/src/app/file.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { TestBed } from '@angular/core/testing';
2 |
3 | import { FileService } from './file.service';
4 |
5 | describe('FileService', () => {
6 | beforeEach(() => TestBed.configureTestingModule({}));
7 |
8 | it('should be created', () => {
9 | const service: FileService = TestBed.get(FileService);
10 | expect(service).toBeTruthy();
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/src/app/file.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { ElectronService } from 'ngx-electron';
3 | import { Subject } from 'rxjs/internal/Subject';
4 | import { HttpClient } from '@angular/common/http';
5 | import { environment } from 'src/environments/environment';
6 |
7 | @Injectable({
8 | providedIn: 'root'
9 | })
10 | export class FileService {
11 | public projects: Array<{ file: string; data: Object }> = [];
12 | public currentModule: string;
13 | public _listners = new Subject();
14 |
15 | constructor(
16 | private _electronService: ElectronService,
17 | private http: HttpClient
18 | ) {
19 | this._electronService.ipcRenderer.on('addAnalytics', (event, data) => {
20 | this.http
21 | .post(environment.API + '/addUser', {
22 | macAddress: data.macAddress,
23 | platform: data.os,
24 | version: data.version
25 | })
26 | .subscribe(
27 | res => {
28 | // Success
29 | },
30 | err => {
31 | // Show error dialog
32 | }
33 | );
34 | });
35 | }
36 |
37 | async getFiles() {
38 | return new Promise((resolve, reject) => {
39 | this._electronService.ipcRenderer.once(
40 | 'getFilesResponse',
41 | (event, arg) => {
42 | if (arg && this.distinct(this.projects, arg)) {
43 | this.projects.push(arg);
44 | resolve(arg);
45 | } else {
46 | reject();
47 | }
48 | }
49 | );
50 | this._electronService.ipcRenderer.send('getFiles');
51 | });
52 | }
53 |
54 | copyCode(data) {
55 | return this._electronService.ipcRenderer.send('copyCode', data);
56 | }
57 |
58 | noFileError(error) {
59 | return this._electronService.ipcRenderer.send('onFileError', error);
60 | }
61 | distinct(projects: any, arg) {
62 | if (projects.filter(project => project.file === arg.file).length === 1) {
63 | this._electronService.ipcRenderer.send('onAlreadyExist', 'project');
64 | return false;
65 | } else if (projects.length === 0) {
66 | return true;
67 | } else {
68 | return true;
69 | }
70 | }
71 |
72 | async openMenu(project) {
73 | return new Promise>((res, rej) => {
74 | this._electronService.ipcRenderer.on('removeProject', event => {
75 | this.projects = this.projects.filter(
76 | element => element.file != project.file
77 | );
78 | res(this.projects);
79 | });
80 | this._electronService.ipcRenderer.send('openMenu');
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/app/md-viewer/md-viewer.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/md-viewer/md-viewer.component.css
--------------------------------------------------------------------------------
/src/app/md-viewer/md-viewer.component.html:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/src/app/md-viewer/md-viewer.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { MdViewerComponent } from './md-viewer.component';
4 |
5 | describe('MdViewerComponent', () => {
6 | let component: MdViewerComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ MdViewerComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(MdViewerComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/app/md-viewer/md-viewer.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Input } from '@angular/core';
2 | import { MarkdownService } from 'ngx-markdown';
3 | import { FileService } from '../file.service';
4 |
5 | @Component({
6 | selector: 'md-viewer',
7 | templateUrl: './md-viewer.component.html',
8 | styleUrls: ['./md-viewer.component.css']
9 | })
10 | export class MdViewerComponent implements OnInit {
11 | @Input() src: string;
12 | public externalLink: string;
13 | public copyText;
14 |
15 | constructor(
16 | private markdownService: MarkdownService,
17 | private fileService: FileService
18 | ) {}
19 |
20 | ngOnInit() {
21 | this.markdownService.renderer.heading = (text: string, level: number) => {
22 | if (text.indexOf(':') === text.length - 1) text = text.replace(':', '');
23 | const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');
24 | return (
25 | '' + text + ''
26 | );
27 | };
28 | this.copyText = event => {
29 | this.fileService.copyCode(event.target.parentNode.nextSibling.innerText);
30 | event.target.innerText = 'copied';
31 | setTimeout(() => {
32 | event.target.innerText = 'copy';
33 | }, 2000);
34 | };
35 |
36 | this.fileService._listners.subscribe(res => {
37 | console.log('s');
38 | this.clear();
39 | });
40 | }
41 |
42 | onLoad(e) {
43 | this.src = null;
44 | window.scrollTo(0, 0);
45 | document
46 | .querySelector('.markdown-body')
47 | .setAttribute('style', 'display:block');
48 | document.querySelectorAll('a').forEach(e => {
49 | let href = e.getAttribute('href');
50 | e.onclick = event => {
51 | event.preventDefault();
52 | if (href.indexOf('#') === 0) {
53 | var top = document.getElementById(href.split('#')[1]).offsetTop;
54 | window.scrollTo(0, top);
55 | } else {
56 | document
57 | .querySelector('.markdown-body')
58 | .setAttribute('style', 'display:none');
59 | document
60 | .querySelector('.browser-body')
61 | .setAttribute('style', 'display:block');
62 | document.querySelector('webview').setAttribute('src', href);
63 | }
64 | };
65 | });
66 |
67 | document.querySelectorAll('pre').forEach(e => {
68 | var span = document.createElement('div');
69 | span.innerHTML = 'copy';
70 | span.id = 'clipper';
71 | e.insertBefore(span, e.firstChild);
72 | span.addEventListener('click', this.copyText, false);
73 | });
74 | }
75 |
76 | noError(e) {
77 | this.fileService.noFileError(e);
78 | }
79 |
80 | reset() {
81 | document
82 | .querySelector('.markdown-body')
83 | .setAttribute('style', 'display:block');
84 | document
85 | .querySelector('.browser-body')
86 | .setAttribute('style', 'display:none');
87 | }
88 |
89 | clear() {
90 | document
91 | .querySelector('.markdown-body')
92 | .setAttribute('style', 'display:none');
93 | document
94 | .querySelector('.browser-body')
95 | .setAttribute('style', 'display:none');
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/app/modulebar/modulebar.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/modulebar/modulebar.component.css
--------------------------------------------------------------------------------
/src/app/modulebar/modulebar.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Modules
4 |
5 |
6 |
7 |
8 |
Dependencies List
9 |
10 |
11 |
12 |
{{dev}} {{project.dependencies[dev]}}
13 |
14 |
15 |
16 |
17 |
18 |
Dev Dependencies List
19 |
20 |
21 |
22 |
{{dev}} {{project.devDependencies[dev]}}
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/src/app/modulebar/modulebar.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ModulebarComponent } from './modulebar.component';
4 |
5 | describe('ModulebarComponent', () => {
6 | let component: ModulebarComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ModulebarComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ModulebarComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/app/modulebar/modulebar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
2 |
3 | @Component({
4 | selector: 'modulebar',
5 | templateUrl: './modulebar.component.html',
6 | styleUrls: ['./modulebar.component.css']
7 | })
8 |
9 | export class ModulebarComponent implements OnInit {
10 |
11 | public moduleHide:boolean = true;
12 | public devHide:boolean = true;
13 | public objectKeys = Object.keys;
14 |
15 | @Output() currentModule = new EventEmitter();
16 | @Input() project: {file:string};
17 |
18 | constructor() { }
19 |
20 | ngOnInit() {
21 | }
22 |
23 | setCurrentModule(module){
24 | this.currentModule.emit(this.project.file +"/node_modules/"+module+"/README.md");
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/app/projectbar/projectbar.component.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sarthology/moddoc/5fcbf9a2810cae3aba0b180bdb59c44f6a5e6de1/src/app/projectbar/projectbar.component.css
--------------------------------------------------------------------------------
/src/app/projectbar/projectbar.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
7 |
8 |
10 |
{{project.name}}
11 |
{{highlightProject()}}
12 |
13 |
14 |
15 |
16 |
+
17 |
18 |
--------------------------------------------------------------------------------
/src/app/projectbar/projectbar.component.spec.ts:
--------------------------------------------------------------------------------
1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2 |
3 | import { ProjectbarComponent } from './projectbar.component';
4 |
5 | describe('ProjectbarComponent', () => {
6 | let component: ProjectbarComponent;
7 | let fixture: ComponentFixture;
8 |
9 | beforeEach(async(() => {
10 | TestBed.configureTestingModule({
11 | declarations: [ ProjectbarComponent ]
12 | })
13 | .compileComponents();
14 | }));
15 |
16 | beforeEach(() => {
17 | fixture = TestBed.createComponent(ProjectbarComponent);
18 | component = fixture.componentInstance;
19 | fixture.detectChanges();
20 | });
21 |
22 | it('should create', () => {
23 | expect(component).toBeTruthy();
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/src/app/projectbar/projectbar.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, Output, EventEmitter } from '@angular/core';
2 | import { FileService } from '../file.service';
3 |
4 | @Component({
5 | selector: 'projectbar',
6 | templateUrl: './projectbar.component.html',
7 | styleUrls: ['./projectbar.component.css']
8 | })
9 | export class ProjectbarComponent implements OnInit {
10 | public projects: Array