├── src ├── assets │ ├── .gitkeep │ ├── background.jpg │ ├── i18n │ │ └── en.json │ ├── more-vertical.svg │ └── more-vertical-light.svg ├── app │ ├── app.component.scss │ ├── add-emoji │ │ ├── add-emoji.component.css │ │ ├── add-emoji.component.html │ │ ├── add-emoji.component.ts │ │ └── add-emoji.component.spec.ts │ ├── app.component.html │ ├── shared │ │ ├── components │ │ │ ├── page-not-found │ │ │ │ ├── page-not-found.component.scss │ │ │ │ ├── page-not-found.component.html │ │ │ │ ├── page-not-found.component.ts │ │ │ │ └── page-not-found.component.spec.ts │ │ │ └── index.ts │ │ ├── directives │ │ │ ├── index.ts │ │ │ └── webview │ │ │ │ ├── webview.directive.ts │ │ │ │ └── webview.directive.spec.ts │ │ └── shared.module.ts │ ├── core │ │ ├── services │ │ │ ├── index.ts │ │ │ ├── electron │ │ │ │ ├── electron.service.spec.ts │ │ │ │ └── electron.service.ts │ │ │ └── markdown.service.ts │ │ └── core.module.ts │ ├── home │ │ ├── home.component.html │ │ ├── home-routing.module.ts │ │ ├── home.component.scss │ │ ├── home.component.spec.ts │ │ ├── home.component.ts │ │ └── home.module.ts │ ├── models │ │ ├── markdown.ts │ │ └── metadata.ts │ ├── load-dialog │ │ ├── load-dialog.component.css │ │ ├── load-dialog.component.html │ │ ├── load-dialog.component.spec.ts │ │ └── load-dialog.component.ts │ ├── save-dialog │ │ ├── save-dialog.component.css │ │ ├── save-dialog.component.html │ │ ├── save-dialog.component.spec.ts │ │ └── save-dialog.component.ts │ ├── app-routing.module.ts │ ├── markup │ │ ├── markup.component.html │ │ ├── markup.component.spec.ts │ │ ├── markup.component.css │ │ └── markup.component.ts │ ├── navbar │ │ ├── navbar.component.spec.ts │ │ ├── navbar.component.html │ │ ├── navbar.component.ts │ │ └── navbar.component.css │ ├── options-dialog │ │ ├── options-dialog.component.css │ │ ├── options-dialog.component.spec.ts │ │ ├── options-dialog.component.html │ │ └── options-dialog.component.ts │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── icons │ │ └── icons.module.ts │ ├── app.module.ts │ └── constants │ │ ├── form-constants.ts │ │ └── app-constants.ts ├── polyfills-test.ts ├── favicon.png ├── favicon.256x256.png ├── favicon.512x512.png ├── environments │ ├── environment.ts │ ├── environment.prod.ts │ └── environment.dev.ts ├── typings.d.ts ├── tsconfig.app.json ├── tsconfig.spec.json ├── main.ts ├── test.ts ├── karma.conf.js ├── manifest.webmanifest ├── polyfills.ts ├── index.html └── styles.scss ├── postcss.config.js ├── _config.yml ├── preview.png ├── logo-angular.jpg ├── logo-electron.jpg ├── e2e ├── tsconfig.e2e.json ├── main.spec.ts └── common-setup.ts ├── .editorconfig ├── .travis.yml ├── browserslist ├── tsconfig-serve.json ├── tsconfig.json ├── postinstall-web.js ├── postinstall.js ├── ngsw-config.json ├── electron-builder.json ├── .gitignore ├── .github ├── workflow │ └── electron.yml └── workflows │ └── electron.yml ├── LICENSE.md ├── main.ts ├── README.md ├── tslint.json ├── package.json ├── angular.json └── CHANGELOG.md /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /src/app/add-emoji/add-emoji.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/shared/components/page-not-found/page-not-found.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/preview.png -------------------------------------------------------------------------------- /src/app/core/services/index.ts: -------------------------------------------------------------------------------- 1 | export * from './electron/electron.service'; 2 | -------------------------------------------------------------------------------- /src/app/shared/directives/index.ts: -------------------------------------------------------------------------------- 1 | export * from './webview/webview.directive'; 2 | -------------------------------------------------------------------------------- /src/polyfills-test.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/es/reflect'; 2 | import 'zone.js/dist/zone'; 3 | -------------------------------------------------------------------------------- /logo-angular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/logo-angular.jpg -------------------------------------------------------------------------------- /src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/src/favicon.png -------------------------------------------------------------------------------- /logo-electron.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/logo-electron.jpg -------------------------------------------------------------------------------- /src/app/shared/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './page-not-found/page-not-found.component'; 2 | -------------------------------------------------------------------------------- /src/favicon.256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/src/favicon.256x256.png -------------------------------------------------------------------------------- /src/favicon.512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/src/favicon.512x512.png -------------------------------------------------------------------------------- /src/assets/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JP1016/Markdown-Electron/HEAD/src/assets/background.jpg -------------------------------------------------------------------------------- /src/app/shared/components/page-not-found/page-not-found.component.html: -------------------------------------------------------------------------------- 1 |

2 | page-not-found works! 3 |

