v --
49 |--
50 |Release Note:
51 |├── .editorconfig ├── .gitignore ├── LICENSE ├── LICENSE.md ├── README.md ├── _config.yml ├── angular.json ├── common ├── ipc-channels.ts ├── models │ └── updateCheckResult.interface.ts └── utils.ts ├── dev-app-update.yml ├── e2e ├── app.e2e-spec.ts ├── app.po.ts ├── protractor.conf.js └── tsconfig.e2e.json ├── electron-builder.json ├── hexo-note-image-save-image.png ├── hexo-note-image.png ├── hexo-note-logo.svg ├── logo-angular.jpg ├── logo-electron.jpg ├── main.ts ├── main ├── autoUpdater.ts ├── menu.ts └── utils.ts ├── package.json ├── postcss.config.js ├── postinstall-web.js ├── postinstall.js ├── renderer ├── update-progress.html └── update-window.html ├── src ├── app │ ├── Models │ │ ├── Article.interface.ts │ │ ├── Article.ts │ │ ├── Category.interface.ts │ │ ├── Config.Interface.ts │ │ ├── Post.interface.ts │ │ └── Tag.interface.ts │ ├── app-routing.module.ts │ ├── app.component.html │ ├── app.component.scss │ ├── app.component.spec.ts │ ├── app.component.ts │ ├── app.module.ts │ ├── components │ │ ├── article-list-item │ │ │ ├── article-list-item.component.html │ │ │ ├── article-list-item.component.scss │ │ │ ├── article-list-item.component.spec.ts │ │ │ └── article-list-item.component.ts │ │ ├── article-md-editor │ │ │ ├── article-md-editor.component.html │ │ │ ├── article-md-editor.component.scss │ │ │ ├── article-md-editor.component.spec.ts │ │ │ └── article-md-editor.component.ts │ │ ├── custom-md-editor │ │ │ ├── custom-md-editor.component.html │ │ │ ├── custom-md-editor.component.scss │ │ │ ├── custom-md-editor.component.spec.ts │ │ │ └── custom-md-editor.component.ts │ │ ├── new-article-form │ │ │ ├── new-article-form.component.html │ │ │ ├── new-article-form.component.scss │ │ │ ├── new-article-form.component.spec.ts │ │ │ └── new-article-form.component.ts │ │ ├── new-blog-modal │ │ │ ├── new-blog-modal.component.html │ │ │ ├── new-blog-modal.component.scss │ │ │ ├── new-blog-modal.component.spec.ts │ │ │ └── new-blog-modal.component.ts │ │ ├── rename-article-modal │ │ │ ├── rename-article-modal.component.html │ │ │ ├── rename-article-modal.component.scss │ │ │ ├── rename-article-modal.component.spec.ts │ │ │ └── rename-article-modal.component.ts │ │ ├── save-article-image-modal │ │ │ ├── save-article-image-modal.component.html │ │ │ ├── save-article-image-modal.component.scss │ │ │ ├── save-article-image-modal.component.spec.ts │ │ │ └── save-article-image-modal.component.ts │ │ └── sidebar │ │ │ ├── sidebar.component.html │ │ │ ├── sidebar.component.scss │ │ │ ├── sidebar.component.spec.ts │ │ │ └── sidebar.component.ts │ ├── directives │ │ └── webview.directive.ts │ ├── guard │ │ ├── app-init.guard.spec.ts │ │ ├── app-init.guard.ts │ │ ├── can-deactivate.guard.spec.ts │ │ ├── can-deactivate.guard.ts │ │ ├── config-init.guard.spec.ts │ │ ├── config-init.guard.ts │ │ ├── hexo-init.guard.spec.ts │ │ └── hexo-init.guard.ts │ ├── pages │ │ ├── dashboard │ │ │ ├── article │ │ │ │ ├── article-detail │ │ │ │ │ ├── article-detail.component.html │ │ │ │ │ ├── article-detail.component.scss │ │ │ │ │ ├── article-detail.component.spec.ts │ │ │ │ │ └── article-detail.component.ts │ │ │ │ ├── article.component.html │ │ │ │ ├── article.component.scss │ │ │ │ ├── article.component.spec.ts │ │ │ │ └── article.component.ts │ │ │ ├── dashboard.component.html │ │ │ ├── dashboard.component.scss │ │ │ ├── dashboard.component.spec.ts │ │ │ ├── dashboard.component.ts │ │ │ └── settings │ │ │ │ ├── settings.component.html │ │ │ │ ├── settings.component.scss │ │ │ │ ├── settings.component.spec.ts │ │ │ │ └── settings.component.ts │ │ └── not-project-found │ │ │ ├── not-project-found.component.html │ │ │ ├── not-project-found.component.scss │ │ │ ├── not-project-found.component.spec.ts │ │ │ └── not-project-found.component.ts │ └── services │ │ ├── article.service.spec.ts │ │ ├── article.service.ts │ │ ├── asset.service.spec.ts │ │ ├── asset.service.ts │ │ ├── config.service.spec.ts │ │ ├── config.service.ts │ │ ├── electron.service.ts │ │ ├── hexo.service.spec.ts │ │ ├── hexo.service.ts │ │ ├── scaffold.service.spec.ts │ │ ├── scaffold.service.ts │ │ ├── server.service.spec.ts │ │ ├── server.service.ts │ │ ├── system-settings.service.spec.ts │ │ ├── system-settings.service.ts │ │ ├── utils.service.spec.ts │ │ └── utils.service.ts ├── assets │ ├── .gitkeep │ ├── background.jpg │ ├── hexo-logo.svg │ ├── hexo-note-logo.svg │ └── i18n │ │ └── en.json ├── environments │ ├── environment.common.ts │ ├── environment.dev.ts │ ├── environment.prod.ts │ └── environment.ts ├── favicon.256x256.png ├── favicon.512x512.png ├── favicon.icns ├── favicon.ico ├── favicon.png ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills-test.ts ├── polyfills.ts ├── style │ ├── _color.scss │ ├── _index.scss │ ├── _size.scss │ └── _spacing.scss ├── styles.scss ├── test.ts ├── theme.less ├── tsconfig.app.json ├── tsconfig.spec.json └── typings.d.ts ├── tsconfig-serve.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /app-builds 8 | /release 9 | main.js 10 | src/**/*.js 11 | *.js.map 12 | /main/**/*.js 13 | /common/**/*.js 14 | 15 | # dependencies 16 | /node_modules 17 | 18 | # IDEs and editors 19 | /.idea 20 | .project 21 | .classpath 22 | .c9/ 23 | *.launch 24 | .settings/ 25 | *.sublime-workspace 26 | 27 | # IDE - VSCode 28 | .vscode/* 29 | !.vscode/settings.json 30 | !.vscode/tasks.json 31 | !.vscode/launch.json 32 | !.vscode/extensions.json 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | testem.log 41 | /typings 42 | package-lock.json 43 | 44 | # e2e 45 | /e2e/*.js 46 | !/e2e/protractor.conf.js 47 | /e2e/*.map 48 | 49 | # System Files 50 | .DS_Store 51 | Thumbs.db 52 | 53 | /private 54 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hexo-Note 2 | 3 | A Hexojs Client project 4 | 5 | hexojs 客户端 6 | 7 | ## Highlights / 特点 8 | 9 |  10 | 11 | You Can Save Image!!! 12 | 13 | 可以保存图片!!! 14 |  15 | 16 | ## Installation / 安装 17 | 18 | Windows, Mac and AppImage binaries are available in the [Releases / 下载](https://github.com/tmirun/Hexo-Note/releases) 19 | 20 | Or you can also install from repo, 21 | 1. Clone this project to a local folder / 下载项目到本地 22 | 2. Run `npm start` / 打开执行 `npm start` 23 | 3. More scripts are available in [package.json](package.json) / 更多命令看 [package.json](package.json) 24 | 25 | ## Prerequisites / 安装需求 26 | 27 | - Hexo, see the [installation guide](https://hexo.io/docs/) / 请看 [安装教程](https://hexo.io/zh-cn/docs/) 28 | - At least a blog post, see the [writing guide](https://hexo.io/docs/writing) / 创建至少一篇文章,请看 [写作教程](https://hexo.io/zh-cn/docs/writing) 29 | 30 | ## Tech stack / 在这项目中使用了: 31 | - Framework / 框架: [angular6 + electron](https://github.com/maximegris/angular-electron) 32 | - UI / 设计: [ng-zorro ant design](https://github.com/NG-ZORRO/ng-zorro-antd) 33 | - Customize the theme in in `src/theme.less` / 你可以在 `src/theme.less` 自定义主题 34 | - Icon / 图标: [font awesome](https://fontawesome.com/icons?from=io) 35 | - Editor / 写作框: [code mirror](https://codemirror.net/) 36 | 37 | ## Architecture / 软件框架图 38 | TODO 39 | 40 | ## Feedback 41 | 42 | If you have any opinion or suggestion for improvement, please raise an [Issue](https://github.com/tmirun/Hexo-Note/issues) and we will discuss it together. 43 | 44 | You can write it with English, Spanish or Chinese. 45 | 46 | 如果你有什么想法 意见 或者 改善的地方 可以直接写到 [Issue](https://github.com/tmirun/Hexo-Note/issues) 里,我们来一起讨论. 47 | 48 | This documentation is work in progress, if you found any mistake, tell me please. Thanks! 49 | 50 | ## Contribute / 开发: 51 | 52 | Contact me at tmirun@hotmail.com if you wish to develop this program with me. 53 | 54 | 如果哪位同学用兴趣一起完善这个项目,请联系我 tmirun@hotmail.com 55 | 56 | ## TODO LIST 57 | 公开 trello [地址](https://trello.com/b/F20B7ufQ) 58 | 59 | * [x] 获取 hexo 当地地址 DONE 60 | * [x] 获取文章(区分草稿和已发布) DONE 61 | * [x] 新增文章 DONE 62 | * [x] 编辑文章 DONE 63 | * [x] 删除文章 DONE 64 | * [ ] 强化 mk 编译器, 65 | * [x] 添加 toolbar DONE 66 | * [ ] 可自定义 toolbar 67 | * [x] 可以显示本地文章图片(用{% %}方法加的) DONE 68 | * [x] 添加 Read More DONE 69 | * [x] 黏贴 imagen: 在 post asset 自动创建如果打开的话 70 | * [x] 打开文章的图片文件 71 | * [ ] 分类 72 | * [ ] Tag 73 | * [ ] 搜索文章 74 | * [x] 标题 DONE 75 | * [ ] 按分类 76 | * [ ] 按 Tag 77 | * [x] 热键 78 | * [x] 保存 cmd + s / ctrl + s, 79 | * [x] 黑体 cmd + b / ctrl + b, 80 | * [x] italic cmd + i / ctrl + i, 81 | * [x] h1-h6 cmd + [1-6] / ctrl + [1-6], 82 | * [x] 启动 HEXO 服务器 DONE 83 | * [x] 软件偏好设置 -- yml DONE 84 | * [x] 一键编译、发布博客 DONE 85 | * [x] 预览博客 DONE 86 | * [ ] 操作日志记录 87 | * [x] 将文章保存为草稿 DONE 88 | * [ ] 自动保存文章 89 | * [ ] 多语言 90 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-architect -------------------------------------------------------------------------------- /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 | { 27 | "glob": "**/*", 28 | "input": "./node_modules/@ant-design/icons-angular/src/inline-svg/", 29 | "output": "/assets/" 30 | } 31 | ], 32 | "styles": [ 33 | "src/theme.less", 34 | "src/styles.scss", 35 | "node_modules/prismjs/themes/prism-okaidia.css", 36 | "node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss", 37 | "node_modules/@fortawesome/fontawesome-free/scss/solid.scss", 38 | "node_modules/@fortawesome/fontawesome-free/scss/brands.scss" 39 | ], 40 | "scripts": [ 41 | "node_modules/prismjs/prism.js", 42 | "node_modules/marked/lib/marked.js" 43 | ] 44 | }, 45 | "configurations": { 46 | "dev": { 47 | "optimization": false, 48 | "outputHashing": "all", 49 | "sourceMap": true, 50 | "extractCss": true, 51 | "namedChunks": false, 52 | "aot": false, 53 | "extractLicenses": true, 54 | "vendorChunk": false, 55 | "buildOptimizer": false, 56 | "fileReplacements": [ 57 | { 58 | "replace": "src/environments/environment.ts", 59 | "with": "src/environments/environment.dev.ts" 60 | } 61 | ] 62 | }, 63 | "production": { 64 | "optimization": true, 65 | "outputHashing": "all", 66 | "sourceMap": false, 67 | "extractCss": true, 68 | "namedChunks": false, 69 | "aot": true, 70 | "extractLicenses": true, 71 | "vendorChunk": false, 72 | "buildOptimizer": true, 73 | "fileReplacements": [ 74 | { 75 | "replace": "src/environments/environment.ts", 76 | "with": "src/environments/environment.prod.ts" 77 | } 78 | ] 79 | } 80 | } 81 | }, 82 | "serve": { 83 | "builder": "@angular-devkit/build-angular:dev-server", 84 | "options": { 85 | "browserTarget": "angular-electron:build" 86 | }, 87 | "configurations": { 88 | "dev": { 89 | "browserTarget": "angular-electron:build:dev" 90 | }, 91 | "production": { 92 | "browserTarget": "angular-electron:build:production" 93 | } 94 | } 95 | }, 96 | "extract-i18n": { 97 | "builder": "@angular-devkit/build-angular:extract-i18n", 98 | "options": { 99 | "browserTarget": "angular-electron:build" 100 | } 101 | }, 102 | "test": { 103 | "builder": "@angular-devkit/build-angular:karma", 104 | "options": { 105 | "main": "src/test.ts", 106 | "polyfills": "src/polyfills-test.ts", 107 | "tsConfig": "src/tsconfig.spec.json", 108 | "karmaConfig": "src/karma.conf.js", 109 | "assets": [ 110 | "src/assets", 111 | "src/favicon.ico", 112 | "src/favicon.png", 113 | "src/favicon.icns", 114 | "src/favicon.256x256.png", 115 | "src/favicon.512x512.png" 116 | ], 117 | "styles": [ 118 | "src/theme.less", 119 | "src/styles.scss", 120 | "node_modules/prismjs/themes/prism-okaidia.css", 121 | "node_modules/@fortawesome/fontawesome-free/scss/fontawesome.scss", 122 | "node_modules/@fortawesome/fontawesome-free/scss/solid.scss", 123 | "node_modules/@fortawesome/fontawesome-free/scss/brands.scss" 124 | ], 125 | "scripts": [ 126 | "node_modules/prismjs/prism.js", 127 | "node_modules/marked/lib/marked.js" 128 | ] 129 | } 130 | }, 131 | "lint": { 132 | "builder": "@angular-devkit/build-angular:tslint", 133 | "options": { 134 | "tsConfig": [ 135 | "src/tsconfig.app.json", 136 | "src/tsconfig.spec.json" 137 | ], 138 | "exclude": [ 139 | "**/node_modules/**" 140 | ] 141 | } 142 | } 143 | } 144 | }, 145 | "angular-electron-e2e": { 146 | "root": "e2e", 147 | "projectType": "application", 148 | "architect": { 149 | "e2e": { 150 | "builder": "@angular-devkit/build-angular:protractor", 151 | "options": { 152 | "protractorConfig": "e2e/protractor.conf.js", 153 | "devServerTarget": "angular-electron:serve" 154 | } 155 | }, 156 | "lint": { 157 | "builder": "@angular-devkit/build-angular:tslint", 158 | "options": { 159 | "tsConfig": [ 160 | "e2e/tsconfig.e2e.json" 161 | ], 162 | "exclude": [ 163 | "**/node_modules/**" 164 | ] 165 | } 166 | } 167 | } 168 | } 169 | }, 170 | "defaultProject": "angular-electron", 171 | "schematics": { 172 | "@schematics/angular:component": { 173 | "prefix": "app", 174 | "styleext": "scss" 175 | }, 176 | "@schematics/angular:directive": { 177 | "prefix": "app" 178 | } 179 | } 180 | } -------------------------------------------------------------------------------- /common/ipc-channels.ts: -------------------------------------------------------------------------------- 1 | export const IPC_CHANNELS = { 2 | AUTO_UPLOAD_DOWNLOAD_PROGRESS: 'auto-upload-download-progress', 3 | AUTO_UPLOAD_ACCEPT: 'auto-upload-accept' 4 | }; 5 | -------------------------------------------------------------------------------- /common/models/updateCheckResult.interface.ts: -------------------------------------------------------------------------------- 1 | export interface UpdateCheckResult { 2 | version: string; 3 | files: any[]; 4 | path: string; 5 | sha512: string; 6 | releaseDate: string; 7 | releaseName: string; 8 | releaseNotes: string; 9 | } 10 | -------------------------------------------------------------------------------- /common/utils.ts: -------------------------------------------------------------------------------- 1 | import isDev from 'electron-is-dev'; 2 | 3 | export const utils = { 4 | isDev() { return isDev; }, 5 | 6 | isPro() { return !this.isDev(); } 7 | }; 8 | -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | owner: tmirun 2 | repo: Hexo-Note 3 | provider: github 4 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AngularElectronPage } from './app.po'; 2 | import { browser, element, by } from 'protractor'; 3 | 4 | describe('angular-electron App', () => { 5 | let page: AngularElectronPage; 6 | 7 | beforeEach(() => { 8 | page = new AngularElectronPage(); 9 | }); 10 | 11 | it('should display message saying App works !', () => { 12 | page.navigateTo('/'); 13 | expect(element(by.css('app-home h1')).getText()).toMatch('App works !'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | /* tslint:disable */ 4 | export class AngularElectronPage { 5 | navigateTo(route: string) { 6 | return browser.get(route); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 25000, 8 | delayBrowserTimeInSeconds: 0, 9 | specs: [ 10 | './**/*.e2e-spec.ts' 11 | ], 12 | capabilities: { 13 | 'browserName': 'chrome', 14 | chromeOptions: { 15 | args: ["--no-sandbox", "--headless", "--disable-gpu"] 16 | } 17 | }, 18 | chromeOnly: true, 19 | directConnect: true, 20 | baseUrl: 'http://localhost:4200/', 21 | framework: 'jasmine2', 22 | jasmineNodeOpts: { 23 | showColors: true, 24 | defaultTimeoutInterval: 30000, 25 | print: function () { }, 26 | realtimeFailure: true 27 | }, 28 | useAllAngular2AppRoots: true, 29 | beforeLaunch: function () { 30 | require('ts-node').register({ 31 | project: 'e2e/tsconfig.e2e.json' 32 | }); 33 | }, 34 | onPrepare() { 35 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 36 | } 37 | }; 38 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /electron-builder.json: -------------------------------------------------------------------------------- 1 | { 2 | "productName": "Hexo Note", 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-cli.json", 17 | "!_config.yml", 18 | "!karma.conf.js", 19 | "!tsconfig.json", 20 | "!tslint.json", 21 | "!private/" 22 | ], 23 | "win": { 24 | "publish": ["github"], 25 | "icon": "dist", 26 | "certificateFile": "private/hexo-note.p12", 27 | "verifyUpdateCodeSignature": false, 28 | "target": [ 29 | "nsis" 30 | ] 31 | }, 32 | "mac": { 33 | "publish": ["github"], 34 | "icon": "dist", 35 | "category": "public.app-category.productivity", 36 | "target": [ 37 | "dmg", 38 | "zip" 39 | ] 40 | }, 41 | "linux": { 42 | "publish": ["github"], 43 | "icon": "dist", 44 | "category": "Office", 45 | "target": [ 46 | "AppImage" 47 | ] 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /hexo-note-image-save-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmirun/Hexo-Note/bb54e4039bd583fa528099f72916c840c7573914/hexo-note-image-save-image.png -------------------------------------------------------------------------------- /hexo-note-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmirun/Hexo-Note/bb54e4039bd583fa528099f72916c840c7573914/hexo-note-image.png -------------------------------------------------------------------------------- /hexo-note-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /logo-angular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmirun/Hexo-Note/bb54e4039bd583fa528099f72916c840c7573914/logo-angular.jpg -------------------------------------------------------------------------------- /logo-electron.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmirun/Hexo-Note/bb54e4039bd583fa528099f72916c840c7573914/logo-electron.jpg -------------------------------------------------------------------------------- /main.ts: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow, screen, shell } from 'electron'; 2 | import * as path from 'path'; 3 | import * as url from 'url'; 4 | import { autoUploadCheck } from './main/autoUpdater'; 5 | import { createMenu } from './main/menu'; 6 | import { utils } from './main/utils'; 7 | 8 | let win, serve; 9 | const args = process.argv.slice(1); 10 | serve = args.some(val => val === '--serve'); 11 | 12 | function createWindow() { 13 | 14 | const electronScreen = screen; 15 | const size = electronScreen.getPrimaryDisplay().workAreaSize; 16 | 17 | // Create the browser window. 18 | win = new BrowserWindow({ 19 | x: 0, 20 | y: 0, 21 | width: size.width, 22 | height: size.height, 23 | webPreferences: { 24 | devTools: true 25 | } 26 | }); 27 | 28 | // Open In Browser External Links 29 | win.webContents.on('will-navigate', function(e, openedUrl) { 30 | if (openedUrl.includes('http')) { 31 | e.preventDefault(); 32 | shell.openExternal(openedUrl); 33 | } 34 | }); 35 | 36 | if (serve) { 37 | require('electron-reload')(__dirname, { 38 | electron: require(`${__dirname}/node_modules/electron`) 39 | }); 40 | win.loadURL('http://localhost:4200'); 41 | } else { 42 | win.loadURL(url.format({ 43 | pathname: path.join(__dirname, 'dist/index.html'), 44 | protocol: 'file:', 45 | slashes: true 46 | })); 47 | } 48 | 49 | if (utils.isDev()) { 50 | win.webContents.openDevTools(); 51 | } 52 | 53 | // Emitted when the window is closed. 54 | win.on('closed', () => { 55 | // Dereference the window object, usually you would store window 56 | // in an array if your app supports multi windows, this is the time 57 | // when you should delete the corresponding element. 58 | win = null; 59 | }); 60 | } 61 | 62 | try { 63 | 64 | // This method will be called when Electron has finished 65 | // initialization and is ready to create browser windows. 66 | // Some APIs can only be used after this event occurs. 67 | app.on('ready', () => { 68 | createWindow(); 69 | createMenu(); 70 | if (utils.isPro()) { 71 | setTimeout(autoUploadCheck, 2000); 72 | } 73 | }); 74 | 75 | // Quit when all windows are closed. 76 | app.on('window-all-closed', () => { 77 | // On OS X it is common for applications and their menu bar 78 | // to stay active until the user quits explicitly with Cmd + Q 79 | if (process.platform !== 'darwin') { 80 | app.quit(); 81 | } 82 | }); 83 | 84 | app.on('activate', () => { 85 | // On OS X it's common to re-create a window in the app when the 86 | // dock icon is clicked and there are no other windows open. 87 | if (win === null) { 88 | createWindow(); 89 | } 90 | }); 91 | 92 | } catch (e) { 93 | // Catch Error 94 | // throw e; 95 | } 96 | -------------------------------------------------------------------------------- /main/autoUpdater.ts: -------------------------------------------------------------------------------- 1 | import { autoUpdater } from 'electron-updater'; 2 | import * as electronLog from 'electron-log'; 3 | import { dialog, BrowserWindow, ipcMain } from 'electron'; 4 | import { UpdateCheckResult } from '../common/models/updateCheckResult.interface'; 5 | import { IPC_CHANNELS } from '../common/ipc-channels'; 6 | 7 | autoUpdater.logger = electronLog as any; 8 | 9 | export function autoUploadCheck() { 10 | autoUpdater.checkForUpdates(); 11 | 12 | // if exist new version 13 | autoUpdater.on('update-available', ( result: UpdateCheckResult) => { 14 | 15 | // create update information window 16 | let updateWin = new BrowserWindow({ 17 | width: 500, 18 | height: 300, 19 | autoHideMenuBar: true, 20 | maximizable: false, 21 | fullscreen: false, 22 | fullscreenable: false, 23 | resizable: false 24 | }); 25 | 26 | updateWin['custom'] = result; 27 | 28 | updateWin.loadURL(`file://${__dirname}/../renderer/update-window.html`); 29 | 30 | updateWin.on('close', () => { updateWin = null; }); 31 | 32 | ipcMain.on(IPC_CHANNELS.AUTO_UPLOAD_ACCEPT, (event) => { 33 | openDownloadProgressWindow(); 34 | event.returnValue = true; 35 | }); 36 | 37 | function openDownloadProgressWindow() { 38 | // creating progress window; 39 | let progressWin = new BrowserWindow({ 40 | width: 400, 41 | height: 80, 42 | autoHideMenuBar: true, 43 | maximizable: false, 44 | fullscreen: false, 45 | fullscreenable: false, 46 | resizable: false 47 | }); 48 | 49 | progressWin.loadURL(`file://${__dirname}/../renderer/update-progress.html`); 50 | 51 | progressWin.on('close', () => { progressWin = null; }); 52 | 53 | // sent progress percent to window; 54 | let progressPercent = 0; 55 | 56 | ipcMain.on(IPC_CHANNELS.AUTO_UPLOAD_DOWNLOAD_PROGRESS, (event) => { 57 | event.returnValue = progressPercent; 58 | }); 59 | 60 | autoUpdater.on('download-progress', (download) => { 61 | progressPercent = download.percent; 62 | }); 63 | 64 | autoUpdater.on('update-downloaded', () => { 65 | if (progressWin) { progressWin.close(); } 66 | 67 | dialog.showMessageBox( { 68 | type: 'info', 69 | title: 'Update Ready', 70 | message: 'Then new version is downloaded, Quit and install now?', 71 | buttons: ['Yes', 'Late'], 72 | }, 73 | (buttonIndex) => { 74 | if (buttonIndex === 0) { autoUpdater.quitAndInstall(); } 75 | }); 76 | 77 | }); 78 | } 79 | 80 | }); 81 | } 82 | -------------------------------------------------------------------------------- /main/menu.ts: -------------------------------------------------------------------------------- 1 | import { app, Menu } from 'electron'; 2 | 3 | export function createMenu() { 4 | const template = [ 5 | { 6 | label: 'Edit', 7 | submenu: [ 8 | {role: 'undo'}, 9 | {role: 'redo'}, 10 | {type: 'separator'}, 11 | {role: 'cut'}, 12 | {role: 'copy'}, 13 | {role: 'paste'}, 14 | {role: 'pasteandmatchstyle'}, 15 | {role: 'delete'}, 16 | {role: 'selectall'} 17 | ] 18 | }, 19 | { 20 | label: 'View', 21 | submenu: [ 22 | {role: 'reload'}, 23 | {role: 'forcereload'}, 24 | {role: 'toggledevtools'}, 25 | {type: 'separator'}, 26 | {role: 'resetzoom'}, 27 | {role: 'zoomin'}, 28 | {role: 'zoomout'}, 29 | {type: 'separator'}, 30 | {role: 'togglefullscreen'} 31 | ] 32 | }, 33 | { 34 | role: 'window', 35 | submenu: [ 36 | {role: 'minimize'}, 37 | {role: 'close'} 38 | ] 39 | }, 40 | { 41 | role: 'help', 42 | submenu: [ 43 | { 44 | label: 'Learn More', 45 | click () { require('electron').shell.openExternal('https://electronjs.org') } 46 | } 47 | ] 48 | } 49 | ] as any; 50 | 51 | if (process.platform === 'darwin') { 52 | template.unshift( { 53 | label: app.getName(), 54 | submenu: [ 55 | {role: 'about'}, 56 | {type: 'separator'}, 57 | {role: 'services', submenu: []}, 58 | {type: 'separator'}, 59 | {role: 'hide'}, 60 | {role: 'hideothers'}, 61 | {role: 'unhide'}, 62 | {type: 'separator'}, 63 | {role: 'quit'} 64 | ] 65 | }); 66 | 67 | // Edit menu 68 | template[1].submenu.push( 69 | {type: 'separator'}, 70 | { 71 | label: 'Speech', 72 | submenu: [ 73 | {role: 'startspeaking'}, 74 | {role: 'stopspeaking'} 75 | ] 76 | } 77 | ); 78 | 79 | // Window menu 80 | template[3].submenu = [ 81 | {role: 'close'}, 82 | {role: 'minimize'}, 83 | {role: 'zoom'}, 84 | {type: 'separator'}, 85 | {role: 'front'} 86 | ]; 87 | } 88 | 89 | Menu.setApplicationMenu(Menu.buildFromTemplate(template)); 90 | } 91 | -------------------------------------------------------------------------------- /main/utils.ts: -------------------------------------------------------------------------------- 1 | import { utils as commonUtils } from '../common/utils'; 2 | 3 | export const utils = { 4 | ...commonUtils 5 | }; 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hexo-note", 3 | "version": "0.4.0", 4 | "productName": "hexo-note", 5 | "description": "Hexo Note is a desktop client for Hexo.js", 6 | "homepage": "", 7 | "author": { 8 | "name": "Tmirun", 9 | "email": "tmirun@hotmail.com" 10 | }, 11 | "keywords": [ 12 | "hexo", 13 | "hexo note", 14 | "hexonote", 15 | "hexo client", 16 | "hexoclient", 17 | "hexojs", 18 | "angular", 19 | "angular 6", 20 | "electron", 21 | "typescript", 22 | "sass" 23 | ], 24 | "main": "main.js", 25 | "private": true, 26 | "scripts": { 27 | "postinstall": "npm run postinstall:electron && npx electron-builder install-app-deps", 28 | "postinstall:web": "node postinstall-web", 29 | "postinstall:electron": "node postinstall", 30 | "ng": "ng", 31 | "start": "npm run postinstall:electron && npm-run-all -p ng:serve electron:serve", 32 | "build": "npm run postinstall:electron && npm run electron:serve-tsc && ng build", 33 | "build:dev": "npm run build -- -c dev", 34 | "build:prod": "npm run build -- -c production", 35 | "ng:serve": "ng serve", 36 | "ng:serve:web": "npm run postinstall:web && ng serve -o", 37 | "electron:serve-tsc": "tsc -p tsconfig-serve.json", 38 | "electron:serve": "wait-on http-get://localhost:4200/ && npm run electron:serve-tsc && electron . --serve", 39 | "electron:local": "npm run build:prod && electron .", 40 | "electron:linux": "npm run build:prod && npx electron-builder build --linux", 41 | "electron:windows": "npm run build:prod && npx electron-builder build --windows", 42 | "electron:mac": "npm run build:prod && npx electron-builder build --mac", 43 | "electron:all": "npm run build:prod && npx electron-builder build -wml", 44 | "publish:linux": "npm run build:prod && npx electron-builder build -l -p'onTagOrDraft'", 45 | "publish:windows": "npm run build:prod && npx electron-builder build -w -p 'onTagOrDraft'", 46 | "publish:mac": "npm run build:prod && npx electron-builder build -m -p 'onTagOrDraft'", 47 | "publish:all": "npm run build:prod && npx electron-builder build -wml -p 'onTagOrDraft'", 48 | "test": "npm run postinstall:web && ng test", 49 | "e2e": "npm run postinstall:web && ng e2e" 50 | }, 51 | "dependencies": { 52 | "electron-is-dev": "^1.0.1", 53 | "electron-log": "^2.2.17", 54 | "electron-reload": "1.2.2", 55 | "electron-settings": "^3.2.0", 56 | "electron-updater": "^4.0.6", 57 | "fix-path": "^2.1.0", 58 | "fs-extra": "^7.0.0", 59 | "hexo": "^3.7.1", 60 | "jquery": "^3.3.1", 61 | "tslib": "^1.9.0" 62 | }, 63 | "devDependencies": { 64 | "@angular-devkit/build-angular": "~0.12.0", 65 | "@angular/animations": "^7.2.0", 66 | "@angular/cli": "7.2.1", 67 | "@angular/common": "7.2.0", 68 | "@angular/compiler": "7.2.0", 69 | "@angular/compiler-cli": "7.2.0", 70 | "@angular/core": "7.2.0", 71 | "@angular/flex-layout": "^7.0.0-beta.23", 72 | "@angular/forms": "7.2.0", 73 | "@angular/http": "7.2.0", 74 | "@angular/language-service": "7.2.0", 75 | "@angular/platform-browser": "7.2.0", 76 | "@angular/platform-browser-dynamic": "7.2.0", 77 | "@angular/router": "7.2.0", 78 | "@ctrl/ngx-codemirror": "^1.3.8", 79 | "@fortawesome/fontawesome-free": "^5.3.1", 80 | "@ngx-translate/core": "10.0.2", 81 | "@ngx-translate/http-loader": "3.0.1", 82 | "@types/jasmine": "2.8.8", 83 | "@types/jasminewd2": "2.0.3", 84 | "@types/node": "8.9.4", 85 | "@types/promise.prototype.finally": "^2.0.2", 86 | "chokidar": "^2.0.4", 87 | "codelyzer": "4.2.1", 88 | "codemirror": "^5.40.2", 89 | "core-js": "2.5.6", 90 | "electron": "4.0.1", 91 | "electron-builder": "^20.38.4", 92 | "jasmine-core": "3.1.0", 93 | "jasmine-spec-reporter": "4.2.1", 94 | "js-yaml": "^3.12.0", 95 | "karma": "2.0.2", 96 | "karma-chrome-launcher": "2.2.0", 97 | "karma-coverage-istanbul-reporter": "2.0.1", 98 | "karma-jasmine": "1.1.2", 99 | "karma-jasmine-html-reporter": "1.1.0", 100 | "less": "^2.7.3", 101 | "moment": "^2.22.2", 102 | "ng-zorro-antd": "^7.0.0-rc.3", 103 | "ngx-markdown": "^6.2.0", 104 | "npm-run-all": "4.1.3", 105 | "npx": "10.2.0", 106 | "promise.prototype.finally": "^3.1.0", 107 | "protractor": "5.3.2", 108 | "rxjs": "6.3.3", 109 | "rxjs-compat": "^6.3.2", 110 | "ts-node": "6.0.3", 111 | "tslint": "5.10.0", 112 | "typescript": "3.2.2", 113 | "uuid": "^3.3.2", 114 | "wait-on": "2.1.0", 115 | "webdriver-manager": "12.0.6", 116 | "zone.js": "0.8.27" 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /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 | }); -------------------------------------------------------------------------------- /renderer/update-progress.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |v --
49 |--
50 |Release Note:
51 |