4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | export const AppConfig = { 2 | production: false, 3 | environment: 'LOCAL' 4 | }; 5 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const AppConfig = { 2 | production: false, 3 | environment: 'DEV' 4 | }; 5 | -------------------------------------------------------------------------------- /src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |
6 | -------------------------------------------------------------------------------- /src/assets/i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "PAGES": { 3 | "HOME": { 4 | "TITLE": "App works !" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/app/models/markdown.ts: -------------------------------------------------------------------------------- 1 | export interface MarkDownObject { 2 | id: string; 3 | title: string; 4 | data: string; 5 | timestamp?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/models/metadata.ts: -------------------------------------------------------------------------------- 1 | export interface MetaObject { 2 | link: string; 3 | description: string; 4 | type: string; 5 | descr?: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/add-emoji/add-emoji.component.html: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/app/shared/directives/webview/webview.directive.ts: -------------------------------------------------------------------------------- 1 | import { Directive } from '@angular/core'; 2 | 3 | @Directive({ 4 | selector: '[webview]' 5 | }) 6 | export class WebviewDirective { 7 | constructor() {} 8 | } 9 | -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var nodeModule: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | 7 | declare var window: Window; 8 | interface Window { 9 | process: any; 10 | require: any; 11 | } 12 | -------------------------------------------------------------------------------- /src/app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | @NgModule({ 5 | declarations: [], 6 | imports: [ 7 | CommonModule 8 | ] 9 | }) 10 | export class CoreModule { } 11 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "es2015", 6 | "types": [ 7 | "mocha" 8 | ] 9 | }, 10 | "include": [ 11 | "**/*.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "**/*.spec.ts" 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /src/app/shared/directives/webview/webview.directive.spec.ts: -------------------------------------------------------------------------------- 1 | import { WebviewDirective } from './webview.directive'; 2 | 3 | describe('WebviewDirective', () => { 4 | it('should create an instance', () => { 5 | const directive = new WebviewDirective(); 6 | expect(directive).toBeTruthy(); 7 | }); 8 | }); 9 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /src/assets/more-vertical.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/assets/more-vertical-light.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/app/shared/components/page-not-found/page-not-found.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-page-not-found', 5 | templateUrl: './page-not-found.component.html', 6 | styleUrls: ['./page-not-found.component.scss'] 7 | }) 8 | export class PageNotFoundComponent implements OnInit { 9 | constructor() {} 10 | 11 | ngOnInit() {} 12 | } 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: 2 | - linux 3 | - osx 4 | language: node_js 5 | node_js: 6 | - '12' 7 | - '11' 8 | - '10' 9 | dist: xenial 10 | sudo: required 11 | services: 12 | - xvfb 13 | addons: 14 | chrome: stable 15 | before_script: 16 | - export DISPLAY=:99.0 17 | install: 18 | - npm set progress=false 19 | - npm install 20 | script: 21 | - ng lint 22 | - npm run test 23 | - npm run e2e 24 | - npm run build 25 | -------------------------------------------------------------------------------- /src/app/load-dialog/load-dialog.component.css: -------------------------------------------------------------------------------- 1 | .list-items { 2 | display: flex; 3 | justify-content: space-between; 4 | padding: 8px 0; 5 | justify-content: space-between; 6 | font-size: 19px; 7 | 8 | } 9 | 10 | .list-items span, 11 | .list-items .fe-icon { 12 | cursor: pointer; 13 | } 14 | 15 | .list-items span:hover, 16 | .list-items .fe-icon:hover { 17 | color: var(--note-sub-text); 18 | cursor: pointer; 19 | } 20 | -------------------------------------------------------------------------------- /src/app/core/services/electron/electron.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | 3 | import { ElectronService } from './electron.service'; 4 | 5 | describe('ElectronService', () => { 6 | beforeEach(() => TestBed.configureTestingModule({})); 7 | 8 | it('should be created', () => { 9 | const service: ElectronService = TestBed.get(ElectronService); 10 | expect(service).toBeTruthy(); 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /src/environments/environment.dev.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `index.ts`, but if you do 3 | // `ng build --env=prod` then `index.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const AppConfig = { 7 | production: false, 8 | environment: 'DEV' 9 | }; 10 | -------------------------------------------------------------------------------- /browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "types": [ 7 | "jasmine", 8 | "node" 9 | ] 10 | }, 11 | "files": [ 12 | "test.ts", 13 | "polyfills-test.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ], 19 | "exclude": [ 20 | "dist", 21 | "release", 22 | "node_modules" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import 'hammerjs'; 2 | import { enableProdMode } from '@angular/core'; 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | 5 | import { AppModule } from './app/app.module'; 6 | import { AppConfig } from './environments/environment'; 7 | 8 | if (AppConfig.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic() 13 | .bootstrapModule(AppModule, { 14 | preserveWhitespaces: false 15 | }) 16 | .catch(err => console.error(err)); 17 | -------------------------------------------------------------------------------- /src/app/save-dialog/save-dialog.component.css: -------------------------------------------------------------------------------- 1 | input[type='text'] { 2 | background: var(--btn-hover); 3 | padding: 10px; 4 | border-radius: 4px; 5 | margin-top: 5px; 6 | margin-bottom: 18px; 7 | width: 100%; 8 | } 9 | 10 | .close-icon { 11 | font-size: 30px; 12 | } 13 | 14 | .mat-dialog-actions { 15 | justify-content: flex-end; 16 | margin-bottom: -6px; 17 | } 18 | 19 | .mat-dialog-actions button { 20 | padding: 5px 11px; 21 | background: #1d88e5; 22 | border-radius: 4px; 23 | font-size: 14px; 24 | } 25 | -------------------------------------------------------------------------------- /src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | 6 | import { PageNotFoundComponent } from './components/'; 7 | import { WebviewDirective } from './directives/'; 8 | 9 | @NgModule({ 10 | declarations: [PageNotFoundComponent, WebviewDirective], 11 | imports: [CommonModule, TranslateModule], 12 | exports: [TranslateModule, WebviewDirective] 13 | }) 14 | export class SharedModule {} 15 | -------------------------------------------------------------------------------- /src/app/home/home-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { Routes, RouterModule } from '@angular/router'; 4 | import { HomeComponent } from './home.component'; 5 | 6 | const routes: Routes = [ 7 | { 8 | path: 'home', 9 | component: HomeComponent 10 | } 11 | ]; 12 | 13 | @NgModule({ 14 | declarations: [], 15 | imports: [CommonModule, RouterModule.forChild(routes)], 16 | exports: [RouterModule] 17 | }) 18 | export class HomeRoutingModule {} 19 | -------------------------------------------------------------------------------- /tsconfig-serve.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "sourceMap": true, 4 | "declaration": false, 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "target": "es5", 9 | "types": [ 10 | "node" 11 | ], 12 | "lib": [ 13 | "es2017", 14 | "es2016", 15 | "es2015", 16 | "dom" 17 | ] 18 | }, 19 | "include": [ 20 | "main.ts" 21 | ], 22 | "exclude": [ 23 | "node_modules", 24 | "**/*.spec.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { PageNotFoundComponent } from './shared/components'; 4 | 5 | const routes: Routes = [ 6 | { 7 | path: '', 8 | redirectTo: 'home', 9 | pathMatch: 'full' 10 | }, 11 | { 12 | path: '**', 13 | component: PageNotFoundComponent 14 | } 15 | ]; 16 | 17 | @NgModule({ 18 | imports: [RouterModule.forRoot(routes, { useHash: true })], 19 | exports: [RouterModule] 20 | }) 21 | export class AppRoutingModule {} 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "es2016", 17 | "es2015", 18 | "dom" 19 | ] 20 | }, 21 | "include": [ 22 | "main.ts", 23 | "src/**/*" 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /src/app/markup/markup.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 11 | 12 | 13 |
14 | 15 |
16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /src/app/add-emoji/add-emoji.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from '@angular/core'; 2 | import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; 3 | 4 | @Component({ 5 | selector: 'app-add-emoji', 6 | templateUrl: './add-emoji.component.html', 7 | styleUrls: ['./add-emoji.component.css'] 8 | }) 9 | export class AddEmojiComponent implements OnInit { 10 | 11 | constructor(@Inject(MAT_DIALOG_DATA) public data: any, 12 | public dialogRef: MatDialogRef) { } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | addEmoji(event) { 18 | this.dialogRef.close({ success: true, data: event.emoji.native }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /postinstall-web.js: -------------------------------------------------------------------------------- 1 | // Allow angular using electron module (native node modules) 2 | const fs = require('fs'); 3 | const f_angular = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js'; 4 | 5 | fs.readFile(f_angular, 'utf8', function (err, data) { 6 | if (err) { 7 | return console.log(err); 8 | } 9 | var result = data.replace(/target: "electron-renderer",/g, ''); 10 | var result = result.replace(/target: "web",/g, ''); 11 | var result = result.replace(/return \{/g, 'return {target: "web",'); 12 | 13 | fs.writeFile(f_angular, result, 'utf8', function (err) { 14 | if (err) return console.log(err); 15 | }); 16 | }); -------------------------------------------------------------------------------- /postinstall.js: -------------------------------------------------------------------------------- 1 | // Allow angular using electron module (native node modules) 2 | const fs = require('fs'); 3 | const f_angular = 'node_modules/@angular-devkit/build-angular/src/angular-cli-files/models/webpack-configs/browser.js'; 4 | 5 | fs.readFile(f_angular, 'utf8', function (err, data) { 6 | if (err) { 7 | return console.log(err); 8 | } 9 | var result = data.replace(/target: "electron-renderer",/g, ''); 10 | var result = result.replace(/target: "web",/g, ''); 11 | var result = result.replace(/return \{/g, 'return {target: "electron-renderer",'); 12 | 13 | fs.writeFile(f_angular, result, 'utf8', function (err) { 14 | if (err) return console.log(err); 15 | }); 16 | }); -------------------------------------------------------------------------------- /src/app/save-dialog/save-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 | Save Markdown 3 | 11 |
12 | 13 | Enter filename 14 |
15 | 16 |
17 |
18 |
19 | 27 |
28 | -------------------------------------------------------------------------------- /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: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/app/home/home.component.scss: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | width: 100%; 4 | height: 100%; 5 | } 6 | 7 | body { 8 | margin: 0px !important; 9 | padding: 0px !important; 10 | } 11 | 12 | button:focus { 13 | outline: 0 !important; 14 | } 15 | 16 | .clearfix { 17 | overflow: auto; 18 | } 19 | 20 | .header { 21 | height: 64px; 22 | background: #2196f3; 23 | } 24 | 25 | 26 | .handle { 27 | width: 8px; 28 | background: #ddd; 29 | cursor: ew-resize; 30 | flex: 1; 31 | } 32 | 33 | .content { 34 | flex-grow: 1; 35 | overflow: auto; 36 | width: 50%; 37 | } 38 | 39 | 40 | @media only screen and (max-width: 600px) { 41 | .sidebar { 42 | width: 600%; 43 | } 44 | 45 | .content { 46 | width: 0%; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/service-worker/config/schema.json", 3 | "index": "/index.html", 4 | "assetGroups": [ 5 | { 6 | "name": "app", 7 | "installMode": "prefetch", 8 | "resources": { 9 | "files": [ 10 | "/favicon.ico", 11 | "/index.html", 12 | "/manifest.webmanifest", 13 | "/*.css", 14 | "/*.js" 15 | ] 16 | } 17 | }, { 18 | "name": "assets", 19 | "installMode": "lazy", 20 | "updateMode": "prefetch", 21 | "resources": { 22 | "files": [ 23 | "/assets/**", 24 | "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" 25 | ] 26 | } 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /src/app/markup/markup.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { MarkupComponent } from './markup.component'; 4 | 5 | describe('MarkupComponent', () => { 6 | let component: MarkupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ MarkupComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(MarkupComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/navbar/navbar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NavbarComponent } from './navbar.component'; 4 | 5 | describe('NavbarComponent', () => { 6 | let component: NavbarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NavbarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NavbarComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /electron-builder.json: -------------------------------------------------------------------------------- 1 | { 2 | "productName": "MarkdownEditor", 3 | "directories": { 4 | "output": "release/" 5 | }, 6 | "files": [ 7 | "**/*", 8 | "!**/*.ts", 9 | "!*.code-workspace", 10 | "!LICENSE.md", 11 | "!package.json", 12 | "!package-lock.json", 13 | "!src/", 14 | "!e2e/", 15 | "!hooks/", 16 | "!angular.json", 17 | "!_config.yml", 18 | "!karma.conf.js", 19 | "!tsconfig.json", 20 | "!tslint.json" 21 | ], 22 | "win": { 23 | "icon": "dist", 24 | "target": [ 25 | "portable" 26 | ] 27 | }, 28 | "mac": { 29 | "icon": "dist", 30 | "target": [ 31 | "dmg" 32 | ] 33 | }, 34 | "linux": { 35 | "icon": "dist", 36 | "target": [ 37 | "AppImage" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /e2e/main.spec.ts: -------------------------------------------------------------------------------- 1 | import {expect, assert} from 'chai'; 2 | import {SpectronClient} from 'spectron'; 3 | 4 | import commonSetup from './common-setup'; 5 | 6 | describe('angular-electron App', function () { 7 | commonSetup.apply(this); 8 | 9 | let browser: any; 10 | let client: SpectronClient; 11 | 12 | beforeEach(function () { 13 | client = this.app.client; 14 | browser = client as any; 15 | }); 16 | 17 | it('should display message saying App works !', async function () { 18 | const text = await browser.getText('app-home h1'); 19 | expect(text).to.equal('App works !'); 20 | }); 21 | 22 | 23 | it('creates initial windows', async function () { 24 | const count = await client.getWindowCount(); 25 | expect(count).to.equal(1); 26 | }); 27 | 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/add-emoji/add-emoji.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { AddEmojiComponent } from './add-emoji.component'; 4 | 5 | describe('AddEmojiComponent', () => { 6 | let component: AddEmojiComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ AddEmojiComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(AddEmojiComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/load-dialog/load-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 | Load Markdown 3 | 11 |
12 | 13 |
14 | {{ i + 1 + ". " + file.title }} 15 | 20 |
21 | 📭 No saved markdowns found !! 24 |
25 | -------------------------------------------------------------------------------- /src/app/load-dialog/load-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoadDialogComponent } from './load-dialog.component'; 4 | 5 | describe('LoadDialogComponent', () => { 6 | let component: LoadDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoadDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoadDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/save-dialog/save-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SaveDialogComponent } from './save-dialog.component'; 4 | 5 | describe('SaveDialogComponent', () => { 6 | let component: SaveDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SaveDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SaveDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/options-dialog/options-dialog.component.css: -------------------------------------------------------------------------------- 1 | textarea { 2 | background: var(--bg); 3 | border: 0px; 4 | height: 100%; 5 | width: 100%; 6 | padding: 10px; 7 | border-radius: 4px; 8 | margin-top: 18px; 9 | resize: none; 10 | } 11 | 12 | input[type='text'] { 13 | background: var(--bg); 14 | padding: 10px; 15 | border-radius: 4px; 16 | margin-top: 5px; 17 | margin-bottom: 18px; 18 | width: 100%; 19 | } 20 | 21 | textarea:focus { 22 | outline: 0; 23 | } 24 | 25 | .help-block { 26 | font-size: 14px; 27 | color: var(--list-color); 28 | } 29 | 30 | .mat-dialog-actions { 31 | justify-content: flex-end; 32 | margin-bottom: -6px; 33 | } 34 | 35 | .mat-dialog-actions button { 36 | padding: 5px 11px; 37 | background: #1d88e5; 38 | border-radius: 4px; 39 | font-size: 14px; 40 | } 41 | -------------------------------------------------------------------------------- /src/app/options-dialog/options-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { OptionsDialogComponent } from './options-dialog.component'; 4 | 5 | describe('OptionsDialogComponent', () => { 6 | let component: OptionsDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ OptionsDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(OptionsDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/shared/components/page-not-found/page-not-found.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { PageNotFoundComponent } from './page-not-found.component'; 4 | 5 | describe('PageNotFoundComponent', () => { 6 | let component: PageNotFoundComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ PageNotFoundComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(PageNotFoundComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /.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 | /app-builds 8 | /release 9 | main.js 10 | src/**/*.js 11 | !src/karma.conf.js 12 | *.js.map 13 | 14 | # dependencies 15 | /node_modules 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | .vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | 33 | # misc 34 | /.sass-cache 35 | /connect.lock 36 | /coverage 37 | /libpeerconnection.log 38 | npm-debug.log 39 | testem.log 40 | /typings 41 | package-lock.json 42 | 43 | # e2e 44 | /e2e/*.js 45 | !/e2e/protractor.conf.js 46 | /e2e/*.map 47 | 48 | # System Files 49 | .DS_Store 50 | Thumbs.db 51 | -------------------------------------------------------------------------------- /.github/workflow/electron.yml: -------------------------------------------------------------------------------- 1 | # name of your github action 2 | name: CI 3 | # this will help you specify where to run 4 | on: 5 | push: 6 | branches: 7 | # this will run on the master branch 8 | - master 9 | # this is where the magic happens, each job happens in parallel btw 10 | jobs: 11 | build_on_mac: 12 | runs-on: macOS-latest 13 | steps: 14 | - uses: actions/checkout@master 15 | with: 16 | ref: electron 17 | - uses: actions/setup-node@master 18 | with: 19 | node-version: 10.16 20 | - name: see directory 21 | run: ls 22 | build_on_win: 23 | runs-on: windows-2016 24 | steps: 25 | - uses: actions/checkout@master 26 | with: 27 | ref: feature/github-actions 28 | - uses: actions/setup-node@master 29 | with: 30 | node-version: 10.16 31 | - name: see directory 32 | run: ls 33 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | import { ElectronService } from './core/services'; 6 | 7 | describe('AppComponent', () => { 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [AppComponent], 11 | providers: [ElectronService], 12 | imports: [RouterTestingModule, TranslateModule.forRoot()] 13 | }).compileComponents(); 14 | })); 15 | 16 | it('should create the app', async(() => { 17 | const fixture = TestBed.createComponent(AppComponent); 18 | const app = fixture.debugElement.componentInstance; 19 | expect(app).toBeTruthy(); 20 | })); 21 | }); 22 | 23 | class TranslateServiceStub { 24 | setDefaultLang(lang: string): void {} 25 | } 26 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ElectronService } from './core/services'; 3 | import { TranslateService } from '@ngx-translate/core'; 4 | import { AppConfig } from '../environments/environment'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.scss'] 10 | }) 11 | export class AppComponent { 12 | constructor( 13 | public electronService: ElectronService, 14 | private translate: TranslateService 15 | ) { 16 | translate.setDefaultLang('en'); 17 | console.log('AppConfig', AppConfig); 18 | 19 | if (electronService.isElectron) { 20 | console.log(process.env); 21 | console.log('Mode electron'); 22 | console.log('Electron ipcRenderer', electronService.ipcRenderer); 23 | console.log('NodeJS childProcess', electronService.childProcess); 24 | } else { 25 | console.log('Mode web'); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2018 - Maxime GRIS 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /src/app/home/home.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { HomeComponent } from './home.component'; 4 | import { TranslateModule } from '@ngx-translate/core'; 5 | 6 | describe('HomeComponent', () => { 7 | let component: HomeComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [HomeComponent], 13 | imports: [TranslateModule.forRoot()] 14 | }).compileComponents(); 15 | })); 16 | 17 | beforeEach(() => { 18 | fixture = TestBed.createComponent(HomeComponent); 19 | component = fixture.componentInstance; 20 | fixture.detectChanges(); 21 | }); 22 | 23 | it('should create', () => { 24 | expect(component).toBeTruthy(); 25 | }); 26 | 27 | it('should render title in a h1 tag', async(() => { 28 | const compiled = fixture.debugElement.nativeElement; 29 | expect(compiled.querySelector('h1').textContent).toContain( 30 | 'PAGES.HOME.TITLE' 31 | ); 32 | })); 33 | }); 34 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/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-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage'), 20 | reports: [ 'html', 'lcovonly' ], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: true 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /src/app/markup/markup.component.css: -------------------------------------------------------------------------------- 1 | .editor { 2 | letter-spacing: 0.00625em; 3 | font-size: 1.3rem; 4 | font-weight: 400; 5 | line-height: 2rem; 6 | padding: 15px 25px; 7 | outline: none; 8 | height: 90vh; 9 | overflow: auto; 10 | } 11 | 12 | .split { 13 | height: 94vh; 14 | width: 100%; 15 | } 16 | 17 | .mark-pad { 18 | padding: 25px; 19 | cursor: not-allowed; 20 | } 21 | 22 | .menu { 23 | display: flex; 24 | align-items: center; 25 | } 26 | 27 | .menu a { 28 | padding-left: 20px; 29 | display: flex; 30 | align-items: center; 31 | } 32 | 33 | table { 34 | width: 100%; 35 | background: #fff; 36 | margin: 1em 0; 37 | border: 1px solid rgba(34, 36, 38, 0.15); 38 | -webkit-box-shadow: none; 39 | box-shadow: none; 40 | border-radius: 0.28571429rem; 41 | text-align: left; 42 | color: rgba(0, 0, 0, 0.87); 43 | border-collapse: separate; 44 | border-spacing: 0; 45 | display: table; 46 | } 47 | 48 | textarea { 49 | background: var(--bg); 50 | border: 0px; 51 | height: 100%; 52 | resize: none; 53 | width: 100%; 54 | padding: 25px; 55 | } 56 | 57 | textarea:focus { 58 | outline: 0; 59 | } 60 | -------------------------------------------------------------------------------- /src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ElementRef, Renderer2 } from '@angular/core'; 2 | import { SwUpdate } from '@angular/service-worker'; 3 | import { MarkdownService } from 'ngx-markdown'; 4 | 5 | @Component({ 6 | selector: 'app-home', 7 | templateUrl: './home.component.html', 8 | styleUrls: ['./home.component.scss'] 9 | }) 10 | export class HomeComponent implements OnInit { 11 | 12 | title = 'notes'; 13 | inputElement: ElementRef; 14 | noteText = ""; 15 | public isSidebarVisible: Boolean = true; 16 | 17 | constructor(private element: ElementRef, private renderer: Renderer2, private swUpdate: SwUpdate, private markdownService: MarkdownService) { } 18 | 19 | ngAfterViewInit(): void { 20 | 21 | this.renderer.listen(this.element.nativeElement, 'paste', (event) => { 22 | navigator['clipboard'].readText().then(clipText => { 23 | this.noteText = clipText 24 | }); 25 | }); 26 | 27 | } 28 | 29 | 30 | ngOnInit(): void { 31 | if (this.swUpdate.isEnabled) { 32 | this.swUpdate.available.subscribe(() => { 33 | window.location.reload(); 34 | }); 35 | } 36 | 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/save-dialog/save-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from "@angular/core"; 2 | import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material"; 3 | import { OptionsDialogComponent } from "../options-dialog/options-dialog.component"; 4 | import { FormBuilder, FormGroup } from "@angular/forms"; 5 | import { IndexedDB } from "ng-indexed-db"; 6 | import { Observable } from "rxjs"; 7 | import { MarkdownService } from "../core/services/markdown.service"; 8 | 9 | @Component({ 10 | selector: "app-save-dialog", 11 | templateUrl: "./save-dialog.component.html", 12 | styleUrls: ["./save-dialog.component.css"] 13 | }) 14 | export class SaveDialogComponent implements OnInit { 15 | public saveOption: FormGroup; 16 | public fileName = ""; 17 | $list: Observable; 18 | 19 | constructor( 20 | @Inject(MAT_DIALOG_DATA) public data: any, 21 | public saveDialog: MatDialogRef, 22 | private markdownService: MarkdownService 23 | ) { } 24 | 25 | ngOnInit() { } 26 | 27 | saveFile() { 28 | this.markdownService.saveMarkdown.next(this.fileName); 29 | this.saveDialog.close({ data: this.fileName }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/app/core/services/electron/electron.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | // If you import a module but never use any of the imported values other than as TypeScript types, 4 | // the resulting javascript file will look as if you never imported the module at all. 5 | import { ipcRenderer, webFrame, remote } from 'electron'; 6 | import * as childProcess from 'child_process'; 7 | import * as fs from 'fs'; 8 | 9 | @Injectable({ 10 | providedIn: 'root' 11 | }) 12 | export class ElectronService { 13 | ipcRenderer: typeof ipcRenderer; 14 | webFrame: typeof webFrame; 15 | remote: typeof remote; 16 | childProcess: typeof childProcess; 17 | fs: typeof fs; 18 | 19 | get isElectron() { 20 | return window && window.process && window.process.type; 21 | } 22 | 23 | constructor() { 24 | // Conditional imports 25 | if (this.isElectron) { 26 | this.ipcRenderer = window.require('electron').ipcRenderer; 27 | this.webFrame = window.require('electron').webFrame; 28 | this.remote = window.require('electron').remote; 29 | 30 | this.childProcess = window.require('child_process'); 31 | this.fs = window.require('fs'); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/app/options-dialog/options-dialog.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{ formOption.title }} 3 | 6 |
7 | 8 |
9 | {{ item.label }} 10 |
11 | 17 | 24 | * You can replace the above text with your own and reuse it while creating next readme 26 | 27 |
28 |
29 |
30 |
31 | 34 |
35 | -------------------------------------------------------------------------------- /src/manifest.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Markdown Editor", 3 | "short_name": "Markdown Editor", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "/", 8 | "start_url": "/", 9 | "icons": [{ 10 | "src": "assets/icons/icon-72x72.png", 11 | "sizes": "72x72", 12 | "type": "image/png" 13 | }, 14 | { 15 | "src": "assets/icons/icon-96x96.png", 16 | "sizes": "96x96", 17 | "type": "image/png" 18 | }, 19 | { 20 | "src": "assets/icons/icon-128x128.png", 21 | "sizes": "128x128", 22 | "type": "image/png" 23 | }, 24 | { 25 | "src": "assets/icons/icon-144x144.png", 26 | "sizes": "144x144", 27 | "type": "image/png" 28 | }, 29 | { 30 | "src": "assets/icons/icon-152x152.png", 31 | "sizes": "152x152", 32 | "type": "image/png" 33 | }, 34 | { 35 | "src": "assets/icons/icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image/png" 38 | }, 39 | { 40 | "src": "assets/icons/icon-384x384.png", 41 | "sizes": "384x384", 42 | "type": "image/png" 43 | }, 44 | { 45 | "src": "assets/icons/icon-512x512.png", 46 | "sizes": "512x512", 47 | "type": "image/png" 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /src/app/core/services/markdown.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@angular/core"; 2 | import { BehaviorSubject } from "rxjs"; 3 | import { MetaObject } from "../../models/metadata"; 4 | import { MarkDownObject } from "../../models/markdown"; 5 | 6 | @Injectable({ 7 | providedIn: "root" 8 | }) 9 | 10 | @Injectable({ 11 | providedIn: "root" 12 | }) 13 | export class MarkdownService { 14 | public optionChanged: BehaviorSubject = new BehaviorSubject( 15 | null 16 | ); 17 | public emojiAdded: BehaviorSubject = new BehaviorSubject( 18 | null 19 | ); 20 | public copyMarkdown: BehaviorSubject = new BehaviorSubject( 21 | false 22 | ); 23 | public downloadMarkdown: BehaviorSubject = new BehaviorSubject< 24 | boolean 25 | >(false); 26 | public saveMarkdown: BehaviorSubject = new BehaviorSubject( 27 | null 28 | ); 29 | public metaAdded: BehaviorSubject = new BehaviorSubject< 30 | MetaObject 31 | >(null); 32 | public loadMarkdown: BehaviorSubject = new BehaviorSubject< 33 | MarkDownObject 34 | >(null); 35 | public newMarkdown: BehaviorSubject = new BehaviorSubject( 36 | null 37 | ); 38 | public markdownFromLocalStorage: BehaviorSubject = new BehaviorSubject( 39 | null 40 | ); 41 | 42 | constructor() {} 43 | } 44 | -------------------------------------------------------------------------------- /src/app/icons/icons.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from "@angular/core"; 2 | 3 | import { FeatherModule } from "angular-feather"; 4 | import { 5 | Camera, 6 | Heart, 7 | Github, 8 | Trash2, 9 | AlertCircle, 10 | Send, 11 | Twitter, 12 | Moon, 13 | Sun, 14 | File, 15 | Plus, 16 | Menu, 17 | BookOpen, 18 | Bold, 19 | Italic, 20 | Code, 21 | Link, 22 | CheckSquare, 23 | List, 24 | ChevronRight, 25 | Minus, 26 | Image, 27 | Type, 28 | Circle, 29 | Book, 30 | Hash, 31 | ChevronsRight, 32 | HardDrive, 33 | Columns, 34 | Smile, 35 | Copy, 36 | Download, 37 | Package, 38 | Loader, 39 | Save, 40 | GitMerge, 41 | Users 42 | } from "angular-feather/icons"; 43 | 44 | const icons = { 45 | Camera, 46 | Heart, 47 | Github, 48 | Trash2, 49 | Send, 50 | Moon, 51 | Loader, 52 | Sun, 53 | Plus, 54 | Menu, 55 | Book, 56 | BookOpen, 57 | Twitter, 58 | Bold, 59 | Italic, 60 | Smile, 61 | Copy, 62 | Download, 63 | Package, 64 | Save, 65 | Code, 66 | Link, 67 | CheckSquare, 68 | HardDrive, 69 | List, 70 | ChevronRight, 71 | Minus, 72 | Image, 73 | Type, 74 | Circle, 75 | Hash, 76 | ChevronsRight, 77 | Columns, 78 | GitMerge, 79 | AlertCircle, 80 | File, 81 | Users 82 | }; 83 | 84 | @NgModule({ 85 | imports: [FeatherModule.pick(icons)], 86 | exports: [FeatherModule] 87 | }) 88 | export class IconsModule { } 89 | -------------------------------------------------------------------------------- /e2e/common-setup.ts: -------------------------------------------------------------------------------- 1 | const Application = require('spectron').Application; 2 | const electronPath = require('electron'); // Require Electron from the binaries included in node_modules. 3 | const path = require('path'); 4 | 5 | export default function setup() { 6 | beforeEach(async function () { 7 | this.app = new Application({ 8 | // Your electron path can be any binary 9 | // i.e for OSX an example path could be '/Applications/MyApp.app/Contents/MacOS/MyApp' 10 | // But for the sake of the example we fetch it from our node_modules. 11 | path: electronPath, 12 | 13 | // Assuming you have the following directory structure 14 | 15 | // |__ my project 16 | // |__ ... 17 | // |__ main.js 18 | // |__ package.json 19 | // |__ index.html 20 | // |__ ... 21 | // |__ test 22 | // |__ spec.js <- You are here! ~ Well you should be. 23 | 24 | // The following line tells spectron to look and use the main.js file 25 | // and the package.json located 1 level above. 26 | args: [path.join(__dirname, '..')], 27 | webdriverOptions: {} 28 | }); 29 | await this.app.start(); 30 | const browser = this.app.client; 31 | await browser.waitUntilWindowLoaded(); 32 | 33 | browser.timeouts('script', 15000); 34 | }); 35 | 36 | afterEach(function () { 37 | if (this.app && this.app.isRunning()) { 38 | return this.app.stop(); 39 | } 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /src/app/load-dialog/load-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | import { MatSnackBar, MatDialog, MatDialogRef } from "@angular/material"; 3 | import { IndexedDB } from "ng-indexed-db"; 4 | import { Observable } from "rxjs"; 5 | import { MarkdownService } from "../core/services/markdown.service"; 6 | 7 | @Component({ 8 | selector: "app-load-dialog", 9 | templateUrl: "./load-dialog.component.html", 10 | styleUrls: ["./load-dialog.component.css"] 11 | }) 12 | export class LoadDialogComponent implements OnInit { 13 | $list: Observable; 14 | 15 | constructor( 16 | public loadDialog: MatDialogRef, 17 | private markDownService: MarkdownService, 18 | private indexedDbService: IndexedDB, 19 | private snackBar: MatSnackBar 20 | ) { } 21 | 22 | deleteMarkdown(id) { 23 | console.log(id); 24 | this.indexedDbService.delete("markdown_store", id).subscribe( 25 | response => { 26 | this.getMarkdowns(); 27 | this.snackBar.open("Markdown Deleted !! 🗑", " ", { 28 | duration: 1000 29 | }); 30 | console.log("Deleted"); 31 | }, 32 | error => { 33 | this.snackBar.open("Error Occured while deleting markdown !!", " ", { 34 | duration: 1000 35 | }); 36 | } 37 | ); 38 | } 39 | 40 | getMarkdowns() { 41 | this.$list = this.indexedDbService.list("markdown_store"); 42 | } 43 | 44 | loadMarkdown(item) { 45 | this.markDownService.loadMarkdown.next(item); 46 | this.loadDialog.close({ data: item }); 47 | } 48 | 49 | ngOnInit() { 50 | this.getMarkdowns(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/app/options-dialog/options-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject } from "@angular/core"; 2 | import { FormGroup, FormBuilder, FormControl } from "@angular/forms"; 3 | import { MatDialogRef, MAT_DIALOG_DATA } from "@angular/material"; 4 | import { FORM_OPTIONS } from "../constants/form-constants"; 5 | import { MarkdownService } from "../core/services/markdown.service"; 6 | 7 | @Component({ 8 | selector: "app-options-dialog", 9 | templateUrl: "./options-dialog.component.html", 10 | styleUrls: ["./options-dialog.component.css"] 11 | }) 12 | export class OptionsDialogComponent implements OnInit { 13 | public addOption: FormGroup; 14 | 15 | public options = FORM_OPTIONS; 16 | public formOption; 17 | 18 | constructor( 19 | @Inject(MAT_DIALOG_DATA) public data: any, 20 | public optionsDialog: MatDialogRef, 21 | private fb: FormBuilder, 22 | private markService: MarkdownService 23 | ) { } 24 | 25 | ngOnInit() { 26 | this.formOption = FORM_OPTIONS[this.data.type]; 27 | this.populateFormControl(); 28 | } 29 | 30 | populateFormControl() { 31 | this.addOption = this.fb.group({}); 32 | const form = FORM_OPTIONS[this.data.type]; 33 | let value = ""; 34 | let preVal = localStorage.getItem(this.data.type); 35 | if (FORM_OPTIONS[this.data.type].hasOwnProperty("default")) { 36 | value = FORM_OPTIONS[this.data.type]["default"]; 37 | } 38 | if (preVal) { 39 | value = preVal; 40 | } 41 | 42 | form.fields.map(column => { 43 | this.addOption.addControl(column.name, new FormControl(value, [])); 44 | }); 45 | } 46 | 47 | 48 | executeFormAction() { 49 | if (this.data.type == "image") { 50 | this.optionsDialog.close({ 51 | success: true, 52 | data: { type: "image", ...this.addOption.value } 53 | }); 54 | } else if (this.data.type == "link") { 55 | this.optionsDialog.close({ 56 | success: true, 57 | data: { type: "link", ...this.addOption.value } 58 | }); 59 | } else { 60 | localStorage.setItem(this.data.type, this.addOption.value.descr) 61 | this.optionsDialog.close({ 62 | success: true, 63 | data: { type: "text", ...this.addOption.value } 64 | }); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow, screen } from 'electron'; 2 | import * as path from 'path'; 3 | import * as url from 'url'; 4 | 5 | let win, serve; 6 | const args = process.argv.slice(1); 7 | serve = args.some(val => val === '--serve'); 8 | 9 | function createWindow() { 10 | 11 | const electronScreen = screen; 12 | const size = electronScreen.getPrimaryDisplay().workAreaSize; 13 | 14 | // Create the browser window. 15 | win = new BrowserWindow({ 16 | x: 0, 17 | y: 0, 18 | width: size.width, 19 | height: size.height, 20 | webPreferences: { 21 | nodeIntegration: true, 22 | }, 23 | }); 24 | 25 | if (serve) { 26 | require('electron-reload')(__dirname, { 27 | electron: require(`${__dirname}/node_modules/electron`) 28 | }); 29 | win.loadURL('http://localhost:4200'); 30 | } else { 31 | win.loadURL(url.format({ 32 | pathname: path.join(__dirname, 'dist/index.html'), 33 | protocol: 'file:', 34 | slashes: true 35 | })); 36 | } 37 | 38 | if (serve) { 39 | win.webContents.openDevTools(); 40 | } 41 | 42 | // Emitted when the window is closed. 43 | win.on('closed', () => { 44 | // Dereference the window object, usually you would store window 45 | // in an array if your app supports multi windows, this is the time 46 | // when you should delete the corresponding element. 47 | win = null; 48 | }); 49 | 50 | } 51 | 52 | try { 53 | 54 | // This method will be called when Electron has finished 55 | // initialization and is ready to create browser windows. 56 | // Some APIs can only be used after this event occurs. 57 | app.on('ready', createWindow); 58 | 59 | // Quit when all windows are closed. 60 | app.on('window-all-closed', () => { 61 | // On OS X it is common for applications and their menu bar 62 | // to stay active until the user quits explicitly with Cmd + Q 63 | 64 | 65 | if (process.platform !== 'darwin') { 66 | 67 | // app.quit(); 68 | } 69 | }); 70 | 71 | app.on('activate', () => { 72 | // On OS X it's common to re-create a window in the app when the 73 | // dock icon is clicked and there are no other windows open. 74 | 75 | 76 | if (win === null) { 77 | createWindow(); 78 | } 79 | }); 80 | 81 | } catch (e) { 82 | // Catch Error 83 | // throw e; 84 | } 85 | -------------------------------------------------------------------------------- /src/app/home/home.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { HomeRoutingModule } from './home-routing.module'; 5 | 6 | import { HomeComponent } from './home.component'; 7 | import { SharedModule } from '../shared/shared.module'; 8 | import { NavbarComponent } from '../navbar/navbar.component'; 9 | import { MarkupComponent } from '../markup/markup.component'; 10 | import { AddEmojiComponent } from '../add-emoji/add-emoji.component'; 11 | import { OptionsDialogComponent } from '../options-dialog/options-dialog.component'; 12 | import { SaveDialogComponent } from '../save-dialog/save-dialog.component'; 13 | import { LoadDialogComponent } from '../load-dialog/load-dialog.component'; 14 | import { MatDialogModule, MatTooltipModule, MatIconModule, MatSnackBarModule } from '@angular/material'; 15 | import { IconsModule } from '../icons/icons.module'; 16 | import { PickerModule } from '@ctrl/ngx-emoji-mart'; 17 | import { NtkmeButtonModule } from '@ctrl/ngx-github-buttons'; 18 | import { MarkdownModule } from 'ngx-markdown'; 19 | import { KeyboardShortcutsModule } from 'ng-keyboard-shortcuts'; 20 | import { AngularSplitModule } from 'angular-split'; 21 | import { IndexedDBModule } from 'ng-indexed-db'; 22 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 23 | import { BrowserModule } from '@angular/platform-browser'; 24 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 25 | 26 | @NgModule({ 27 | declarations: [HomeComponent, 28 | NavbarComponent, 29 | MarkupComponent, 30 | AddEmojiComponent, 31 | OptionsDialogComponent, 32 | SaveDialogComponent, 33 | LoadDialogComponent], 34 | imports: [CommonModule, SharedModule, HomeRoutingModule, 35 | MatDialogModule, 36 | IconsModule, 37 | FormsModule, 38 | BrowserAnimationsModule, 39 | ReactiveFormsModule, 40 | BrowserModule, 41 | MatTooltipModule, 42 | MatIconModule, 43 | MatSnackBarModule, 44 | PickerModule, 45 | NtkmeButtonModule, 46 | MarkdownModule.forRoot(), 47 | KeyboardShortcutsModule.forRoot(), 48 | AngularSplitModule.forRoot(), 49 | IndexedDBModule.forRoot([ 50 | { 51 | name: "markdown_db", 52 | stores: [{ name: "markdown_store" }] 53 | } 54 | ]),], 55 | entryComponents: [ 56 | AddEmojiComponent, 57 | OptionsDialogComponent, 58 | SaveDialogComponent, 59 | LoadDialogComponent 60 | ] 61 | }) 62 | export class HomeModule { } 63 | -------------------------------------------------------------------------------- /.github/workflows/electron.yml: -------------------------------------------------------------------------------- 1 | # name of your github action 2 | name: CI 3 | # this will help you specify where to run 4 | 5 | on: 6 | push: 7 | branches: 8 | # this will run on the master branch 9 | - master 10 | 11 | # this is where the magic happens, each job happens in parallel btw 12 | jobs: 13 | build_on_mac: 14 | runs-on: macOS-latest 15 | steps: 16 | - uses: actions/checkout@master 17 | with: 18 | ref: master 19 | - uses: actions/setup-node@master 20 | with: 21 | node-version: 10.16 22 | - name: see directory 23 | run: ls 24 | - name: Install dependencies 25 | run: npm install 26 | - name: Build Electron 27 | run: npm run electron:mac 28 | - name: see directory 29 | run: ls 30 | - uses: lucyio/upload-to-release@master 31 | with: 32 | name: JP1016/Markdown-Electron 33 | path: ./release 34 | action: published 35 | repo-token: ${{ secrets.GITHUB_TOKEN }} 36 | release_id: 1 37 | release-repo: JP1016/Markdown-Electron 38 | build_on_win: 39 | runs-on: windows-latest 40 | steps: 41 | - uses: actions/checkout@master 42 | with: 43 | ref: master 44 | - uses: actions/setup-node@master 45 | with: 46 | node-version: 10.16 47 | - name: see directory 48 | run: ls 49 | - name: Install dependencies 50 | run: npm install 51 | - name: Build Electron 52 | run: npm run electron:windows 53 | - name: see directory 54 | run: ls 55 | - uses: lucyio/upload-to-release@master 56 | with: 57 | name: JP1016/Markdown-Electron 58 | path: ./release 59 | action: published 60 | repo-token: ${{ secrets.GITHUB_TOKEN }} 61 | release_id: 1 62 | release-repo: JP1016/Markdown-Electron 63 | build_on_linux: 64 | runs-on: ubuntu-latest 65 | steps: 66 | - uses: actions/checkout@master 67 | with: 68 | ref: master 69 | - uses: actions/setup-node@master 70 | with: 71 | node-version: 10.16 72 | - name: see directory 73 | run: ls 74 | - name: Install dependencies 75 | run: npm install 76 | - name: Build Electron 77 | run: npm run electron:linux 78 | - name: see directory 79 | run: ls 80 | - uses: lucyio/upload-to-release@master 81 | with: 82 | name: JP1016/Markdown-Electron 83 | path: ./release 84 | action: published 85 | repo-token: ${{ secrets.GITHUB_TOKEN }} 86 | release_id: 1 87 | release-repo: JP1016/Markdown-Electron 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import '../polyfills'; 3 | 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | import { NgModule } from '@angular/core'; 6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 7 | import { HttpClientModule, HttpClient } from '@angular/common/http'; 8 | import { CoreModule } from './core/core.module'; 9 | import { SharedModule } from './shared/shared.module'; 10 | 11 | import { AppRoutingModule } from './app-routing.module'; 12 | 13 | // NG Translate 14 | import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; 15 | import { TranslateHttpLoader } from '@ngx-translate/http-loader'; 16 | 17 | import { HomeModule } from './home/home.module'; 18 | 19 | import { AppComponent } from './app.component'; 20 | import { ServiceWorkerModule } from '@angular/service-worker'; 21 | import { AppConfig } from '../environments/environment'; 22 | import { NavbarComponent } from './navbar/navbar.component'; 23 | import { MarkupComponent } from './markup/markup.component'; 24 | import { AddEmojiComponent } from './add-emoji/add-emoji.component'; 25 | import { OptionsDialogComponent } from './options-dialog/options-dialog.component'; 26 | import { SaveDialogComponent } from './save-dialog/save-dialog.component'; 27 | import { LoadDialogComponent } from './load-dialog/load-dialog.component'; 28 | import { MatDialogModule, MatTooltipModule, MatIconModule, MatSnackBarModule } from '@angular/material'; 29 | import { IconsModule } from './icons/icons.module'; 30 | import { KeyboardShortcutsModule } from 'ng-keyboard-shortcuts'; 31 | import { IndexedDBModule } from 'ng-indexed-db'; 32 | import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; 33 | import { NtkmeButtonModule } from "@ctrl/ngx-github-buttons"; 34 | import { AngularSplitModule } from "angular-split"; 35 | import { MarkdownModule } from "ngx-markdown"; 36 | import { PickerModule } from "@ctrl/ngx-emoji-mart"; 37 | // AoT requires an exported function for factories 38 | export function HttpLoaderFactory(http: HttpClient) { 39 | return new TranslateHttpLoader(http, './assets/i18n/', '.json'); 40 | } 41 | 42 | @NgModule({ 43 | declarations: [ 44 | AppComponent], 45 | imports: [ 46 | BrowserModule, 47 | FormsModule, 48 | HttpClientModule, 49 | CoreModule, 50 | SharedModule, 51 | HomeModule, 52 | AppRoutingModule, 53 | BrowserAnimationsModule, 54 | ReactiveFormsModule, 55 | TranslateModule.forRoot({ 56 | loader: { 57 | provide: TranslateLoader, 58 | useFactory: HttpLoaderFactory, 59 | deps: [HttpClient] 60 | } 61 | }), 62 | ServiceWorkerModule.register('ngsw-worker.js', { enabled: AppConfig.production }) 63 | ], 64 | providers: [], 65 | bootstrap: [AppComponent] 66 | }) 67 | export class AppModule { } 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 📖 Markdown Editor 2 | 3 | 4 | 5 | ### ⚡Creating markdown made easy!! 6 | 7 | [![Markdown](https://github.com/JP1016/Markdown-Electron/blob/master/preview.png?raw=true "Markdown-Electron")]() 8 | 9 | ```javascript 10 | 🎉 Features 11 | 12 | ``` 13 | 14 | #### 👆One Click Licence, Contribution Guidelines Export 15 | 16 | #### 💾Load and Save Markdown to Indexed DB 17 | 18 | #### 🚀Copy/Download Markdown with one-click 19 | 20 | #### 🌟Auto Save for Markdowns 21 | 22 | #### 🌓Dark/Light Mode 23 | 24 | #### 🎎Resizable Split UI 25 | 26 | #### ✨Assist for Inserting Images/Link 27 | 28 | #### 🚅Save Frequently used Contributing Guidelines/Contributors/Licence on to local storage 29 | 30 | #### 📬Opens the recent file, that you were editing on resuming 31 | 32 | #### ⚛️ Electron & PWA app for offline use 33 | 34 | #### 🔌 No Internet 35 | 36 | #### 📖 OpenSource 37 | 38 | Made with ❤️ by Twitter Follow 39 | 40 | ```javascript 41 | 🌟 Markdown Samples 42 | 43 | ``` 44 | 45 | | Formatting | Example | 46 | | ------------ | ---------------------------- | 47 | | Bold Text | **This is a bold text** | 48 | | Italics | _This will be in italics_ | 49 | | Striked Text | ~~This will appear striked~~ | 50 | 51 | Heading - ### Sample H3 Header 52 | 53 | ### Bullet List 54 | 55 | - Bullet 1 56 | - Bullet 2 57 | 58 | ### Checkbox 59 | 60 | - [ ] Unchecked Checkbox 61 | - [x] Checked 62 | 63 | ### Blockquote 64 | 65 | > This is a sample blockquote 66 | 67 | ### Code 68 | 69 | ```javascript 70 | let a = 1; 71 | (function() { 72 | console.log("IIFE"); 73 | })(); 74 | ``` 75 | 76 | ### Table 77 | 78 | | Name | Purpose | 79 | | --------------------------------- | --------------------- | 80 | | [Paper](https://paperapp.now.sh/) | Note Taking App | 81 | | [Markdown](https://mdown.now.sh) | Markdown Creation app | 82 | 83 | ### Link 84 | 85 | [Markdown Web URL](https://mdown.now.sh) 86 | 87 | ### Image 88 | 89 | Original Size 90 | ![Markdown Logo](http://icons.iconarchive.com/icons/paomedia/small-n-flat/256/terminal-icon.png) 91 | 92 | Custom Size 93 | 94 | 95 | ```javascript 96 | 🔨 Stack 97 | ``` 98 | 99 | - Angular 100 | - Indexed DB 101 | - Electron 102 | 103 | ```javascript 104 | 🤝 Contributing 105 | ``` 106 | 107 | Contributions, issues and feature requests are welcome! 😍 108 | 109 | Show your support 110 | 111 | Give a ⭐️ if this project helped you! 🥰 112 | 113 | If you like this app , Star it on Github, Follow me on Twitter 114 | 115 | Icons by FeatherIcons from https://feathericons.com 116 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["node_modules/codelyzer"], 3 | "rules": { 4 | "arrow-return-shorthand": true, 5 | "callable-types": true, 6 | "class-name": true, 7 | "comment-format": [true, "check-space"], 8 | "component-class-suffix": true, 9 | "component-selector": [true, "element", "app", "kebab-case"], 10 | "curly": true, 11 | "deprecation": { "severity": "warn" }, 12 | "directive-class-suffix": true, 13 | "eofline": true, 14 | "forin": true, 15 | "import-blacklist": [true, "rxjs/Rx"], 16 | "import-spacing": true, 17 | "indent": [true, "spaces"], 18 | "interface-over-type-literal": true, 19 | "label-position": true, 20 | "max-line-length": [true, 140], 21 | "member-access": false, 22 | "member-ordering": [ 23 | true, 24 | { 25 | "order": [ 26 | "static-field", 27 | "instance-field", 28 | "static-method", 29 | "instance-method" 30 | ] 31 | } 32 | ], 33 | "no-arg": true, 34 | "no-bitwise": true, 35 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 36 | "no-construct": true, 37 | "no-debugger": true, 38 | "no-duplicate-super": true, 39 | "no-empty": false, 40 | "no-empty-interface": true, 41 | "no-eval": true, 42 | "no-host-metadata-property": true, 43 | "no-inferrable-types": [true, "ignore-params"], 44 | "no-input-rename": true, 45 | "no-inputs-metadata-property": true, 46 | "no-misused-new": true, 47 | "no-non-null-assertion": true, 48 | "no-output-on-prefix": true, 49 | "no-output-rename": true, 50 | "no-outputs-metadata-property": true, 51 | "no-shadowed-variable": true, 52 | "no-string-literal": false, 53 | "no-string-throw": true, 54 | "no-switch-case-fall-through": true, 55 | "no-trailing-whitespace": true, 56 | "no-unnecessary-initializer": true, 57 | "no-unused-expression": true, 58 | "no-var-keyword": true, 59 | "object-literal-sort-keys": false, 60 | "one-line": [ 61 | true, 62 | "check-open-brace", 63 | "check-catch", 64 | "check-else", 65 | "check-whitespace" 66 | ], 67 | "prefer-const": true, 68 | "quotemark": [true, "single"], 69 | "radix": true, 70 | "semicolon": [true, "always"], 71 | "triple-equals": [true, "allow-null-check"], 72 | "typedef-whitespace": [ 73 | true, 74 | { 75 | "call-signature": "nospace", 76 | "index-signature": "nospace", 77 | "parameter": "nospace", 78 | "property-declaration": "nospace", 79 | "variable-declaration": "nospace" 80 | } 81 | ], 82 | "unified-signatures": true, 83 | "use-life-cycle-interface": true, 84 | "use-lifecycle-interface": true, 85 | "use-pipe-transform-interface": true, 86 | "variable-name": false, 87 | "whitespace": [ 88 | true, 89 | "check-branch", 90 | "check-decl", 91 | "check-operator", 92 | "check-separator", 93 | "check-type" 94 | ] 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /src/app/constants/form-constants.ts: -------------------------------------------------------------------------------- 1 | import { CONTRIBUTION_GUIDE } from "./app-constants"; 2 | 3 | export const IMAGE_SELECT = "image"; 4 | export const LINK_SELECT = "link"; 5 | export const CONTRIB_GUIDELINES_SELECT = "cguide"; 6 | export const CONTRIB_LIST = "clist"; 7 | export const LICENCE_SELECT = "licence"; 8 | export const SAVE_TEMPLATE = "save"; 9 | export const LOAD_TEMPLATE = "load"; 10 | const END_QUOTES = "```"; 11 | 12 | export const FORM_OPTIONS = { 13 | [IMAGE_SELECT]: { 14 | title: "Insert Image", 15 | fields: [ 16 | { 17 | label: "Enter Image URL", 18 | name: "link" 19 | }, 20 | { 21 | label: "Enter Image Description", 22 | name: "description" 23 | } 24 | ] 25 | }, 26 | [LINK_SELECT]: { 27 | title: "Insert Link", 28 | fields: [ 29 | { 30 | label: "Enter URL", 31 | name: "link" 32 | }, 33 | { 34 | label: "Enter Description", 35 | name: "description" 36 | } 37 | ] 38 | }, 39 | [CONTRIB_GUIDELINES_SELECT]: { 40 | title: "Add Contribution Guideline", 41 | fields: [ 42 | { 43 | label: "Enter Contibution Guideline", 44 | name: "descr" 45 | } 46 | ], 47 | default: `## Contributing 48 | If you've ever wanted to contribute to open source, and a great cause, now is your chance! 49 | 50 | See the [contributing docs](http://example.com) for more information` 51 | }, 52 | [CONTRIB_LIST]: { 53 | title: "Add Contribution List", 54 | fields: [ 55 | { 56 | label: "Enter Contibution List", 57 | name: "descr" 58 | } 59 | ], 60 | default: `## Contributors ✨ 61 | 62 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 63 | 64 | 65 | 66 | 67 | 68 | 82 | 95 | 96 |
69 | 70 | Kent C. Dodds 71 |
72 | 73 | Kent C. Dodds 74 | 75 |
76 |
77 | 💬 78 | 📖 79 | 👀 80 | 📢 81 |
83 | 84 | Jeroen Engels 85 |
86 | 87 | Jeroen Engels 88 | 89 |
90 |
91 | 📖 92 | 👀 93 | 🔧 94 |
97 | ` 98 | }, 99 | [LICENCE_SELECT]: { 100 | title: "Enter licence information", 101 | fields: [ 102 | { 103 | label: "Enter licence information", 104 | name: "descr" 105 | } 106 | ], 107 | default: `## LICENCE 108 | ${END_QUOTES} 109 | Copyright 2019 110 | 111 | Licensed under the Apache License, Version 2.0 (the "License"); 112 | you may not use this file except in compliance with the License. 113 | You may obtain a copy of the License at 114 | 115 | http://www.apache.org/licenses/LICENSE-2.0 116 | 117 | Unless required by applicable law or agreed to in writing, software 118 | distributed under the License is distributed on an "AS IS" BASIS, 119 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 120 | See the License for the specific language governing permissions and 121 | limitations under the License. 122 | ${END_QUOTES}` 123 | } 124 | }; 125 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MarkdownEditor", 3 | "version": "6.1.0", 4 | "description": "Markdown editor by devzstudio", 5 | "homepage": "https://github.com/JP1016/Markdown", 6 | "author": { 7 | "name": "Jithin P", 8 | "email": "emast007@gmail.com" 9 | }, 10 | "keywords": [ 11 | "markdown", 12 | "markdown editor", 13 | "markdown generator", 14 | "free markdown editor", 15 | "markdown pwa app" 16 | ], 17 | "main": "main.js", 18 | "private": true, 19 | "scripts": { 20 | "postinstall": "npm run postinstall:electron && electron-builder install-app-deps", 21 | "postinstall:web": "node postinstall-web", 22 | "postinstall:electron": "node postinstall", 23 | "ng": "ng", 24 | "start": "npm run postinstall:electron && npm-run-all -p ng:serve electron:serve", 25 | "build": "npm run postinstall:electron && npm run electron:serve-tsc && ng build", 26 | "build:dev": "npm run build -- -c dev", 27 | "build:prod": "npm run build -- -c production", 28 | "ng:serve": "ng serve", 29 | "ng:serve:web": "npm run postinstall:web && ng serve -o", 30 | "electron:serve-tsc": "tsc -p tsconfig-serve.json", 31 | "electron:serve": "wait-on http-get://localhost:4200/ && npm run electron:serve-tsc && electron . --serve", 32 | "electron:local": "npm run build:prod && electron .", 33 | "electron:linux": "npm run build:prod && electron-builder build --linux", 34 | "electron:windows": "npm run build:prod && electron-builder build --windows", 35 | "electron:mac": "npm run build:prod && electron-builder build --mac", 36 | "test": "npm run postinstall:web && ng test", 37 | "e2e": "npm run build:prod && mocha --timeout 300000 --require ts-node/register e2e/**/*.spec.ts", 38 | "version": "conventional-changelog -i CHANGELOG.md -s -r 0 && git add CHANGELOG.md", 39 | "lint": "ng lint" 40 | }, 41 | "devDependencies": { 42 | "@angular-devkit/build-angular": "0.802.2", 43 | "@angular/cli": "8.2.2", 44 | "@angular/common": "8.2.2", 45 | "@angular/compiler": "8.2.2", 46 | "@angular/compiler-cli": "8.2.2", 47 | "@angular/core": "8.2.2", 48 | "@angular/forms": "8.2.2", 49 | "@angular/language-service": "8.2.2", 50 | "@angular/platform-browser": "8.2.2", 51 | "@angular/platform-browser-dynamic": "8.2.2", 52 | "@angular/router": "8.2.2", 53 | "@angular/service-worker": "8.2.2", 54 | "@ngx-translate/core": "11.0.1", 55 | "@ngx-translate/http-loader": "4.0.0", 56 | "@types/jasmine": "3.3.16", 57 | "@types/jasminewd2": "2.0.6", 58 | "@types/mocha": "5.2.7", 59 | "@types/node": "12.6.8", 60 | "chai": "4.2.0", 61 | "codelyzer": "5.1.0", 62 | "conventional-changelog-cli": "2.0.21", 63 | "core-js": "3.1.4", 64 | "electron": "^6.0.2", 65 | "electron-builder": "^21.2.0", 66 | "electron-reload": "1.5.0", 67 | "jasmine-core": "3.4.0", 68 | "jasmine-spec-reporter": "4.2.1", 69 | "karma": "4.2.0", 70 | "karma-chrome-launcher": "3.0.0", 71 | "karma-coverage-istanbul-reporter": "2.1.0", 72 | "karma-jasmine": "2.0.1", 73 | "karma-jasmine-html-reporter": "1.4.2", 74 | "mocha": "6.2.0", 75 | "npm-run-all": "4.1.5", 76 | "rxjs": "6.5.2", 77 | "spectron": "8.0.0", 78 | "ts-node": "8.3.0", 79 | "tslint": "5.18.0", 80 | "typescript": "3.5.3", 81 | "wait-on": "3.3.0", 82 | "webdriver-manager": "12.1.5", 83 | "zone.js": "0.9.1", 84 | "@ctrl/ngx-emoji-mart": "^1.0.1", 85 | "@ctrl/ngx-github-buttons": "^3.2.2", 86 | "angular-feather": "^6.0.2", 87 | "angular-split": "^3.0.2", 88 | "ng-indexed-db": "0.0.0-beta.1", 89 | "ng-keyboard-shortcuts": "^8.0.0", 90 | "ngx-markdown": "^8.1.0", 91 | "prismjs": "^1.17.1", 92 | "tailwindcss": "^1.1.2" 93 | }, 94 | "engines": { 95 | "node": ">=10.9.0" 96 | }, 97 | "dependencies": { 98 | "@angular/animations": "^8.0.0 || ^9.0.0-0", 99 | "@angular/cdk": "~8.2.1", 100 | "@angular/forms": "^8.0.0 || ^9.0.0-0", 101 | "@angular/material": "^8.2.1", 102 | "@angular/pwa": "^0.803.6", 103 | "hammerjs": "^2.0.8", 104 | "ngx-electron": "^2.1.1" 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Markdown Editor 6 | 7 | 11 | 12 | 16 | 22 | 28 | 29 | 35 | 36 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 53 | 54 | 62 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 102 | 105 | 106 | 107 | Loading... 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /src/app/constants/app-constants.ts: -------------------------------------------------------------------------------- 1 | const DESC = 'enter description here'; 2 | 3 | export const OPTION = Object.freeze({ 4 | BOLD: "bold", 5 | ITALIC: "italic", 6 | SIZE: "type", 7 | STRIKE: "minus", 8 | LIST: "list", 9 | CHECK_BOX: "check-square", 10 | BLOCK_QUOTE: "chevron-right", 11 | CODE: "code", 12 | TABLE: "columns", 13 | LINK: "link", 14 | IMAGE: "image" 15 | }) 16 | const END_QUOTES = "```" 17 | 18 | export const TOOLBAR = Object.freeze({ 19 | [OPTION.BOLD]: { 20 | text: "Bold ⌘+Shift+B", 21 | startTag: "**", 22 | endTag: "**" 23 | }, 24 | [OPTION.ITALIC]: { 25 | text: "Italic ⌘+Shift+I", 26 | startTag: "*", 27 | endTag: "*" 28 | }, 29 | [OPTION.SIZE]: { 30 | text: "Heading ⌘+Shift+H", 31 | startTag: "#" 32 | }, 33 | [OPTION.STRIKE]: { 34 | text: "Strike ⌘+Shift+S", 35 | startTag: "~~", 36 | endTag: "~~" 37 | }, 38 | [OPTION.LIST]: { 39 | text: "Bullet List ⌘+Shift+L", 40 | startTag: "- " 41 | }, 42 | [OPTION.CHECK_BOX]: { 43 | text: "List ⌘+Shift+C", 44 | startTag: "- [ ] " 45 | }, 46 | [OPTION.BLOCK_QUOTE]: { 47 | text: "Blockquote ⌘+Shift+Q", 48 | startTag: "> " 49 | }, 50 | [OPTION.CODE]: { 51 | text: "Code ⌘+Shift+D", 52 | startTag: '```javascript ', 53 | endTag: END_QUOTES 54 | }, 55 | [OPTION.TABLE]: { 56 | text: "Table ⌘+Shift+T", 57 | startTag: 58 | `| Name | Heading | 59 | |--|--| 60 | | Foo | Bar |` 61 | }, 62 | [OPTION.LINK]: { 63 | text: "Link ⌘+Shift+K", 64 | startTag: `[${DESC}](`, 65 | endTag: ")" 66 | }, 67 | [OPTION.IMAGE]: { 68 | text: "Image ⌘+Shift+G", 69 | startTag: `![${DESC}](`, 70 | endTag: ")" 71 | } 72 | }); 73 | 74 | export const CONTRIBUTORS = ` 75 | ## Contributors ✨ 76 | 77 | Thanks goes to these wonderful people 78 | 79 | 80 | 81 | 82 | 83 | 97 | 110 | 111 |
84 | 85 | Jithin Pariyarath 86 |
87 | 88 | Jithin Pariyarath 89 | 90 |
91 |
92 | 💬 93 | 📖 94 | 👀 95 | 📢 96 |
98 | 99 | Jijin Pariyarath 100 |
101 | 102 | Jijin Pariyarath 103 | 104 |
105 |
106 | 📖 107 | 👀 108 | 🔧 109 |
` 112 | 113 | export const CONTRIBUTION_GUIDE = ` 114 | Contributing 115 | If you've ever wanted to contribute to open source, and a great cause, now is your chance! 116 | See the contributing docs for more information 117 | ` 118 | 119 | export const LICENCE = `# License 120 | 121 | Copyright 2018 122 | 123 | Licensed under the Apache License, Version 2.0 (the "License"); 124 | you may not use this file except in compliance with the License. 125 | You may obtain a copy of the License at 126 | 127 | http://www.apache.org/licenses/LICENSE-2.0 128 | 129 | Unless required by applicable law or agreed to in writing, software 130 | distributed under the License is distributed on an "AS IS" BASIS, 131 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132 | See the License for the specific language governing permissions and 133 | limitations under the License.` 134 | 135 | export const SAMPLE = 136 | ` 137 | 138 | # Paper 139 | 140 | 🚀A "no-cloud" note taking app with "no-internet" sharing. 141 | 142 | [![Paper](https://github.com/JP1016/Paper/blob/master/preview.png?raw=true 'Paper')]() 143 | 144 | ✅ Live Preview: https://paperapp.now.sh 145 | 146 |

147 | Made with ❤️ by Twitter Follow 148 |

149 | 150 | 151 | ## Features 152 | 153 | 🔥PWA Based 154 | 155 | 📖 OpenSource 156 | 157 | ⛓️ Easy Share 158 | 159 | 🔌 No Internet 160 | 161 | 🖥️ LocalStorage 162 | 163 | 📠 Share through QR 164 | 165 | 🌗 Dark/Light Theme 166 | 167 | ## 🤝 Contributing 168 | 169 | Contributions, issues and feature requests are welcome! 😍 170 | 171 | ## Show your support 172 | 173 | Give a ⭐️ if this project helped you! 🥰 174 | 175 | If you like this app , Star it on Github, Follow me on Twitter 176 | ` 177 | -------------------------------------------------------------------------------- /src/app/navbar/navbar.component.html: -------------------------------------------------------------------------------- 1 | 155 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | @import '~@angular/material/prebuilt-themes/indigo-pink.css'; 3 | 4 | body[class='dark-mode'] { 5 | --bg: #0f1119; 6 | --text: #fff; 7 | --text-color: #718096; 8 | --shadow: rgba(27, 31, 46, 0.4); 9 | --selected: #12151f; 10 | --sidebar-shadow: rgba(39, 37, 39, 0.4); 11 | --border: #3333337a; 12 | --button: #1a202c; 13 | --btn-hover: #2d3748; 14 | --sidebar: #1a1c25; 15 | --list-color: #556080; 16 | --ernote-hov: #1a202c; 17 | --note-main-text: #e2e8f0; 18 | --note-sub-text: #718096; 19 | --modal-bg: #1a202c; 20 | --split-img: url('/assets/more-vertical.svg'); 21 | 22 | --blockquote: #ededed12; 23 | 24 | --table-odd: #090b0f; 25 | --table-even: #0f111a; 26 | --table-border: #333; 27 | } 28 | 29 | body[class='light-mode'] { 30 | --bg: #fff; 31 | --text: #212121; 32 | --shadow: rgba(0, 0, 0, 0.04); 33 | --sidebar-shadow: rgba(26, 6, 6, 0.2); 34 | --border: #3333330f; 35 | --button: #edf2f7; 36 | --btn-hover: #e2e8f0; 37 | --sidebar: #edf2f7; 38 | --list-color: #474747; 39 | --selected: #e2e8f0; 40 | 41 | --note-hover: #f7fafc; 42 | --note-main-text: #4a5568; 43 | --note-sub-text: #a0aec0; 44 | --modal-bg: #3b434f; 45 | --split-img: url('/assets/more-vertical-light.svg'); 46 | --blockquote: #edf2f6; 47 | 48 | --table-odd: #f7fafc; 49 | --table-even: #edf2f7; 50 | --table-border: #a0aec0; 51 | } 52 | 53 | * { 54 | font-family: 'Quicksand', sans-serif; 55 | } 56 | 57 | ::selection { 58 | background: #79ffe1; 59 | } 60 | 61 | button:focus { 62 | outline: 0; 63 | } 64 | 65 | html, 66 | body { 67 | font-family: 'Quicksand', sans-serif; 68 | background: var(--bg); 69 | overflow: hidden; 70 | color: var(--text); 71 | } 72 | 73 | .toggle-icon { 74 | display: none; 75 | } 76 | 77 | .fe-icon { 78 | width: 15px !important; 79 | color: var(--text); 80 | height: 16px !important; 81 | } 82 | 83 | .fe-icon:hover { 84 | color: #718096; 85 | } 86 | 87 | .me-editable { 88 | height: 80vh; 89 | padding: 20px; 90 | outline: 0 solid transparent; 91 | } 92 | 93 | .custom-class-h1 { 94 | font-size: 200px; 95 | } 96 | 97 | .custom-class-h2 { 98 | font-size: 15px; 99 | } 100 | 101 | .notelist { 102 | border-bottom: 1px solid var(--border); 103 | padding: 4px 16px; 104 | } 105 | 106 | .notelist .text-sm { 107 | color: var(--note-main-text); 108 | } 109 | 110 | .notelist .text-xs { 111 | color: var(--note-sub-text); 112 | } 113 | 114 | .notelist:hover { 115 | background: var(--note-hover); 116 | } 117 | 118 | .mat-dialog-container { 119 | background: var(--modal-bg); 120 | } 121 | 122 | .mat-dialog-title { 123 | display: flex !important; 124 | justify-content: space-between; 125 | color: var(--note-sub-text); 126 | } 127 | 128 | .ph-badge { 129 | position: absolute; 130 | bottom: 0; 131 | margin-bottom: 40px; 132 | right: 0; 133 | margin-right: 17px; 134 | } 135 | 136 | @media only screen and (max-width: 600px) { 137 | .toggle-icon { 138 | display: flex; 139 | align-items: center; 140 | } 141 | } 142 | 143 | .pointer { 144 | cursor: pointer; 145 | } 146 | 147 | a { 148 | color: #1d88e5; 149 | } 150 | 151 | blockquote { 152 | font-size: 14px; 153 | font-style: italic; 154 | border-left: 3px solid #1d88e5; 155 | line-height: 1.6; 156 | position: relative; 157 | background: var(--blockquote); 158 | padding: 0.3rem 1rem; 159 | } 160 | 161 | p { 162 | margin: 15px 0; 163 | } 164 | 165 | h1 { 166 | font-size: 2em; 167 | } 168 | 169 | h2 { 170 | font-size: 1.5em; 171 | } 172 | 173 | h3 { 174 | font-size: 1.17em; 175 | } 176 | 177 | h4 { 178 | font-size: 1.12em; 179 | } 180 | 181 | h5 { 182 | font-size: 0.83em; 183 | } 184 | 185 | h6 { 186 | font-size: 0.75em; 187 | } 188 | 189 | table, 190 | thead tr, 191 | tbody tr { 192 | border: 1px solid var(--table-border); 193 | } 194 | 195 | th, 196 | td { 197 | padding: 10px; 198 | } 199 | 200 | tr:nth-of-type(odd) { 201 | background-color: var(--table-odd); 202 | } 203 | 204 | tr:nth-of-type(even) { 205 | background-color: var(--table-even); 206 | } 207 | 208 | ul { 209 | list-style-type: disc; 210 | list-style-position: inside; 211 | } 212 | 213 | ol { 214 | list-style-type: decimal; 215 | list-style-position: inside; 216 | } 217 | 218 | ul ul, 219 | ol ul { 220 | list-style-type: circle; 221 | list-style-position: inside; 222 | margin-left: 15px; 223 | } 224 | 225 | ol ol, 226 | ul ol { 227 | list-style-type: lower-latin; 228 | list-style-position: inside; 229 | margin-left: 15px; 230 | } 231 | 232 | .as-split-gutter-icon { 233 | background: var(--sidebar); 234 | background-image: var(--split-img) !important; 235 | } 236 | 237 | .emoji-add .mat-dialog-container { 238 | padding: 0px !important; 239 | background: unset !important; 240 | } 241 | 242 | .mat-dialog-container { 243 | color: var(--text); 244 | min-width: 500px; 245 | background: var(--bg); 246 | } 247 | 248 | *.unselectable { 249 | -moz-user-select: none; 250 | -khtml-user-select: none; 251 | -webkit-user-select: none; 252 | -ms-user-select: none; 253 | user-select: none; 254 | } 255 | 256 | button:disabled { 257 | background: #494949 !important; 258 | color: #e2e8f0; 259 | cursor: not-allowed; 260 | } 261 | 262 | .close-icon { 263 | font-size: 30px; 264 | } 265 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-electron": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "architect": { 11 | "build": { 12 | "builder": "@angular-devkit/build-angular:browser", 13 | "options": { 14 | "outputPath": "dist", 15 | "index": "src/index.html", 16 | "main": "src/main.ts", 17 | "tsConfig": "src/tsconfig.app.json", 18 | "polyfills": "src/polyfills.ts", 19 | "assets": [ 20 | "src/assets", 21 | "src/favicon.ico", 22 | "src/favicon.png", 23 | "src/favicon.icns", 24 | "src/favicon.256x256.png", 25 | "src/favicon.512x512.png", 26 | "src/manifest.webmanifest" 27 | ], 28 | "styles": [ 29 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 30 | "src/styles.scss", 31 | "node_modules/marked/lib/marked.js", "node_modules/prismjs/themes/prism-okaidia.css", "node_modules/@ctrl/ngx-emoji-mart/picker.css" 32 | ], 33 | "scripts": [ 34 | "node_modules/prismjs/prism.js", 35 | "node_modules/prismjs/components/prism-css.min.js" 36 | ] 37 | }, 38 | "configurations": { 39 | "dev": { 40 | "optimization": false, 41 | "outputHashing": "all", 42 | "sourceMap": true, 43 | "extractCss": true, 44 | "namedChunks": false, 45 | "aot": false, 46 | "extractLicenses": true, 47 | "vendorChunk": false, 48 | "buildOptimizer": false, 49 | "fileReplacements": [{ 50 | "replace": "src/environments/environment.ts", 51 | "with": "src/environments/environment.dev.ts" 52 | }] 53 | }, 54 | "production": { 55 | "optimization": true, 56 | "outputHashing": "all", 57 | "sourceMap": false, 58 | "extractCss": true, 59 | "namedChunks": false, 60 | "aot": true, 61 | "extractLicenses": true, 62 | "vendorChunk": false, 63 | "buildOptimizer": true, 64 | "fileReplacements": [{ 65 | "replace": "src/environments/environment.ts", 66 | "with": "src/environments/environment.prod.ts" 67 | }], 68 | "serviceWorker": true, 69 | "ngswConfigPath": "ngsw-config.json" 70 | } 71 | } 72 | }, 73 | "serve": { 74 | "builder": "@angular-devkit/build-angular:dev-server", 75 | "options": { 76 | "browserTarget": "angular-electron:build" 77 | }, 78 | "configurations": { 79 | "dev": { 80 | "browserTarget": "angular-electron:build:dev" 81 | }, 82 | "production": { 83 | "browserTarget": "angular-electron:build:production" 84 | } 85 | } 86 | }, 87 | "extract-i18n": { 88 | "builder": "@angular-devkit/build-angular:extract-i18n", 89 | "options": { 90 | "browserTarget": "angular-electron:build" 91 | } 92 | }, 93 | "test": { 94 | "builder": "@angular-devkit/build-angular:karma", 95 | "options": { 96 | "main": "src/test.ts", 97 | "polyfills": "src/polyfills-test.ts", 98 | "tsConfig": "src/tsconfig.spec.json", 99 | "karmaConfig": "src/karma.conf.js", 100 | "scripts": [], 101 | "styles": [ 102 | "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css", 103 | "src/styles.scss" 104 | ], 105 | "assets": [ 106 | "src/assets", 107 | "src/favicon.ico", 108 | "src/favicon.png", 109 | "src/favicon.icns", 110 | "src/favicon.256x256.png", 111 | "src/favicon.512x512.png", 112 | "src/manifest.webmanifest" 113 | ] 114 | } 115 | }, 116 | "lint": { 117 | "builder": "@angular-devkit/build-angular:tslint", 118 | "options": { 119 | "tsConfig": [ 120 | "src/tsconfig.app.json", 121 | "src/tsconfig.spec.json" 122 | ], 123 | "exclude": [ 124 | "**/node_modules/**" 125 | ] 126 | } 127 | } 128 | } 129 | }, 130 | "angular-electron-e2e": { 131 | "root": "e2e", 132 | "projectType": "application", 133 | "architect": { 134 | "lint": { 135 | "builder": "@angular-devkit/build-angular:tslint", 136 | "options": { 137 | "tsConfig": [ 138 | "e2e/tsconfig.e2e.json" 139 | ], 140 | "exclude": [ 141 | "**/node_modules/**" 142 | ] 143 | } 144 | } 145 | } 146 | } 147 | }, 148 | "defaultProject": "angular-electron", 149 | "schematics": { 150 | "@schematics/angular:component": { 151 | "prefix": "app", 152 | "styleext": "scss" 153 | }, 154 | "@schematics/angular:directive": { 155 | "prefix": "app" 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/app/navbar/navbar.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Inject, Renderer2, ViewChild } from "@angular/core"; 2 | import { DOCUMENT } from "@angular/common"; 3 | import { MatDialog } from "@angular/material"; 4 | import { AddEmojiComponent } from "../add-emoji/add-emoji.component"; 5 | import { ShortcutInput, AllowIn } from "ng-keyboard-shortcuts"; 6 | import { Observable } from "rxjs"; 7 | import { IndexedDB } from "ng-indexed-db"; 8 | import { OptionsDialogComponent } from "../options-dialog/options-dialog.component"; 9 | import { SaveDialogComponent } from "../save-dialog/save-dialog.component"; 10 | import { LoadDialogComponent } from "../load-dialog/load-dialog.component"; 11 | import { OPTION, TOOLBAR } from "../constants/app-constants"; 12 | import { CONTRIB_GUIDELINES_SELECT, CONTRIB_LIST, LICENCE_SELECT } from "../constants/form-constants"; 13 | import { MarkdownService } from "../core/services/markdown.service"; 14 | 15 | @Component({ 16 | selector: "app-navbar", 17 | templateUrl: "./navbar.component.html", 18 | styleUrls: ["./navbar.component.css"] 19 | }) 20 | export class NavbarComponent implements OnInit { 21 | public isDarkMode = true; 22 | public options = OPTION; 23 | public toolbar = TOOLBAR; 24 | public fileName; 25 | shortcuts: ShortcutInput[] = []; 26 | $list: Observable; 27 | 28 | public CONTRIB_GUIDELINES_SELECT = CONTRIB_GUIDELINES_SELECT; 29 | public CONTRIB_LIST = CONTRIB_LIST; 30 | public LICENCE_SELECT = LICENCE_SELECT; 31 | 32 | constructor( 33 | @Inject(DOCUMENT) private document: Document, 34 | private renderer: Renderer2, 35 | private dialog: MatDialog, 36 | private markDown: MarkdownService, 37 | private indexedDbService: IndexedDB 38 | ) { 39 | this.$list = this.indexedDbService.list("markdown_table"); 40 | } 41 | 42 | ngOnInit() { 43 | const theme = localStorage.getItem("theme") || "dark-mode"; 44 | this.switchTheme(theme); 45 | this.loadedMarkupFromLocalStorage(); 46 | } 47 | 48 | loadedMarkupFromLocalStorage() { 49 | this.markDown.markdownFromLocalStorage.subscribe(markdown => { 50 | if (markdown) { 51 | this.fileName = markdown.title; 52 | } 53 | }) 54 | } 55 | copyMarkup() { 56 | this.markDown.copyMarkdown.next(true); 57 | } 58 | 59 | downloadMarkup() { 60 | this.markDown.downloadMarkdown.next(true); 61 | } 62 | 63 | newFile() { 64 | this.fileName = null; 65 | this.markDown.newMarkdown.next(true); 66 | } 67 | 68 | saveMarkup() { 69 | const dialogRef = this.dialog.open(SaveDialogComponent, { 70 | data: { 71 | text: null 72 | } 73 | }); 74 | 75 | dialogRef.afterClosed().subscribe(result => { 76 | if (result && result.hasOwnProperty("data")) { 77 | this.fileName = result.data; 78 | } 79 | }); 80 | 81 | } 82 | 83 | loadMarkup() { 84 | const dialogRef = this.dialog.open(LoadDialogComponent, { 85 | data: { 86 | text: null 87 | } 88 | }); 89 | dialogRef.afterClosed().subscribe(result => { 90 | if (result && result.hasOwnProperty("data")) { 91 | this.fileName = result.data.title; 92 | } 93 | }); 94 | } 95 | 96 | ngAfterViewInit(): void { 97 | this.shortcuts.push( 98 | { 99 | key: ["cmd + shift + b", "ctrl + shift + b"], 100 | allowIn: [AllowIn.Textarea], 101 | command: e => this.markDown.optionChanged.next(OPTION.BOLD), 102 | preventDefault: true 103 | }, 104 | { 105 | key: ["cmd + shift + i", "ctrl + shift + i"], 106 | allowIn: [AllowIn.Textarea], 107 | command: e => this.markDown.optionChanged.next(OPTION.ITALIC), 108 | preventDefault: true 109 | }, 110 | { 111 | key: ["cmd + shift + H", "ctrl + shift + H"], 112 | allowIn: [AllowIn.Textarea], 113 | command: e => this.markDown.optionChanged.next(OPTION.SIZE), 114 | preventDefault: true 115 | }, 116 | { 117 | key: ["cmd + shift + L", "ctrl + shift + L"], 118 | allowIn: [AllowIn.Textarea], 119 | command: e => this.markDown.optionChanged.next(OPTION.LIST), 120 | preventDefault: true 121 | }, 122 | { 123 | key: ["cmd + shift + C", "ctrl + shift + C"], 124 | allowIn: [AllowIn.Textarea], 125 | command: e => this.markDown.optionChanged.next(OPTION.CHECK_BOX), 126 | preventDefault: true 127 | }, 128 | { 129 | key: ["cmd + shift + Q", "ctrl + shift + Q"], 130 | allowIn: [AllowIn.Textarea], 131 | command: e => this.markDown.optionChanged.next(OPTION.BLOCK_QUOTE), 132 | preventDefault: true 133 | }, 134 | { 135 | key: ["cmd + shift + D", "ctrl + shift + D"], 136 | allowIn: [AllowIn.Textarea], 137 | command: e => this.markDown.optionChanged.next(OPTION.CODE), 138 | preventDefault: true 139 | }, 140 | { 141 | key: ["cmd + shift + T", "ctrl + shift + T"], 142 | allowIn: [AllowIn.Textarea], 143 | command: e => this.markDown.optionChanged.next(OPTION.TABLE), 144 | preventDefault: true 145 | }, 146 | { 147 | key: ["cmd + shift + K", "ctrl + shift + K"], 148 | allowIn: [AllowIn.Textarea], 149 | command: e => this.markDown.optionChanged.next(OPTION.LINK), 150 | preventDefault: true 151 | }, 152 | { 153 | key: ["cmd + shift + G", "ctrl + shift + G"], 154 | allowIn: [AllowIn.Textarea], 155 | command: e => this.markDown.optionChanged.next(OPTION.IMAGE), 156 | preventDefault: true 157 | } 158 | ); 159 | } 160 | 161 | openEmojiDialog() { 162 | const dialogRef = this.dialog.open(AddEmojiComponent, { 163 | data: { 164 | text: null 165 | }, 166 | panelClass: "emoji-add" 167 | }); 168 | 169 | dialogRef.afterClosed().subscribe(result => { 170 | if (result && result.hasOwnProperty("success")) { 171 | this.markDown.emojiAdded.next(result.data); 172 | } 173 | }); 174 | } 175 | 176 | //Hack to prevent default angular sorting 177 | sortNull() { } 178 | 179 | formatText(option) { 180 | console.log(option); 181 | 182 | if (option == OPTION.IMAGE || option == OPTION.LINK) { 183 | const dialogRef = this.dialog.open(OptionsDialogComponent, { 184 | data: { 185 | type: option 186 | } 187 | }); 188 | 189 | dialogRef.afterClosed().subscribe(result => { 190 | console.log(result); 191 | if (result && result.hasOwnProperty("success")) { 192 | this.markDown.metaAdded.next(result.data); 193 | } 194 | }); 195 | } else if (Object.values(OPTION).indexOf(option) == -1) { 196 | const dialogRef = this.dialog.open(OptionsDialogComponent, { 197 | data: { 198 | type: option 199 | } 200 | }); 201 | 202 | dialogRef.afterClosed().subscribe(result => { 203 | if (result && result.hasOwnProperty("success")) { 204 | console.log("Success"); 205 | console.log(result); 206 | this.markDown.metaAdded.next(result.data); 207 | } 208 | }); 209 | } else { 210 | console.log("should not"); 211 | this.markDown.optionChanged.next(option); 212 | } 213 | } 214 | 215 | toggleMode() { 216 | let mode; 217 | if (document.body.classList.contains("dark-mode")) mode = "light-mode"; 218 | else mode = "dark-mode"; 219 | 220 | this.switchTheme(mode); 221 | localStorage.setItem("theme", mode); 222 | } 223 | 224 | switchTheme(mode) { 225 | let oldMode; 226 | if (mode === "light-mode") { 227 | oldMode = "dark-mode"; 228 | this.isDarkMode = false; 229 | } 230 | if (mode === "dark-mode") { 231 | this.isDarkMode = true; 232 | oldMode = "light-mode"; 233 | } 234 | 235 | this.renderer.removeClass(this.document.body, oldMode); 236 | this.renderer.addClass(this.document.body, mode); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/app/markup/markup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, ViewChild, ElementRef, HostListener } from "@angular/core"; 2 | import { FormControl } from "@angular/forms"; 3 | import { MatDialog, MatSnackBar } from "@angular/material"; 4 | import { HttpClient } from "@angular/common/http"; 5 | import { IndexedDB } from "ng-indexed-db"; 6 | import { interval } from "rxjs"; 7 | import { OPTION, SAMPLE, TOOLBAR } from "../constants/app-constants"; 8 | import { MarkdownService } from "../core/services/markdown.service"; 9 | 10 | @Component({ 11 | selector: "app-markup", 12 | templateUrl: "./markup.component.html", 13 | styleUrls: ["./markup.component.css"] 14 | }) 15 | export class MarkupComponent implements OnInit { 16 | options = OPTION; 17 | markupCtrl = new FormControl(); 18 | @ViewChild("markupPad", { static: false }) markupPad: ElementRef; 19 | @ViewChild('scrollRaw', { static: false }) scrollRaw: ElementRef; 20 | @ViewChild('scrollMarkup', { static: false }) scrollMarkup: ElementRef; 21 | markdownMode: Boolean = true; 22 | action = { 23 | text: 50, 24 | markup: 50 25 | }; 26 | markdownData; 27 | currentMarkdown = null; 28 | 29 | 30 | 31 | constructor( 32 | private snackBar: MatSnackBar, 33 | private dialog: MatDialog, 34 | private markDownService: MarkdownService, 35 | private indexedDbService: IndexedDB 36 | ) { } 37 | 38 | //Hack to change markdown on empty/dynamic insertion 39 | triggerMarkdownChange() { 40 | this.markdownData = ` 41 | ` 42 | } 43 | 44 | 45 | textAreaEmpty() { 46 | if (this.markdownData.length == 0) { 47 | this.triggerMarkdownChange(); 48 | } 49 | } 50 | 51 | @HostListener('window:beforeunload', ['$event']) 52 | beforeunloadHandler(event) { 53 | localStorage.setItem("saving", "true"); 54 | localStorage.setItem("md", JSON.stringify(this.currentMarkdown)) 55 | localStorage.setItem("recentItem", this.currentMarkdown.id); 56 | } 57 | 58 | 59 | saveFile() { 60 | interval(200).subscribe(_ => { 61 | if (this.currentMarkdown) { 62 | localStorage.setItem("recentItem", this.currentMarkdown.id); 63 | this.indexedDbService 64 | .update("markdown_store", { 65 | title: this.currentMarkdown.title, 66 | id: this.currentMarkdown.id, 67 | data: this.markdownData 68 | }) 69 | .subscribe(response => { 70 | }, error => { }); 71 | 72 | } else { 73 | localStorage.setItem("tempMarkdown", this.markdownData); 74 | } 75 | }); 76 | } 77 | 78 | loadRecent() { 79 | const id = localStorage.getItem("recentItem"); 80 | if (id) { 81 | this.currentMarkdown = JSON.parse(localStorage.getItem("md")); 82 | this.markdownData = this.currentMarkdown.data; 83 | this.markDownService.markdownFromLocalStorage.next(this.currentMarkdown); 84 | } else { 85 | this.markdownData = localStorage.getItem("tempMarkdown") || SAMPLE; 86 | } 87 | } 88 | 89 | ngOnInit() { 90 | this.listenToToolbarEvents(); 91 | this.emojiAdded(); 92 | this.clipboardListener(); 93 | this.downloadListener(); 94 | this.saveListener(); 95 | this.metaListener(); 96 | this.loadMarkdownListener(); 97 | this.newMarkdownListener(); 98 | this.saveFile(); 99 | this.loadRecent(); 100 | 101 | } 102 | 103 | newMarkdownListener() { 104 | this.markDownService.newMarkdown.subscribe(newFile => { 105 | if (newFile) { 106 | localStorage.removeItem("recentItem"); 107 | this.currentMarkdown = null; 108 | this.triggerMarkdownChange(); 109 | 110 | } 111 | }); 112 | } 113 | 114 | loadMarkdownListener() { 115 | this.markDownService.loadMarkdown.subscribe(markdown => { 116 | if (markdown) { 117 | 118 | this.markdownData = markdown.data; 119 | this.currentMarkdown = markdown; 120 | 121 | } 122 | }); 123 | } 124 | 125 | metaListener() { 126 | this.markDownService.metaAdded.subscribe(val => { 127 | if (val && val.hasOwnProperty("type") && val.type != "text") { 128 | const imageDiv = 129 | TOOLBAR[val.type].startTag.replace( 130 | "enter description here", 131 | val.description 132 | ) + 133 | val.link + 134 | TOOLBAR[val.type].endTag; 135 | this.insertAtCaret(imageDiv); 136 | } else if (val && val.hasOwnProperty("type") && val.type == "text") { 137 | this.insertAtCaret((val as any).descr); 138 | } 139 | }); 140 | } 141 | 142 | saveMarkup(fileName) { 143 | this.indexedDbService 144 | .create("markdown_store", { title: fileName, data: this.markdownData }) 145 | .subscribe( 146 | response => { 147 | this.snackBar.open("Markdown Saved !! 💾", " ", { 148 | duration: 1000 149 | }); 150 | }, 151 | error => { 152 | this.snackBar.open("Error Occured while saving markdown !! 🛑", " ", { 153 | duration: 1000 154 | }); 155 | } 156 | ); 157 | } 158 | 159 | copyMarkDown() { 160 | let selBox = document.createElement("textarea"); 161 | selBox.style.position = "fixed"; 162 | selBox.style.left = "0"; 163 | selBox.style.top = "0"; 164 | selBox.style.opacity = "0"; 165 | selBox.value = this.markdownData; 166 | document.body.appendChild(selBox); 167 | selBox.focus(); 168 | selBox.select(); 169 | document.execCommand("copy"); 170 | document.body.removeChild(selBox); 171 | 172 | this.snackBar.open("Markdown Copied to Clipboard 📋", " ", { 173 | duration: 1000 174 | }); 175 | } 176 | 177 | download(filename, text) { 178 | let element = document.createElement("a"); 179 | element.setAttribute( 180 | "href", 181 | "data:text/plain;charset=utf-8," + encodeURIComponent(text) 182 | ); 183 | element.setAttribute("download", filename); 184 | element.style.display = "none"; 185 | document.body.appendChild(element); 186 | element.click(); 187 | document.body.removeChild(element); 188 | } 189 | 190 | replaceSelectedText(startTag, endTag) { 191 | let sel; 192 | let range; 193 | if (window.getSelection) { 194 | sel = window.getSelection(); 195 | if (sel && sel.anchorNode.parentElement.id != "splitMain") { 196 | return; 197 | } 198 | if (sel.rangeCount) { 199 | range = sel.getRangeAt(0); 200 | const selectedContent = sel.toString(); 201 | range.deleteContents(); 202 | let replaceDiv = startTag + selectedContent; 203 | if (endTag) { 204 | replaceDiv = replaceDiv + endTag; 205 | } 206 | document.execCommand("insertText", false, replaceDiv); 207 | } 208 | } else if ( 209 | (document as any).selection && 210 | (document as any).selection.createRange 211 | ) { 212 | range = (document as any).selection.createRange(); 213 | range.text = startTag; 214 | } 215 | } 216 | 217 | emojiAdded() { 218 | this.markDownService.emojiAdded.subscribe(emoji => { 219 | if (emoji) { 220 | this.insertAtCaret(emoji); 221 | } 222 | }); 223 | } 224 | 225 | listenToToolbarEvents() { 226 | this.markDownService.optionChanged.subscribe(value => { 227 | if (value) { 228 | this.replaceSelectedText( 229 | TOOLBAR[value].startTag, 230 | TOOLBAR[value].endTag 231 | ); 232 | } 233 | }); 234 | } 235 | 236 | clipboardListener() { 237 | this.markDownService.copyMarkdown.subscribe(value => { 238 | if (value) { 239 | this.copyMarkDown(); 240 | } 241 | }); 242 | } 243 | 244 | downloadListener() { 245 | this.markDownService.downloadMarkdown.subscribe(value => { 246 | if (value) { 247 | this.download("README.md", this.markdownData); 248 | } 249 | }); 250 | } 251 | 252 | saveListener() { 253 | this.markDownService.saveMarkdown.subscribe(value => { 254 | if (value) { 255 | this.saveMarkup(this.markDownService.saveMarkdown.getValue()); 256 | } 257 | }); 258 | } 259 | 260 | insertAtCaret(text) { 261 | if (text) { 262 | const txtarea = document.getElementById("mArea"); 263 | if (!txtarea) { 264 | return; 265 | } 266 | 267 | let scrollPos = txtarea.scrollTop; 268 | let strPos = 0; 269 | let br = 270 | (txtarea as any).selectionStart || 271 | (txtarea as any).selectionStart == "0" 272 | ? "ff" 273 | : (document as any).selection 274 | ? "ie" 275 | : false; 276 | if (br == "ie") { 277 | txtarea.focus(); 278 | let range = (document as any).selection.createRange(); 279 | range.moveStart("character", -(txtarea as any).value.length); 280 | strPos = range.text.length; 281 | } else if (br == "ff") { 282 | strPos = (txtarea as any).selectionStart; 283 | } 284 | 285 | let front = (txtarea as any).value.substring(0, strPos); 286 | let back = (txtarea as any).value.substring( 287 | strPos, 288 | (txtarea as any).value.length 289 | ); 290 | this.markdownData = front + text + back; 291 | strPos = strPos + text.length; 292 | if (br == "ie") { 293 | txtarea.focus(); 294 | let ieRange = (document as any).selection.createRange(); 295 | ieRange.moveStart("character", -(txtarea as any).value.length); 296 | ieRange.moveStart("character", strPos); 297 | ieRange.moveEnd("character", 0); 298 | ieRange.select(); 299 | } else if (br == "ff") { 300 | (txtarea as any).selectionStart = strPos; 301 | (txtarea as any).selectionEnd = strPos; 302 | txtarea.focus(); 303 | } 304 | 305 | txtarea.scrollTop = scrollPos; 306 | 307 | } 308 | 309 | 310 | } 311 | } 312 | -------------------------------------------------------------------------------- /src/app/navbar/navbar.component.css: -------------------------------------------------------------------------------- 1 | .header { 2 | display: flex; 3 | width: 100%; 4 | justify-content: space-between; 5 | align-items: center; 6 | } 7 | 8 | .logo { 9 | display: flex; 10 | } 11 | 12 | .logo span { 13 | visibility: hidden; 14 | } 15 | 16 | .logo:hover span { 17 | visibility: visible; 18 | } 19 | 20 | .menu { 21 | display: flex; 22 | align-items: center; 23 | flex: 1; 24 | } 25 | 26 | .end { 27 | justify-content: flex-end; 28 | } 29 | 30 | .github-star { 31 | margin-top: -4px; 32 | } 33 | 34 | .menu a { 35 | padding-left: 20px; 36 | display: flex; 37 | align-items: center; 38 | } 39 | 40 | .menu button { 41 | padding-left: 20px; 42 | display: flex; 43 | align-items: center; 44 | } 45 | 46 | 47 | nav { 48 | box-shadow: 0 4px 12px 0 var(--shadow) !important; 49 | } 50 | 51 | .navbar img { 52 | padding-right: 10px; 53 | height: 40px; 54 | } 55 | 56 | .navbar { 57 | position: relative; 58 | display: -ms-flexbox; 59 | display: flex; 60 | -ms-flex-wrap: wrap; 61 | flex-wrap: wrap; 62 | -ms-flex-align: center; 63 | align-items: center; 64 | -ms-flex-pack: justify; 65 | justify-content: space-between; 66 | padding: 0.5rem 1rem; 67 | } 68 | 69 | .navbar>.container, 70 | .navbar>.container-fluid { 71 | display: -ms-flexbox; 72 | display: flex; 73 | -ms-flex-wrap: wrap; 74 | flex-wrap: wrap; 75 | -ms-flex-align: center; 76 | align-items: center; 77 | -ms-flex-pack: justify; 78 | justify-content: space-between; 79 | } 80 | 81 | .navbar-brand { 82 | display: inline-block; 83 | padding-top: 0.3125rem; 84 | padding-bottom: 0.3125rem; 85 | margin-right: 1rem; 86 | font-size: 1.25rem; 87 | line-height: inherit; 88 | white-space: nowrap; 89 | } 90 | 91 | .navbar-brand:hover, 92 | .navbar-brand:focus { 93 | text-decoration: none; 94 | } 95 | 96 | .navbar-nav { 97 | display: -ms-flexbox; 98 | display: flex; 99 | -ms-flex-direction: column; 100 | flex-direction: column; 101 | padding-left: 0; 102 | margin-bottom: 0; 103 | list-style: none; 104 | } 105 | 106 | .navbar-nav .nav-link { 107 | padding-right: 0; 108 | padding-left: 0; 109 | } 110 | 111 | .navbar-nav .dropdown-menu { 112 | position: static; 113 | float: none; 114 | } 115 | 116 | .navbar-text { 117 | display: inline-block; 118 | padding-top: 0.5rem; 119 | padding-bottom: 0.5rem; 120 | } 121 | 122 | .navbar-collapse { 123 | -ms-flex-preferred-size: 100%; 124 | flex-basis: 100%; 125 | -ms-flex-positive: 1; 126 | flex-grow: 1; 127 | -ms-flex-align: center; 128 | align-items: center; 129 | } 130 | 131 | .navbar-toggler { 132 | padding: 0.25rem 0.75rem; 133 | font-size: 1.25rem; 134 | line-height: 1; 135 | background-color: transparent; 136 | border: 1px solid transparent; 137 | border-radius: 0.25rem; 138 | } 139 | 140 | .navbar-toggler:hover, 141 | .navbar-toggler:focus { 142 | text-decoration: none; 143 | } 144 | 145 | .navbar-toggler-icon { 146 | display: inline-block; 147 | width: 1.5em; 148 | height: 1.5em; 149 | vertical-align: middle; 150 | content: ''; 151 | background: no-repeat center center; 152 | background-size: 100% 100%; 153 | } 154 | 155 | @media (max-width: 575.98px) { 156 | 157 | .navbar-expand-sm>.container, 158 | .navbar-expand-sm>.container-fluid { 159 | padding-right: 0; 160 | padding-left: 0; 161 | } 162 | } 163 | 164 | @media (min-width: 576px) { 165 | .navbar-expand-sm { 166 | -ms-flex-flow: row nowrap; 167 | flex-flow: row nowrap; 168 | -ms-flex-pack: start; 169 | justify-content: flex-start; 170 | } 171 | 172 | .navbar-expand-sm .navbar-nav { 173 | -ms-flex-direction: row; 174 | flex-direction: row; 175 | } 176 | 177 | .navbar-expand-sm .navbar-nav .dropdown-menu { 178 | position: absolute; 179 | } 180 | 181 | .navbar-expand-sm .navbar-nav .nav-link { 182 | padding-right: 0.5rem; 183 | padding-left: 0.5rem; 184 | } 185 | 186 | .navbar-expand-sm>.container, 187 | .navbar-expand-sm>.container-fluid { 188 | -ms-flex-wrap: nowrap; 189 | flex-wrap: nowrap; 190 | } 191 | 192 | .navbar-expand-sm .navbar-collapse { 193 | display: -ms-flexbox !important; 194 | display: flex !important; 195 | -ms-flex-preferred-size: auto; 196 | flex-basis: auto; 197 | } 198 | 199 | .navbar-expand-sm .navbar-toggler { 200 | display: none; 201 | } 202 | } 203 | 204 | @media (max-width: 767.98px) { 205 | 206 | .navbar-expand-md>.container, 207 | .navbar-expand-md>.container-fluid { 208 | padding-right: 0; 209 | padding-left: 0; 210 | } 211 | } 212 | 213 | @media (min-width: 768px) { 214 | .navbar-expand-md { 215 | -ms-flex-flow: row nowrap; 216 | flex-flow: row nowrap; 217 | -ms-flex-pack: start; 218 | justify-content: flex-start; 219 | } 220 | 221 | .navbar-expand-md .navbar-nav { 222 | -ms-flex-direction: row; 223 | flex-direction: row; 224 | } 225 | 226 | .navbar-expand-md .navbar-nav .dropdown-menu { 227 | position: absolute; 228 | } 229 | 230 | .navbar-expand-md .navbar-nav .nav-link { 231 | padding-right: 0.5rem; 232 | padding-left: 0.5rem; 233 | } 234 | 235 | .navbar-expand-md>.container, 236 | .navbar-expand-md>.container-fluid { 237 | -ms-flex-wrap: nowrap; 238 | flex-wrap: nowrap; 239 | } 240 | 241 | .navbar-expand-md .navbar-collapse { 242 | display: -ms-flexbox !important; 243 | display: flex !important; 244 | -ms-flex-preferred-size: auto; 245 | flex-basis: auto; 246 | } 247 | 248 | .navbar-expand-md .navbar-toggler { 249 | display: none; 250 | } 251 | } 252 | 253 | @media (max-width: 991.98px) { 254 | 255 | .navbar-expand-lg>.container, 256 | .navbar-expand-lg>.container-fluid { 257 | padding-right: 0; 258 | padding-left: 0; 259 | } 260 | } 261 | 262 | @media (min-width: 992px) { 263 | .navbar-expand-lg { 264 | -ms-flex-flow: row nowrap; 265 | flex-flow: row nowrap; 266 | -ms-flex-pack: start; 267 | justify-content: flex-start; 268 | } 269 | 270 | .navbar-expand-lg .navbar-nav { 271 | -ms-flex-direction: row; 272 | flex-direction: row; 273 | } 274 | 275 | .navbar-expand-lg .navbar-nav .dropdown-menu { 276 | position: absolute; 277 | } 278 | 279 | .navbar-expand-lg .navbar-nav .nav-link { 280 | padding-right: 0.5rem; 281 | padding-left: 0.5rem; 282 | } 283 | 284 | .navbar-expand-lg>.container, 285 | .navbar-expand-lg>.container-fluid { 286 | -ms-flex-wrap: nowrap; 287 | flex-wrap: nowrap; 288 | } 289 | 290 | .navbar-expand-lg .navbar-collapse { 291 | display: -ms-flexbox !important; 292 | display: flex !important; 293 | -ms-flex-preferred-size: auto; 294 | flex-basis: auto; 295 | } 296 | 297 | .navbar-expand-lg .navbar-toggler { 298 | display: none; 299 | } 300 | } 301 | 302 | @media (max-width: 1199.98px) { 303 | 304 | .navbar-expand-xl>.container, 305 | .navbar-expand-xl>.container-fluid { 306 | padding-right: 0; 307 | padding-left: 0; 308 | } 309 | } 310 | 311 | @media (min-width: 1200px) { 312 | .navbar-expand-xl { 313 | -ms-flex-flow: row nowrap; 314 | flex-flow: row nowrap; 315 | -ms-flex-pack: start; 316 | justify-content: flex-start; 317 | } 318 | 319 | .navbar-expand-xl .navbar-nav { 320 | -ms-flex-direction: row; 321 | flex-direction: row; 322 | } 323 | 324 | .navbar-expand-xl .navbar-nav .dropdown-menu { 325 | position: absolute; 326 | } 327 | 328 | .navbar-expand-xl .navbar-nav .nav-link { 329 | padding-right: 0.5rem; 330 | padding-left: 0.5rem; 331 | } 332 | 333 | .navbar-expand-xl>.container, 334 | .navbar-expand-xl>.container-fluid { 335 | -ms-flex-wrap: nowrap; 336 | flex-wrap: nowrap; 337 | } 338 | 339 | .navbar-expand-xl .navbar-collapse { 340 | display: -ms-flexbox !important; 341 | display: flex !important; 342 | -ms-flex-preferred-size: auto; 343 | flex-basis: auto; 344 | } 345 | 346 | .navbar-expand-xl .navbar-toggler { 347 | display: none; 348 | } 349 | } 350 | 351 | .navbar-expand { 352 | -ms-flex-flow: row nowrap; 353 | flex-flow: row nowrap; 354 | -ms-flex-pack: start; 355 | justify-content: flex-start; 356 | } 357 | 358 | .navbar-expand>.container, 359 | .navbar-expand>.container-fluid { 360 | padding-right: 0; 361 | padding-left: 0; 362 | } 363 | 364 | .navbar-expand .navbar-nav { 365 | -ms-flex-direction: row; 366 | flex-direction: row; 367 | } 368 | 369 | .navbar-expand .navbar-nav .dropdown-menu { 370 | position: absolute; 371 | } 372 | 373 | .navbar-expand .navbar-nav .nav-link { 374 | padding-right: 0.5rem; 375 | padding-left: 0.5rem; 376 | } 377 | 378 | .navbar-expand>.container, 379 | .navbar-expand>.container-fluid { 380 | -ms-flex-wrap: nowrap; 381 | flex-wrap: nowrap; 382 | } 383 | 384 | .navbar-expand .navbar-collapse { 385 | display: -ms-flexbox !important; 386 | display: flex !important; 387 | -ms-flex-preferred-size: auto; 388 | flex-basis: auto; 389 | } 390 | 391 | .navbar-expand .navbar-toggler { 392 | display: none; 393 | } 394 | 395 | .navbar-light .navbar-brand { 396 | color: var(--text); 397 | } 398 | 399 | .navbar-light .navbar-brand:hover, 400 | .navbar-light .navbar-brand:focus { 401 | color: var(--text); 402 | } 403 | 404 | .navbar-light .navbar-nav .nav-link { 405 | color: var(--text); 406 | } 407 | 408 | .navbar-light .navbar-nav .nav-link:hover, 409 | .navbar-light .navbar-nav .nav-link:focus { 410 | color: var(--text); 411 | } 412 | 413 | .navbar-light .navbar-nav .nav-link.disabled { 414 | color: var(--text); 415 | } 416 | 417 | .navbar-light .navbar-nav .show>.nav-link, 418 | .navbar-light .navbar-nav .active>.nav-link, 419 | .navbar-light .navbar-nav .nav-link.show, 420 | .navbar-light .navbar-nav .nav-link.active { 421 | color: var(--text); 422 | } 423 | 424 | .navbar-light .navbar-toggler { 425 | color: rgba(0, 0, 0, 0.5); 426 | border-color: rgba(0, 0, 0, 0.1); 427 | } 428 | 429 | .navbar-light .navbar-toggler-icon { 430 | background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); 431 | } 432 | 433 | .navbar-light .navbar-text { 434 | color: rgba(0, 0, 0, 0.5); 435 | } 436 | 437 | .navbar-light .navbar-text a { 438 | color: rgba(0, 0, 0, 0.9); 439 | } 440 | 441 | .navbar-light .navbar-text a:hover, 442 | .navbar-light .navbar-text a:focus { 443 | color: rgba(0, 0, 0, 0.9); 444 | } 445 | 446 | .navbar-dark .navbar-brand { 447 | color: #fff; 448 | } 449 | 450 | .navbar-dark .navbar-brand:hover, 451 | .navbar-dark .navbar-brand:focus { 452 | color: #fff; 453 | } 454 | 455 | .navbar-dark .navbar-nav .nav-link { 456 | color: rgba(255, 255, 255, 0.5); 457 | } 458 | 459 | .navbar-dark .navbar-nav .nav-link:hover, 460 | .navbar-dark .navbar-nav .nav-link:focus { 461 | color: rgba(255, 255, 255, 0.75); 462 | } 463 | 464 | .navbar-dark .navbar-nav .nav-link.disabled { 465 | color: rgba(255, 255, 255, 0.25); 466 | } 467 | 468 | .navbar-dark .navbar-nav .show>.nav-link, 469 | .navbar-dark .navbar-nav .active>.nav-link, 470 | .navbar-dark .navbar-nav .nav-link.show, 471 | .navbar-dark .navbar-nav .nav-link.active { 472 | color: #fff; 473 | } 474 | 475 | .navbar-dark .navbar-toggler { 476 | color: rgba(255, 255, 255, 0.5); 477 | border-color: rgba(255, 255, 255, 0.1); 478 | } 479 | 480 | .navbar-dark .navbar-toggler-icon { 481 | background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); 482 | } 483 | 484 | .navbar-dark .navbar-text { 485 | color: rgba(255, 255, 255, 0.5); 486 | } 487 | 488 | .navbar-dark .navbar-text a { 489 | color: #fff; 490 | } 491 | 492 | .navbar-dark .navbar-text a:hover, 493 | .navbar-dark .navbar-text a:focus { 494 | color: #fff; 495 | } 496 | 497 | 498 | .emoji-add { 499 | width: 550px; 500 | padding: 0px !important; 501 | 502 | } 503 | 504 | mat-dialog-container { 505 | padding: 0px !important; 506 | 507 | } 508 | 509 | .warning { 510 | padding-top: 3px; 511 | color: #ff9301; 512 | } 513 | 514 | .file-icon { 515 | margin-top: 4px 516 | } 517 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 6.1.0 (2019-08-15) 2 | 3 | * [DELETE]: vscode settings removed ([becc9b4](https://github.com/maximegris/angular-electron/commit/becc9b4)) 4 | * [UPDATE]: Typescript version fixes ([a284c23](https://github.com/maximegris/angular-electron/commit/a284c23)) 5 | * Angular src restructured as modular as per angular official guidelines, .travis.yml support added fo ([5983703](https://github.com/maximegris/angular-electron/commit/5983703)) 6 | * Corejs path updates ([88056d6](https://github.com/maximegris/angular-electron/commit/88056d6)) 7 | * Electron 6.0.0 ([1aef350](https://github.com/maximegris/angular-electron/commit/1aef350)) 8 | * fix/ Version Electron in README ([acf0d4f](https://github.com/maximegris/angular-electron/commit/acf0d4f)) 9 | * misc/ upgrade Angular 8.2 / Spectron 7 ([6e2211f](https://github.com/maximegris/angular-electron/commit/6e2211f)) 10 | * Update dependencies ([bd51f28](https://github.com/maximegris/angular-electron/commit/bd51f28)) 11 | 12 | 13 | 14 | ## 6.0.1 (2019-05-31) 15 | 16 | * [Bumped Version] 6.0.1 ([4f9cef3](https://github.com/maximegris/angular-electron/commit/4f9cef3)) 17 | * ref/ strict version build-angular & zonejs ([5a24b56](https://github.com/maximegris/angular-electron/commit/5a24b56)) 18 | * ref/ strict version codelyzer ([6ede0c8](https://github.com/maximegris/angular-electron/commit/6ede0c8)) 19 | 20 | 21 | 22 | ## 6.0.0 (2019-05-31) 23 | 24 | * [Bumped Version] 6.0.0 ([fb719ab](https://github.com/maximegris/angular-electron/commit/fb719ab)) 25 | * Add CI for macOS. ([3ba02e3](https://github.com/maximegris/angular-electron/commit/3ba02e3)) 26 | * bump angular version ([7a564a0](https://github.com/maximegris/angular-electron/commit/7a564a0)) 27 | * bump tslint & codelyzer versions, update tslint rules & alphabetize ([8425cdc](https://github.com/maximegris/angular-electron/commit/8425cdc)) 28 | * Fix Travis CI link ([10aaa4c](https://github.com/maximegris/angular-electron/commit/10aaa4c)) 29 | * Not gitignore src/karma.conf.js ([7599320](https://github.com/maximegris/angular-electron/commit/7599320)) 30 | * ref/ upgrade Angular 8 and Electron 5 ([92334cf](https://github.com/maximegris/angular-electron/commit/92334cf)) 31 | * Remove Node.js v12. ([ccbf6cd](https://github.com/maximegris/angular-electron/commit/ccbf6cd)) 32 | * Run CI for Node.js version 10 ([2538965](https://github.com/maximegris/angular-electron/commit/2538965)) 33 | * update versions and prepare for electron 5 ([07a5786](https://github.com/maximegris/angular-electron/commit/07a5786)) 34 | * Use service xvfb. ([4db31e3](https://github.com/maximegris/angular-electron/commit/4db31e3)) 35 | * version bump ([bb1d6bb](https://github.com/maximegris/angular-electron/commit/bb1d6bb)) 36 | * feat(CI): update Ubuntu and Node versions in Travis ([e0ff557](https://github.com/maximegris/angular-electron/commit/e0ff557)) 37 | * fix: type conflicts ([a2971bf](https://github.com/maximegris/angular-electron/commit/a2971bf)) 38 | * fix(e2e): add mocha types ([20e1e89](https://github.com/maximegris/angular-electron/commit/20e1e89)) 39 | * fix(e2e): without devTools ([2581983](https://github.com/maximegris/angular-electron/commit/2581983)), closes [/github.com/electron/spectron/issues/174#issuecomment-319242097](https://github.com//github.com/electron/spectron/issues/174/issues/issuecomment-319242097) 40 | * chore: Spectron for e2e tests ([901438a](https://github.com/maximegris/angular-electron/commit/901438a)) 41 | 42 | 43 | 44 | ## 5.1.0 (2018-11-30) 45 | 46 | * [Bumped Version] 5.1.0 ([b790e12](https://github.com/maximegris/angular-electron/commit/b790e12)) 47 | * fix/ typo Angular 7 ([fde371f](https://github.com/maximegris/angular-electron/commit/fde371f)) 48 | * fix/ typo README ([723233c](https://github.com/maximegris/angular-electron/commit/723233c)) 49 | * fix/ typo script npm electron:windows ([45bab44](https://github.com/maximegris/angular-electron/commit/45bab44)) 50 | * ref/ remve npx - fix vulnerabilities ([41aeb57](https://github.com/maximegris/angular-electron/commit/41aeb57)) 51 | * update README ([f146d5d](https://github.com/maximegris/angular-electron/commit/f146d5d)) 52 | 53 | 54 | 55 | ## 5.0.0 (2018-11-11) 56 | 57 | * Fix typos in README file ([0440ee9](https://github.com/maximegris/angular-electron/commit/0440ee9)) 58 | * ref/ Generate changelog ([a89b3ce](https://github.com/maximegris/angular-electron/commit/a89b3ce)) 59 | * ref/ Upgrade to Angular 7 ([315a79b](https://github.com/maximegris/angular-electron/commit/315a79b)) 60 | * Update electron-builder.json files rule ([82c7bcf](https://github.com/maximegris/angular-electron/commit/82c7bcf)) 61 | * Update Version Electron 2 to 3 #hacktoberfest ([f083328](https://github.com/maximegris/angular-electron/commit/f083328)) 62 | 63 | 64 | 65 | ## 4.2.2 (2018-08-22) 66 | 67 | * fix/ build serve & electron with single tsc command ([9106c8f](https://github.com/maximegris/angular-electron/commit/9106c8f)) 68 | * fix/ typo README ([a9448aa](https://github.com/maximegris/angular-electron/commit/a9448aa)) 69 | 70 | 71 | 72 | ## 4.2.1 (2018-08-22) 73 | 74 | * fix/ jslib in main process error ([ef33f5e](https://github.com/maximegris/angular-electron/commit/ef33f5e)) 75 | 76 | 77 | 78 | ## 4.2.0 (2018-08-19) 79 | 80 | * [Bumped Version] V4.2.0 ([0da3856](https://github.com/maximegris/angular-electron/commit/0da3856)) 81 | * fix/ electron builder output directories #200 ([f4535e5](https://github.com/maximegris/angular-electron/commit/f4535e5)), closes [#200](https://github.com/maximegris/angular-electron/issues/200) 82 | * Make sure tsconfig be used. ([961c8b1](https://github.com/maximegris/angular-electron/commit/961c8b1)) 83 | * ref/ remove some directories of tsconfig.app.json ([1adad4a](https://github.com/maximegris/angular-electron/commit/1adad4a)) 84 | * Upgrade Angular (6.1.2) deps ([d8818c1](https://github.com/maximegris/angular-electron/commit/d8818c1)) 85 | 86 | 87 | 88 | ## 4.1.0 (2018-06-27) 89 | 90 | * Allow Angular Using Electron Modules ([ec705ee](https://github.com/maximegris/angular-electron/commit/ec705ee)) 91 | * fix/ version angular (revert 6.0.6 -> 6.0.5) ([63a41b8](https://github.com/maximegris/angular-electron/commit/63a41b8)) 92 | * fix/ version ts-node ([0d8341a](https://github.com/maximegris/angular-electron/commit/0d8341a)) 93 | * ref/ postinstall web & electron ([50657d0](https://github.com/maximegris/angular-electron/commit/50657d0)) 94 | * update README ([1d48e32](https://github.com/maximegris/angular-electron/commit/1d48e32)) 95 | * feat(zone): add zone-patch-electron to patch Electron native APIs in polyfills ([01842e2](https://github.com/maximegris/angular-electron/commit/01842e2)) 96 | 97 | 98 | 99 | ## 4.0.0 (2018-05-25) 100 | 101 | * misc/ remove unused packages ([a7e33b6](https://github.com/maximegris/angular-electron/commit/a7e33b6)) 102 | * misc/ update Changelog ([b758122](https://github.com/maximegris/angular-electron/commit/b758122)) 103 | * ref/ upgrade angular to 6.0.3 ([e7fac6e](https://github.com/maximegris/angular-electron/commit/e7fac6e)) 104 | 105 | 106 | 107 | ## 3.4.1 (2018-05-25) 108 | 109 | * misc/ update changelog ([70b359f](https://github.com/maximegris/angular-electron/commit/70b359f)) 110 | * version 3.4.1 ([308ea9c](https://github.com/maximegris/angular-electron/commit/308ea9c)) 111 | 112 | 113 | 114 | ## 3.4.0 (2018-05-25) 115 | 116 | * misc/ update changelog ([7d5eeb3](https://github.com/maximegris/angular-electron/commit/7d5eeb3)) 117 | * Modify electron builder configuration to remove source code and tests ([0cf6899](https://github.com/maximegris/angular-electron/commit/0cf6899)) 118 | * ref/ remove contributors ([6dc97a1](https://github.com/maximegris/angular-electron/commit/6dc97a1)) 119 | * The file is unused ([05c9e39](https://github.com/maximegris/angular-electron/commit/05c9e39)) 120 | * Translation issue ([35354b1](https://github.com/maximegris/angular-electron/commit/35354b1)) 121 | * version 3.4.0 ([06d6b0f](https://github.com/maximegris/angular-electron/commit/06d6b0f)) 122 | * refactor: update electron, electron-builder to latest (2.0.2, 20.14.7) ([f19e6ee](https://github.com/maximegris/angular-electron/commit/f19e6ee)) 123 | * refactor: upgrade to NodeJS 8, Angular 6, CLI 6, Electron 2.0, RxJS 6.1 ([e37efdb](https://github.com/maximegris/angular-electron/commit/e37efdb)) 124 | * refactor(hooks): replace hooks to ng-cli fileReplacements logic ([c940037](https://github.com/maximegris/angular-electron/commit/c940037)) 125 | * fix(test): create polyfills-test.ts for karma test & setup Travis CI ([7fbc68c](https://github.com/maximegris/angular-electron/commit/7fbc68c)) 126 | * fix(travis): set progress to false (speed up npm) ([be48531](https://github.com/maximegris/angular-electron/commit/be48531)) 127 | 128 | 129 | 130 | ## 3.3.0 (2018-04-15) 131 | 132 | * add Changelog file ([71083f1](https://github.com/maximegris/angular-electron/commit/71083f1)) 133 | * fix/ typo README.md (production variables) ([a8c2b63](https://github.com/maximegris/angular-electron/commit/a8c2b63)) 134 | * version 3.3.0 ([a88bda6](https://github.com/maximegris/angular-electron/commit/a88bda6)) 135 | * version 3.3.0 changelog ([ddfbbf9](https://github.com/maximegris/angular-electron/commit/ddfbbf9)) 136 | 137 | 138 | 139 | ## 3.2.0 (2018-04-15) 140 | 141 | * fix e2e tests based on PR #161 and terminate the npm process after test execution ([fccf348](https://github.com/maximegris/angular-electron/commit/fccf348)), closes [#161](https://github.com/maximegris/angular-electron/issues/161) 142 | * fix/ app e2e spec ([8046b2a](https://github.com/maximegris/angular-electron/commit/8046b2a)) 143 | * Including electron to eliminate Electron not found err sg ([d78203f](https://github.com/maximegris/angular-electron/commit/d78203f)) 144 | * provide webFrame access ([6bd044e](https://github.com/maximegris/angular-electron/commit/6bd044e)) 145 | * ref/ add node/electron module import as exemple : fs and remote ([e3ad12d](https://github.com/maximegris/angular-electron/commit/e3ad12d)) 146 | * remove copyfiles ([9af5138](https://github.com/maximegris/angular-electron/commit/9af5138)) 147 | * update dependencies ([89963ab](https://github.com/maximegris/angular-electron/commit/89963ab)) 148 | * version 3.2.0 ([8dc69fa](https://github.com/maximegris/angular-electron/commit/8dc69fa)) 149 | 150 | 151 | 152 | ## 3.1.0 (2018-03-15) 153 | 154 | * Added option -o to script npm run ng:serve so that it really open the browser ([72aff8d](https://github.com/maximegris/angular-electron/commit/72aff8d)) 155 | * Fix to change environment ([448d68b](https://github.com/maximegris/angular-electron/commit/448d68b)) 156 | * version 3.1.0 ([f7c71e7](https://github.com/maximegris/angular-electron/commit/f7c71e7)) 157 | 158 | 159 | 160 | ## 3.0.1 (2018-03-07) 161 | 162 | * fix/ icon app ([22699ef](https://github.com/maximegris/angular-electron/commit/22699ef)) 163 | * version 3.0.1 ([5258ff1](https://github.com/maximegris/angular-electron/commit/5258ff1)) 164 | 165 | 166 | 167 | ## 3.0.0 (2018-02-25) 168 | 169 | * fix/ TranslateModule test ([7863aa9](https://github.com/maximegris/angular-electron/commit/7863aa9)) 170 | * Ng not ejected anymore ([67ab31c](https://github.com/maximegris/angular-electron/commit/67ab31c)) 171 | * pin all dependency versions ([0558d6a](https://github.com/maximegris/angular-electron/commit/0558d6a)) 172 | * update dependencies and fix unit tests ([4d3ca6e](https://github.com/maximegris/angular-electron/commit/4d3ca6e)) 173 | 174 | 175 | 176 | ## 2.7.1 (2018-02-15) 177 | 178 | * ref/ dernière version cli ([3df8158](https://github.com/maximegris/angular-electron/commit/3df8158)) 179 | * version 2.7.1 ([1ae6f7a](https://github.com/maximegris/angular-electron/commit/1ae6f7a)) 180 | 181 | 182 | 183 | ## 2.7.0 (2018-02-15) 184 | 185 | * Correction of a word. ([d6655c7](https://github.com/maximegris/angular-electron/commit/d6655c7)) 186 | * feat/ add webview directive ([e1b5600](https://github.com/maximegris/angular-electron/commit/e1b5600)) 187 | * migrate Angular to 5.2.0 ([b8cf343](https://github.com/maximegris/angular-electron/commit/b8cf343)) 188 | * ref/ Remove sponsor ([2a28239](https://github.com/maximegris/angular-electron/commit/2a28239)) 189 | * ref/ update angular & dep ([e3b1fab](https://github.com/maximegris/angular-electron/commit/e3b1fab)) 190 | * ref/ upgrade electron (security issue) ([f6a0c4e](https://github.com/maximegris/angular-electron/commit/f6a0c4e)) 191 | * version bump + logo resize ([3545d16](https://github.com/maximegris/angular-electron/commit/3545d16)) 192 | * fix: fixes maximegris/angular-electron#118 ([6d21e69](https://github.com/maximegris/angular-electron/commit/6d21e69)), closes [maximegris/angular-electron#118](https://github.com/maximegris/angular-electron/issues/118) 193 | * fix: fixes maximegris/angular-electron#98 ([136344b](https://github.com/maximegris/angular-electron/commit/136344b)), closes [maximegris/angular-electron#98](https://github.com/maximegris/angular-electron/issues/98) 194 | 195 | 196 | 197 | ## 2.4.1 (2017-12-14) 198 | 199 | * fix/ Manage icons for linux binary generation ([ccd0601](https://github.com/maximegris/angular-electron/commit/ccd0601)) 200 | * version 2.4.1 ([5fcfca0](https://github.com/maximegris/angular-electron/commit/5fcfca0)) 201 | 202 | 203 | 204 | ## 2.4.0 (2017-12-08) 205 | 206 | * version 2.4.0 ([0437b33](https://github.com/maximegris/angular-electron/commit/0437b33)) 207 | 208 | 209 | 210 | ## 2.3.0 (2017-12-04) 211 | 212 | * add ngx translate ([facda37](https://github.com/maximegris/angular-electron/commit/facda37)) 213 | * Use HttpClientModule ([5704e2e](https://github.com/maximegris/angular-electron/commit/5704e2e)) 214 | 215 | 216 | 217 | ## 2.2.0 (2017-11-28) 218 | 219 | * Brought back scripts defined in webpack.config.js ([441da3d](https://github.com/maximegris/angular-electron/commit/441da3d)) 220 | * migrate to Angular 5.0.3 ([f4bc5b2](https://github.com/maximegris/angular-electron/commit/f4bc5b2)) 221 | * Update LICENSE badge ([fa783aa](https://github.com/maximegris/angular-electron/commit/fa783aa)) 222 | * Update to electron-builder ([0e94b52](https://github.com/maximegris/angular-electron/commit/0e94b52)) 223 | 224 | 225 | 226 | ## 2.1.1 (2017-11-19) 227 | 228 | * Move codesponsor ([064be4c](https://github.com/maximegris/angular-electron/commit/064be4c)) 229 | 230 | 231 | 232 | ## 2.1.0 (2017-11-19) 233 | 234 | * Add codesponsor ([87e695d](https://github.com/maximegris/angular-electron/commit/87e695d)) 235 | * Add script for winportable ([2be2dae](https://github.com/maximegris/angular-electron/commit/2be2dae)) 236 | * Add support for building a Windows self-contained executable ([7cfa790](https://github.com/maximegris/angular-electron/commit/7cfa790)) 237 | * fix/ electron-packager need favicon >= 256x256 on Windows ([d2c253f](https://github.com/maximegris/angular-electron/commit/d2c253f)) 238 | * fix/ refact webpack config (inspired by ng eject Angular 5) ([d1c30ac](https://github.com/maximegris/angular-electron/commit/d1c30ac)) 239 | * fix/ replace aotPlugin in no prod mode ([a0caf1e](https://github.com/maximegris/angular-electron/commit/a0caf1e)) 240 | * fix/ Replace AotPlugin to AngularCompilerPlugin ([bef106e](https://github.com/maximegris/angular-electron/commit/bef106e)) 241 | * fix/ Update README Angular 5 ([93c6949](https://github.com/maximegris/angular-electron/commit/93c6949)) 242 | * fix/ webpack template path ([518b66b](https://github.com/maximegris/angular-electron/commit/518b66b)) 243 | * Mgrate to Angular 5.0.2 ([bd7bed6](https://github.com/maximegris/angular-electron/commit/bd7bed6)) 244 | * Update package.json ([b16cf73](https://github.com/maximegris/angular-electron/commit/b16cf73)) 245 | * Version 2.1.0 ([fccef2f](https://github.com/maximegris/angular-electron/commit/fccef2f)) 246 | 247 | 248 | 249 | ## 2.0.0 (2017-11-13) 250 | 251 | * Add buffer to externals ([7e797f0](https://github.com/maximegris/angular-electron/commit/7e797f0)) 252 | * Edit a typo on README ([956a2bc](https://github.com/maximegris/angular-electron/commit/956a2bc)) 253 | * Fix #55 removed bootstraps.css which for example purpose before. ([41445eb](https://github.com/maximegris/angular-electron/commit/41445eb)), closes [#55](https://github.com/maximegris/angular-electron/issues/55) 254 | * License MIT ([73494b7](https://github.com/maximegris/angular-electron/commit/73494b7)) 255 | * Migrate to Angular 5 ([3a3ffe1](https://github.com/maximegris/angular-electron/commit/3a3ffe1)) 256 | 257 | 258 | 259 | ## 1.9.0 (2017-09-22) 260 | 261 | * feat/ launch electron & webpack in // (npm run start) ([8c37cc4](https://github.com/maximegris/angular-electron/commit/8c37cc4)) 262 | * ref/ Exclude node_modules (tslint) ([412a0a5](https://github.com/maximegris/angular-electron/commit/412a0a5)) 263 | 264 | 265 | 266 | ## 1.8.1 (2017-09-22) 267 | 268 | * Fix #55 , and also added functionality for scripts global building ([012a894](https://github.com/maximegris/angular-electron/commit/012a894)), closes [#55](https://github.com/maximegris/angular-electron/issues/55) 269 | * ref/ add package-lock in gitignore ([4edd98d](https://github.com/maximegris/angular-electron/commit/4edd98d)) 270 | * remove package-lock ([8e98627](https://github.com/maximegris/angular-electron/commit/8e98627)) 271 | * upgrade angular version 4.4.3 ([10d0f87](https://github.com/maximegris/angular-electron/commit/10d0f87)) 272 | * version 1.8.1 ([70879d1](https://github.com/maximegris/angular-electron/commit/70879d1)) 273 | 274 | 275 | 276 | ## 1.8.0 (2017-09-09) 277 | 278 | * upgrade lib version ([2ac2aa0](https://github.com/maximegris/angular-electron/commit/2ac2aa0)) 279 | 280 | 281 | 282 | ## 1.7.0 (2017-08-18) 283 | 284 | * ref/ Update Angular (4.3.5) / Electron (1.7.2) / Electron Packager (8.7.2) / Typescript (2.5.0) ([f97cd81](https://github.com/maximegris/angular-electron/commit/f97cd81)) 285 | 286 | 287 | 288 | ## 1.6.1 (2017-07-27) 289 | 290 | * fix/ angular-cli error in prod compilation with aot ([c26a5ae](https://github.com/maximegris/angular-electron/commit/c26a5ae)) 291 | * version 1.6.1 ([899babd](https://github.com/maximegris/angular-electron/commit/899babd)) 292 | 293 | 294 | 295 | ## 1.6.0 (2017-07-16) 296 | 297 | * ajout package-lock npm v5 ([09c0840](https://github.com/maximegris/angular-electron/commit/09c0840)) 298 | * Change background img ([7e58717](https://github.com/maximegris/angular-electron/commit/7e58717)) 299 | * Fix npm run build:prod ([c23bade](https://github.com/maximegris/angular-electron/commit/c23bade)) 300 | * fix/ Bindings not updating automatically #44 ([2a90191](https://github.com/maximegris/angular-electron/commit/2a90191)), closes [#44](https://github.com/maximegris/angular-electron/issues/44) 301 | * fix/ e2e test with jasmine2 ([9c51f32](https://github.com/maximegris/angular-electron/commit/9c51f32)) 302 | * fix/ typescript issues ([bb0a6ab](https://github.com/maximegris/angular-electron/commit/bb0a6ab)) 303 | * increment version deps ([bde452c](https://github.com/maximegris/angular-electron/commit/bde452c)) 304 | * Revert last pull request - break production compilation ([ccc9064](https://github.com/maximegris/angular-electron/commit/ccc9064)) 305 | * upgrade angular version to 4.3.0 ([ab16959](https://github.com/maximegris/angular-electron/commit/ab16959)) 306 | 307 | 308 | 309 | ## 1.5.0 (2017-06-10) 310 | 311 | * fix/ karma Unit test ([ea13d6d](https://github.com/maximegris/angular-electron/commit/ea13d6d)) 312 | * fix/ remove yarn because of error with module dep in prod builds ([8a49a45](https://github.com/maximegris/angular-electron/commit/8a49a45)) 313 | * update yarn lock ([18c0e62](https://github.com/maximegris/angular-electron/commit/18c0e62)) 314 | 315 | 316 | 317 | ## 1.4.4 (2017-06-08) 318 | 319 | * fix/ Fix npm run lint ([db7972a](https://github.com/maximegris/angular-electron/commit/db7972a)) 320 | * ref/ electron ./dist more generic ([7e71add](https://github.com/maximegris/angular-electron/commit/7e71add)) 321 | * Replace const icon to let icon ([dadf65f](https://github.com/maximegris/angular-electron/commit/dadf65f)) 322 | 323 | 324 | 325 | ## 1.4.3 (2017-06-06) 326 | 327 | * fix/ favicon path during packaging ([aa2b012](https://github.com/maximegris/angular-electron/commit/aa2b012)) 328 | * remove build node 8 till node-sass failed ([34f201d](https://github.com/maximegris/angular-electron/commit/34f201d)) 329 | * v1.4.3 ([4961fb0](https://github.com/maximegris/angular-electron/commit/4961fb0)) 330 | 331 | 332 | 333 | ## 1.4.2 (2017-05-31) 334 | 335 | * Change dep versions ([62d08d3](https://github.com/maximegris/angular-electron/commit/62d08d3)) 336 | * install npm dep when building ([56948d0](https://github.com/maximegris/angular-electron/commit/56948d0)) 337 | * Minor update ([5f282b7](https://github.com/maximegris/angular-electron/commit/5f282b7)) 338 | * No hot reload in browser ([7892f0d](https://github.com/maximegris/angular-electron/commit/7892f0d)) 339 | * update Electron v1.6.10 ([f2f2080](https://github.com/maximegris/angular-electron/commit/f2f2080)) 340 | * upgrade ng/electron dependencies ([78b0f27](https://github.com/maximegris/angular-electron/commit/78b0f27)) 341 | * chore(package): bump dependencies ([b62c7b6](https://github.com/maximegris/angular-electron/commit/b62c7b6)) 342 | 343 | 344 | 345 | ## 1.4.0 (2017-05-23) 346 | 347 | * 1.4.0 ([23213c4](https://github.com/maximegris/angular-electron/commit/23213c4)) 348 | * Change style home page ([93dcc52](https://github.com/maximegris/angular-electron/commit/93dcc52)) 349 | * Fixed compiler warnings ([fca6b15](https://github.com/maximegris/angular-electron/commit/fca6b15)) 350 | * ref/ electron main from js to ts ([835d32b](https://github.com/maximegris/angular-electron/commit/835d32b)) 351 | * Remove caret & tilde ([dd98155](https://github.com/maximegris/angular-electron/commit/dd98155)) 352 | 353 | 354 | 355 | ## 1.3.5 (2017-05-18) 356 | 357 | * Add new tags ([cd07a86](https://github.com/maximegris/angular-electron/commit/cd07a86)) 358 | * v 1.3.5 ([d528a71](https://github.com/maximegris/angular-electron/commit/d528a71)) 359 | 360 | 361 | 362 | ## 1.3.4 (2017-05-12) 363 | 364 | * feat/ add nodejs native lib in webpack config ([27d9bc6](https://github.com/maximegris/angular-electron/commit/27d9bc6)) 365 | * Fix issue #15 ([d77cbf1](https://github.com/maximegris/angular-electron/commit/d77cbf1)), closes [#15](https://github.com/maximegris/angular-electron/issues/15) 366 | * Ref/ Electron packager in external file ([17b04e8](https://github.com/maximegris/angular-electron/commit/17b04e8)) 367 | * version 1.3.4 ([374af16](https://github.com/maximegris/angular-electron/commit/374af16)) 368 | 369 | 370 | 371 | ## 1.3.3 (2017-05-10) 372 | 373 | * Chapters order ([a772b9c](https://github.com/maximegris/angular-electron/commit/a772b9c)) 374 | * Chapters order ([06547e5](https://github.com/maximegris/angular-electron/commit/06547e5)) 375 | * Delete spec file of electron.service ([083498e](https://github.com/maximegris/angular-electron/commit/083498e)) 376 | * Fix issue #15 ([e7cd6e6](https://github.com/maximegris/angular-electron/commit/e7cd6e6)), closes [#15](https://github.com/maximegris/angular-electron/issues/15) 377 | * Move Browser mode chapter ([8818750](https://github.com/maximegris/angular-electron/commit/8818750)) 378 | * Version 1.3.3 ([f4db75b](https://github.com/maximegris/angular-electron/commit/f4db75b)) 379 | 380 | 381 | 382 | ## 1.3.2 (2017-05-05) 383 | 384 | * Add comments of how conditional import works ([e6c1b3b](https://github.com/maximegris/angular-electron/commit/e6c1b3b)) 385 | * Conditional import of Electron/NodeJS libs - The app can be launch in browser mode ([c434f8a](https://github.com/maximegris/angular-electron/commit/c434f8a)) 386 | * Fix indentation ([6a9836a](https://github.com/maximegris/angular-electron/commit/6a9836a)) 387 | * Fix prepree2e script ([b2af4fd](https://github.com/maximegris/angular-electron/commit/b2af4fd)) 388 | * Set e2e tests ([d223974](https://github.com/maximegris/angular-electron/commit/d223974)) 389 | * Suround electron browser by try/catch ([88be472](https://github.com/maximegris/angular-electron/commit/88be472)) 390 | * Update @types/node ([9d43304](https://github.com/maximegris/angular-electron/commit/9d43304)) 391 | * Update readme with e2e info ([01bbf13](https://github.com/maximegris/angular-electron/commit/01bbf13)) 392 | * update version ([0849a0a](https://github.com/maximegris/angular-electron/commit/0849a0a)) 393 | 394 | 395 | 396 | ## 1.3.1 (2017-05-05) 397 | 398 | * Add routing module ([7334ce8](https://github.com/maximegris/angular-electron/commit/7334ce8)) 399 | * Fixed hardcoded path in glob copy, blocking assets after eject ([815d519](https://github.com/maximegris/angular-electron/commit/815d519)) 400 | * update comments in dev/prod env files ([7cf6a51](https://github.com/maximegris/angular-electron/commit/7cf6a51)) 401 | * Version 1.3.1 ([f18ac77](https://github.com/maximegris/angular-electron/commit/f18ac77)) 402 | 403 | 404 | 405 | ## 1.3.0 (2017-05-01) 406 | 407 | * Fix webpack prod/dev env ([8549da1](https://github.com/maximegris/angular-electron/commit/8549da1)) 408 | 409 | 410 | 411 | ## 1.2.1 (2017-04-30) 412 | 413 | * allowJs ([4efd188](https://github.com/maximegris/angular-electron/commit/4efd188)) 414 | * Example url background in scss ([3705a35](https://github.com/maximegris/angular-electron/commit/3705a35)) 415 | * Fix electron build (extract-zip workaround) ([a7ee90e](https://github.com/maximegris/angular-electron/commit/a7ee90e)) 416 | * Fix webpack config url in css ([cea4be5](https://github.com/maximegris/angular-electron/commit/cea4be5)) 417 | * html loader ([c55558a](https://github.com/maximegris/angular-electron/commit/c55558a)) 418 | * update version 1.2.1 ([78e8da7](https://github.com/maximegris/angular-electron/commit/78e8da7)) 419 | 420 | 421 | 422 | ## 1.2.0 (2017-04-19) 423 | 424 | * Set one example of css class in app component ([a15775f](https://github.com/maximegris/angular-electron/commit/a15775f)) 425 | * Update npm dependencies ([0a93ebe](https://github.com/maximegris/angular-electron/commit/0a93ebe)) 426 | 427 | 428 | 429 | ## 1.1.2 (2017-04-18) 430 | 431 | * Fix typo & fix script electron:mac ([bd06859](https://github.com/maximegris/angular-electron/commit/bd06859)) 432 | * Set theme jekyll-theme-architect ([644d857](https://github.com/maximegris/angular-electron/commit/644d857)) 433 | * update README ([97fa63d](https://github.com/maximegris/angular-electron/commit/97fa63d)) 434 | * update README ([23fc0a9](https://github.com/maximegris/angular-electron/commit/23fc0a9)) 435 | * update README ([a8dcf6a](https://github.com/maximegris/angular-electron/commit/a8dcf6a)) 436 | * v1.1.2 ([e29e467](https://github.com/maximegris/angular-electron/commit/e29e467)) 437 | 438 | 439 | 440 | ## 1.1.1 (2017-04-12) 441 | 442 | * Fix webpack.config file path (travisci) ([a172df9](https://github.com/maximegris/angular-electron/commit/a172df9)) 443 | * live reload on disk ([7bb2f8b](https://github.com/maximegris/angular-electron/commit/7bb2f8b)) 444 | * Remove unused dependency (webpack-dev-server) ([e9150f4](https://github.com/maximegris/angular-electron/commit/e9150f4)) 445 | 446 | 447 | 448 | ## 1.1.0 (2017-04-12) 449 | 450 | * add depdencies CI & Licence ([6ceb0f2](https://github.com/maximegris/angular-electron/commit/6ceb0f2)) 451 | * Override webpack configuration ([60d6116](https://github.com/maximegris/angular-electron/commit/60d6116)) 452 | 453 | 454 | 455 | ## 1.0.3 (2017-04-07) 456 | 457 | * Add TravisCI ([e5640fd](https://github.com/maximegris/angular-electron/commit/e5640fd)) 458 | * v1.0.3 ([9866d53](https://github.com/maximegris/angular-electron/commit/9866d53)) 459 | 460 | 461 | 462 | ## 1.0.2 (2017-04-07) 463 | 464 | * Add TravisCI ([ef4b80e](https://github.com/maximegris/angular-electron/commit/ef4b80e)) 465 | * Fix typo ([f964c3f](https://github.com/maximegris/angular-electron/commit/f964c3f)) 466 | * Fix typo ([e42bb5e](https://github.com/maximegris/angular-electron/commit/e42bb5e)) 467 | * Update README ([3bb45b3](https://github.com/maximegris/angular-electron/commit/3bb45b3)) 468 | * Update README with angular-cli doc ([5a57578](https://github.com/maximegris/angular-electron/commit/5a57578)) 469 | * v1.0.2 ([1bd8e0e](https://github.com/maximegris/angular-electron/commit/1bd8e0e)) 470 | 471 | 472 | 473 | ## 1.0.1 (2017-04-03) 474 | 475 | * feat/ Add electron-packager scripts ([57891dc](https://github.com/maximegris/angular-electron/commit/57891dc)) 476 | * ref/ update README ([7fddc20](https://github.com/maximegris/angular-electron/commit/7fddc20)) 477 | * update README ([9a983c1](https://github.com/maximegris/angular-electron/commit/9a983c1)) 478 | * v1.0.0 ([7a21eb9](https://github.com/maximegris/angular-electron/commit/7a21eb9)) 479 | * v1.0.1 ([68275a3](https://github.com/maximegris/angular-electron/commit/68275a3)) 480 | * chore: initial commit from @angular/cli ([616a69e](https://github.com/maximegris/angular-electron/commit/616a69e)) 481 | 482 | 483 | 484 | --------------------------------------------------------------------------------