├── _icons ├── add ├── icon.icns ├── icon.ico ├── icon.png ├── 30pxblue.png ├── 60pxblue.png ├── 90pxblue.png ├── 128pxblack.png ├── 128pxblue.png ├── 128pxwhite.png ├── 256pxblack.png ├── 256pxblue.png ├── 256pxwhite.png ├── 30pxblack.png ├── 30pxwhite.png ├── 512pxblack.png ├── 512pxblue.png ├── 512pxwhite.png ├── 60pxblack.png ├── 60pxwhite.png ├── 90pxblack.png ├── 90pxwhite.png ├── logotype1blue.png ├── logotype2blue.png ├── logotype1black.png ├── logotype1white.png ├── logotype2black.png ├── logotype2white.png ├── 30pxblack.svg ├── 30pxblue.svg ├── 30pxwhite.svg ├── 60pxblack.svg ├── 90pxblack.svg ├── 60pxblue.svg ├── 60pxwhite.svg ├── 128pxblack.svg ├── 90pxblue.svg ├── 90pxwhite.svg ├── 128pxblue.svg ├── 128pxwhite.svg ├── 256pxblack.svg ├── 256pxwhite.svg ├── 256pxblue.svg ├── 512pxblack.svg ├── 512pxblue.svg ├── 512pxwhite.svg ├── logotype1black.svg ├── logotype2black.svg ├── logotype1blue.svg ├── logotype1white.svg ├── logotype2blue.svg └── logotype2white.svg ├── src ├── data │ └── .gitkeep ├── utilities │ └── workerSample.ts ├── vue-shims.d.ts ├── renderer │ ├── assets │ │ ├── logo.png │ │ └── style │ │ │ ├── main.scss │ │ │ └── animations.scss │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ └── index.js │ ├── App.vue │ ├── views │ │ ├── Help.vue │ │ ├── About.vue │ │ └── Home.vue │ ├── components │ │ └── SystemInformation.vue │ ├── router │ │ └── index.js │ └── main.js ├── index.ejs └── main │ └── index.js ├── static └── .gitkeep ├── .vscode ├── settings.json ├── tasks.json └── launch.json ├── screenshot.png ├── .prettierrc ├── .editorconfig ├── .github ├── main.workflow └── FUNDING.yml ├── .gitignore ├── .whitesource ├── .eslintignore ├── appveyor.yml ├── .babelrc ├── tsconfig.json ├── .all-contributorsrc ├── LICENSE ├── .eslintrc.js ├── .travis.yml ├── _scripts ├── build.js ├── webpack.workers.config.js ├── webpack.main.config.js ├── dev-runner.js ├── webpack.renderer.config.js └── webpack.web.config.js ├── package.json └── README.md /_icons/add: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/data/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /src/utilities/workerSample.ts: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/screenshot.png -------------------------------------------------------------------------------- /_icons/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/icon.icns -------------------------------------------------------------------------------- /_icons/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/icon.ico -------------------------------------------------------------------------------- /_icons/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/icon.png -------------------------------------------------------------------------------- /_icons/30pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/30pxblue.png -------------------------------------------------------------------------------- /_icons/60pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/60pxblue.png -------------------------------------------------------------------------------- /_icons/90pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/90pxblue.png -------------------------------------------------------------------------------- /_icons/128pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/128pxblack.png -------------------------------------------------------------------------------- /_icons/128pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/128pxblue.png -------------------------------------------------------------------------------- /_icons/128pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/128pxwhite.png -------------------------------------------------------------------------------- /_icons/256pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/256pxblack.png -------------------------------------------------------------------------------- /_icons/256pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/256pxblue.png -------------------------------------------------------------------------------- /_icons/256pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/256pxwhite.png -------------------------------------------------------------------------------- /_icons/30pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/30pxblack.png -------------------------------------------------------------------------------- /_icons/30pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/30pxwhite.png -------------------------------------------------------------------------------- /_icons/512pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/512pxblack.png -------------------------------------------------------------------------------- /_icons/512pxblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/512pxblue.png -------------------------------------------------------------------------------- /_icons/512pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/512pxwhite.png -------------------------------------------------------------------------------- /_icons/60pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/60pxblack.png -------------------------------------------------------------------------------- /_icons/60pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/60pxwhite.png -------------------------------------------------------------------------------- /_icons/90pxblack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/90pxblack.png -------------------------------------------------------------------------------- /_icons/90pxwhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/90pxwhite.png -------------------------------------------------------------------------------- /_icons/logotype1blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype1blue.png -------------------------------------------------------------------------------- /_icons/logotype2blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype2blue.png -------------------------------------------------------------------------------- /src/vue-shims.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue' 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /_icons/logotype1black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype1black.png -------------------------------------------------------------------------------- /_icons/logotype1white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype1white.png -------------------------------------------------------------------------------- /_icons/logotype2black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype2black.png -------------------------------------------------------------------------------- /_icons/logotype2white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/_icons/logotype2white.png -------------------------------------------------------------------------------- /src/renderer/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mubaidr/vue-electron-template/HEAD/src/renderer/assets/logo.png -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "tabWidth": 2, 5 | "trailingComma": "es5", 6 | "useTabs": false 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "type": "shell", 4 | "tasks": [ 5 | { 6 | "label": "debug", 7 | "command": "npm", 8 | "args": ["run", "debug"] 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = crlf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "New workflow" { 2 | on = "push" 3 | resolves = ["GitHub Action for npm"] 4 | } 5 | 6 | action "GitHub Action for npm" { 7 | uses = "actions/npm@59b64a598378f31e49cb76f27d6f3312b582f680" 8 | runs = "npm run build" 9 | } 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/electron/* 3 | dist/web/* 4 | build/* 5 | !build/icons 6 | coverage 7 | node_modules/ 8 | npm-debug.log 9 | npm-debug.log.* 10 | thumbs.db 11 | !.gitkeep 12 | data/tmp/ 13 | .tmp/ 14 | tmp/ 15 | .cache 16 | dist 17 | coverage 18 | __coverage__ 19 | -------------------------------------------------------------------------------- /.whitesource: -------------------------------------------------------------------------------- 1 | ########################################################## 2 | #### WhiteSource "Bolt for Github" configuration file #### 3 | ########################################################## 4 | 5 | # Configuration # 6 | #---------------# 7 | ws.repo.scan=true 8 | vulnerable.check.run.conclusion.level=failure 9 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | dist/electron/* 3 | dist/web/* 4 | build/* 5 | !build/icons 6 | coverage 7 | node_modules/ 8 | npm-debug.log 9 | npm-debug.log.* 10 | thumbs.db 11 | !.gitkeep 12 | data/tmp/ 13 | .tmp/ 14 | tmp/ 15 | .cache 16 | dist 17 | coverage 18 | __coverage__ 19 | node_modules 20 | _scripts 21 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | platform: 4 | - x64 5 | 6 | cache: 7 | - node_modules 8 | - '%USERPROFILE%\.electron' 9 | 10 | init: 11 | - git config --global core.autocrlf input 12 | 13 | install: 14 | - ps: Install-Product node 12 x64 15 | - npm install 16 | 17 | build_script: 18 | - npm run build 19 | 20 | test: off 21 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "targets": { 7 | "chrome": "89", 8 | "node": "14.16" 9 | }, 10 | "modules": "commonjs" 11 | } 12 | ] 13 | ], 14 | "plugins": [ 15 | "@babel/proposal-class-properties", 16 | "@babel/proposal-object-rest-spread" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/renderer/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | // import createPersistedState from 'vuex-persistedstate' 4 | 5 | import modules from './modules' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default new Vuex.Store({ 10 | modules, 11 | strict: process.env.NODE_ENV !== 'production', 12 | 13 | // TODO: Enable when deploy 14 | // plugins: [createPersistedState()] 15 | }) 16 | -------------------------------------------------------------------------------- /src/renderer/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": true, 4 | "esModuleInterop": true, 5 | "isolatedModules": true, 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "resolveJsonModule": true, 9 | "strict": true, 10 | "target": "ES6", 11 | "types": ["node"] 12 | }, 13 | "exclude": ["node_modules"], 14 | "files": ["src/vue-shims.d.ts"], 15 | "include": ["src/**/*.ts", "src/**/*.vue"] 16 | } 17 | -------------------------------------------------------------------------------- /src/renderer/store/modules/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The file enables `@/store/index.js` to import all vuex modules 3 | * in a one-shot manner. There should not be any reason to edit this file. 4 | */ 5 | 6 | const files = require.context('.', false, /\.js$/) 7 | const modules = {} 8 | 9 | files.keys().forEach((key) => { 10 | if (key === './index.js') return 11 | modules[key.replace(/(\.\/|\.js)/g, '')] = files(key).default 12 | }) 13 | 14 | export default modules 15 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "cwd": "${workspaceFolder}", 5 | "name": "Electron: Main", 6 | "port": 9222, 7 | "protocol": "inspector", 8 | "request": "attach", 9 | "sourceMaps": true, 10 | "type": "node" 11 | }, 12 | { 13 | "name": "Electron: Renderer", 14 | "port": 9223, 15 | "request": "attach", 16 | "sourceMaps": true, 17 | "type": "chrome", 18 | "webRoot": "${workspaceFolder}" 19 | } 20 | ], 21 | "version": "0.2.0" 22 | } 23 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: mubaidr 4 | patreon: mubaidr 5 | open_collective: mubaidr 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: mubaidr 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /src/renderer/views/Help.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 27 | 28 | 33 | -------------------------------------------------------------------------------- /src/renderer/assets/style/main.scss: -------------------------------------------------------------------------------- 1 | html { 2 | overflow: auto; 3 | } 4 | 5 | body { 6 | -webkit-user-select: none; 7 | -moz-user-select: -moz-none; 8 | -ms-user-select: none; 9 | user-select: none; 10 | } 11 | 12 | img { 13 | box-shadow: none; 14 | } 15 | 16 | .section { 17 | padding: 1.5em; 18 | } 19 | 20 | span + .material-icons { 21 | margin-left: 0.25em; 22 | } 23 | 24 | .material-icons + span { 25 | margin-left: 0.25em; 26 | } 27 | 28 | .has-pointer { 29 | cursor: pointer; 30 | } 31 | 32 | .no-padding { 33 | padding: 0 !important; 34 | } 35 | 36 | .file-name { 37 | padding-top: 0.25em; 38 | } 39 | 40 | /* custom Scroll bars */ 41 | ::-webkit-scrollbar { 42 | width: 10px !important; 43 | height: 10px !important; 44 | } 45 | 46 | ::-webkit-scrollbar-track { 47 | background: #f0f0f0; 48 | } 49 | 50 | ::-webkit-scrollbar-thumb { 51 | background: #666666; 52 | } 53 | -------------------------------------------------------------------------------- /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "vue-electron-template", 3 | "projectOwner": "mubaidr", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": false, 11 | "contributors": [ 12 | { 13 | "login": "jbeguna04", 14 | "name": "Jibbie R. Eguna", 15 | "avatar_url": "https://avatars3.githubusercontent.com/u/35353768?v=4", 16 | "profile": "https://github.com/jbeguna04", 17 | "contributions": [ 18 | "design" 19 | ] 20 | }, 21 | { 22 | "login": "eiurur", 23 | "name": "eiurur", 24 | "avatar_url": "https://avatars0.githubusercontent.com/u/4101830?v=4", 25 | "profile": "https://github.com/eiurur", 26 | "contributions": [ 27 | "code" 28 | ] 29 | } 30 | ], 31 | "contributorsPerLine": 7, 32 | "skipCi": true 33 | } 34 | -------------------------------------------------------------------------------- /src/renderer/components/SystemInformation.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 11 | <% if (htmlWebpackPlugin.options.nodeModules) { %> 12 | 17 | <% } %> 18 | 19 | 20 | 21 |
22 | 23 | 24 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/renderer/views/About.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 36 | 37 | 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Muhammad Ubaid Raza 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 | -------------------------------------------------------------------------------- /src/renderer/views/Home.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 41 | 42 | 47 | -------------------------------------------------------------------------------- /src/renderer/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import About from '../views/About.vue' 4 | import Help from '../views/Help.vue' 5 | import Home from '../views/Home.vue' 6 | 7 | Vue.use(Router) 8 | 9 | const router = new Router({ 10 | routes: [ 11 | { 12 | path: '/', 13 | redirect: '/home', 14 | }, 15 | { 16 | path: '/home', 17 | meta: { 18 | title: 'Home', 19 | icon: 'fa-home', 20 | }, 21 | component: Home, 22 | }, 23 | { 24 | path: '/about', 25 | meta: { 26 | title: 'About', 27 | icon: 'fa-info-circle', 28 | }, 29 | component: About, 30 | }, 31 | { 32 | path: '/help', 33 | meta: { 34 | title: 'Help', 35 | icon: 'fa-info-circle', 36 | }, 37 | component: Help, 38 | }, 39 | { 40 | path: '*', 41 | redirect: '/home', 42 | }, 43 | ], 44 | }) 45 | 46 | // dynamically set application title to current view 47 | router.afterEach((to) => { 48 | let title = 49 | to.path === '/home' 50 | ? process.env.PRODUCT_NAME 51 | : `${to.meta.title} - ${process.env.PRODUCT_NAME}` 52 | 53 | if (!title) { 54 | title = 'Home' 55 | } 56 | 57 | document.title = title 58 | }) 59 | 60 | export default router 61 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // https://eslint.org/docs/user-guide/configuring#using-configuration-files-1 3 | root: true, 4 | 5 | // https://eslint.org/docs/user-guide/configuring#specifying-environments 6 | env: { 7 | browser: true, 8 | node: true, 9 | }, 10 | 11 | // https://eslint.org/docs/user-guide/configuring#specifying-parser 12 | parser: 'vue-eslint-parser', 13 | 14 | // https://vuejs.github.io/eslint-plugin-vue/user-guide/#faq 15 | parserOptions: { 16 | parser: 'babel-eslint', 17 | ecmaVersion: 2018, 18 | sourceType: 'module', 19 | }, 20 | 21 | // https://eslint.org/docs/user-guide/configuring#extending-configuration-files 22 | // order matters: from least important to most important in terms of overriding 23 | // Prettier + Vue: https://medium.com/@gogl.alex/how-to-properly-set-up-eslint-with-prettier-for-vue-or-nuxt-in-vscode-e42532099a9c 24 | extends: [ 25 | 'eslint:recommended', 26 | 'plugin:vue/recommended', 27 | 'plugin:@typescript-eslint/eslint-recommended', 28 | 'plugin:@typescript-eslint/recommended', 29 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', 30 | 'prettier', 31 | 'prettier/@typescript-eslint', 32 | 'prettier/vue', 33 | ], 34 | 35 | // https://eslint.org/docs/user-guide/configuring#configuring-plugins 36 | plugins: ['vue', '@typescript-eslint', 'prettier'], 37 | 38 | rules: { 39 | 'no-console': 0, 40 | semi: 0, 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/main.js: -------------------------------------------------------------------------------- 1 | import 'bulma-fluent/bulma.sass' 2 | import 'material-design-icons/iconfont/material-icons.css' 3 | import Vue from 'vue' 4 | import App from './App.vue' 5 | import './assets/style/animations.scss' 6 | import './assets/style/main.scss' 7 | import router from './router/index' 8 | import store from './store/index' 9 | 10 | const isDev = process.env.NODE_ENV === 'development' 11 | 12 | Vue.config.devtools = isDev 13 | Vue.config.performance = isDev 14 | Vue.config.productionTip = isDev 15 | 16 | // tslint:disable-next-line: no-unused-expression 17 | new Vue({ 18 | el: '#app', 19 | router, 20 | store, 21 | render: (h) => h(App), 22 | }) 23 | 24 | // to avoild accesing electorn api from web app build 25 | if (window && window.process && window.process.type === 'renderer') { 26 | const { ipcRenderer } = require('electron') 27 | 28 | // handle menu event updates from main script 29 | ipcRenderer.on('change-view', (event, data) => { 30 | if (data.route) { 31 | router.push(data.route) 32 | } 33 | }) 34 | } 35 | 36 | // sample context menu 37 | // const { remote } = require('electron') 38 | // const { Menu, MenuItem } = remote 39 | // const menu = new Menu() 40 | // menu.append(new MenuItem({ label: 'Home' })) 41 | // menu.append(new MenuItem({ type: 'separator' })) 42 | // menu.append(new MenuItem({ label: 'Other' })) 43 | 44 | // window.addEventListener( 45 | // 'contextmenu', 46 | // (e) => { 47 | // e.preventDefault() 48 | // menu.popup({ window: remote.getCurrentWindow() }) 49 | // }, 50 | // false 51 | // ) 52 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - os: osx 4 | osx_image: xcode9.3 5 | language: node_js 6 | node_js: '12' 7 | env: 8 | - ELECTRON_CACHE=$HOME/.cache/electron 9 | - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder 10 | 11 | - os: linux 12 | services: docker 13 | language: node_js 14 | node_js: '12' 15 | env: 16 | - ELECTRON_CACHE=$HOME/.cache/electron 17 | - ELECTRON_BUILDER_CACHE=$HOME/.cache/electron-builder 18 | 19 | cache: 20 | directories: 21 | - node_modules 22 | - $HOME/.cache/electron 23 | - $HOME/.cache/electron-builder 24 | 25 | before_install: 26 | - | 27 | if [ "$TRAVIS_OS_NAME" == "osx" ]; then 28 | mkdir -p /tmp/git-lfs && curl -L https://github.com/github/git-lfs/releases/download/v2.3.1/git-lfs-$([ "$TRAVIS_OS_NAME" == "linux" ] && echo "linux" || echo "darwin")-amd64-2.3.1.tar.gz | tar -xz -C /tmp/git-lfs --strip-components 1 29 | export PATH="/tmp/git-lfs:$PATH" 30 | fi 31 | before_script: 32 | - git lfs pull 33 | 34 | script: 35 | - | 36 | if [ "$TRAVIS_OS_NAME" == "linux" ]; then 37 | docker run --rm \ 38 | --env-file <(env | grep -v '\r' | grep -iE 'DEBUG|NODE_|ELECTRON_|YARN_|NPM_|CI|CIRCLE|TRAVIS|APPVEYOR_|CSC_|_TOKEN|_KEY|AWS_|STRIP|BUILD_') \ 39 | -v ${PWD}:/project \ 40 | -v ~/.cache/electron:/root/.cache/electron \ 41 | -v ~/.cache/electron-builder:/root/.cache/electron-builder \ 42 | electronuserland/builder:wine 43 | fi 44 | - npm run build 45 | 46 | before_cache: 47 | - rm -rf $HOME/.cache/electron-builder/wine 48 | 49 | branches: 50 | except: 51 | - "/^v\\d+\\.\\d+\\.\\d+$/" 52 | -------------------------------------------------------------------------------- /_scripts/build.js: -------------------------------------------------------------------------------- 1 | const os = require('os') 2 | const builder = require('electron-builder') 3 | 4 | const Platform = builder.Platform 5 | const { name, productName } = require('../package.json') 6 | 7 | let targets 8 | var platform = os.platform() 9 | 10 | if (platform == 'darwin') { 11 | targets = Platform.MAC.createTarget() 12 | } else if (platform == 'win32') { 13 | targets = Platform.WINDOWS.createTarget() 14 | } else if (platform == 'linux') { 15 | targets = Platform.LINUX.createTarget() 16 | } 17 | 18 | const config = { 19 | appId: `com.mubaidr.${name}`, 20 | copyright: 'Copyright ©2019 mubaidr@gmail.com', 21 | // asar: false, 22 | // compression: 'store', 23 | productName, 24 | directories: { 25 | output: './build/', 26 | }, 27 | files: ['_icons/icon.*', './dist/**/*', '!./dist/web/**/*'], 28 | dmg: { 29 | contents: [ 30 | { 31 | path: '/Applications', 32 | type: 'link', 33 | x: 410, 34 | y: 230, 35 | }, 36 | { 37 | type: 'file', 38 | x: 130, 39 | y: 230, 40 | }, 41 | ], 42 | window: { 43 | height: 380, 44 | width: 540, 45 | }, 46 | }, 47 | linux: { 48 | icon: '_icons/icon.png', 49 | target: ['deb', 'snap', 'AppImage'], 50 | }, 51 | mac: { 52 | category: 'public.app-category.utilities', 53 | icon: '_icons/icon.icns', 54 | target: ['dmg', 'zip'], 55 | type: 'distribution', 56 | }, 57 | win: { 58 | icon: '_icons/icon.ico', 59 | target: ['nsis', 'zip', 'portable'], 60 | }, 61 | nsis: { 62 | allowToChangeInstallationDirectory: true, 63 | oneClick: false, 64 | }, 65 | } 66 | 67 | builder 68 | .build({ 69 | targets, 70 | config, 71 | }) 72 | .then((m) => { 73 | console.log(m) 74 | }) 75 | .catch((e) => { 76 | console.error(e) 77 | }) 78 | -------------------------------------------------------------------------------- /_scripts/webpack.workers.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | 4 | const { 5 | dependencies, 6 | devDependencies, 7 | productName, 8 | } = require('../package.json') 9 | 10 | const externals = Object.keys(dependencies).concat(Object.keys(devDependencies)) 11 | const isDevMode = process.env.NODE_ENV === 'development' 12 | 13 | const config = { 14 | name: 'workers', 15 | mode: process.env.NODE_ENV, 16 | devtool: isDevMode ? 'eval-source-map' : false, 17 | entry: { 18 | workerSample: path.join(__dirname, '../src/utilities/workerSample.ts'), 19 | }, 20 | output: { 21 | libraryTarget: 'commonjs2', 22 | path: path.join(__dirname, '../dist'), 23 | filename: '[name].js', 24 | }, 25 | externals: externals, 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.tsx?$/, 30 | use: 'ts-loader', 31 | exclude: /node_modules/, 32 | }, 33 | { 34 | test: /\.js$/, 35 | use: 'babel-loader', 36 | exclude: /node_modules/, 37 | }, 38 | { 39 | test: /\.node$/, 40 | use: 'node-loader', 41 | }, 42 | ], 43 | }, 44 | node: { 45 | global: true, 46 | __dirname: isDevMode, 47 | __filename: isDevMode, 48 | }, 49 | plugins: [ 50 | // new WriteFilePlugin(), 51 | new webpack.DefinePlugin({ 52 | 'process.env.PRODUCT_NAME': JSON.stringify(productName), 53 | }), 54 | ], 55 | resolve: { 56 | alias: { 57 | '@': path.join(__dirname, '../src/'), 58 | src: path.join(__dirname, '../src/'), 59 | }, 60 | extensions: ['.ts', '.js', '.json'], 61 | }, 62 | target: 'node', 63 | } 64 | 65 | /** 66 | * Adjust rendererConfig for production settings 67 | */ 68 | if (isDevMode) { 69 | // any dev only config 70 | config.plugins.push(new webpack.HotModuleReplacementPlugin()) 71 | } else { 72 | config.plugins.push( 73 | new webpack.LoaderOptionsPlugin({ 74 | minimize: true, 75 | }) 76 | ) 77 | } 78 | 79 | module.exports = config 80 | -------------------------------------------------------------------------------- /_scripts/webpack.main.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const CopyWebpackPlugin = require('copy-webpack-plugin') 4 | 5 | const { 6 | dependencies, 7 | devDependencies, 8 | productName, 9 | } = require('../package.json') 10 | 11 | const externals = Object.keys(dependencies).concat(Object.keys(devDependencies)) 12 | const isDevMode = process.env.NODE_ENV === 'development' 13 | const whiteListedModules = [] 14 | 15 | const config = { 16 | name: 'main', 17 | mode: process.env.NODE_ENV, 18 | devtool: isDevMode ? 'eval-source-map' : false, 19 | entry: { 20 | main: path.join(__dirname, '../src/main/index.js'), 21 | }, 22 | externals: externals.filter((d) => !whiteListedModules.includes(d)), 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.tsx?$/, 27 | use: 'ts-loader', 28 | exclude: /node_modules/, 29 | }, 30 | { 31 | test: /\.js$/, 32 | use: 'babel-loader', 33 | exclude: /node_modules/, 34 | }, 35 | { 36 | test: /\.node$/, 37 | use: 'node-loader', 38 | }, 39 | ], 40 | }, 41 | node: { 42 | global: true, 43 | __dirname: isDevMode, 44 | __filename: isDevMode, 45 | }, 46 | plugins: [ 47 | new webpack.DefinePlugin({ 48 | 'process.env.PRODUCT_NAME': JSON.stringify(productName), 49 | }), 50 | ], 51 | output: { 52 | filename: '[name].js', 53 | libraryTarget: 'commonjs2', 54 | path: path.join(__dirname, '../dist'), 55 | }, 56 | resolve: { 57 | extensions: ['.ts', '.js', '.json'], 58 | alias: { 59 | '@': path.join(__dirname, '../src/'), 60 | src: path.join(__dirname, '../src/'), 61 | }, 62 | }, 63 | target: 'electron-main', 64 | } 65 | 66 | if (isDevMode) { 67 | config.plugins.push( 68 | new webpack.DefinePlugin({ 69 | __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, 70 | }) 71 | ) 72 | } else { 73 | config.plugins.push( 74 | new CopyWebpackPlugin({ 75 | patterns: [ 76 | { 77 | from: path.join(__dirname, '../src/data'), 78 | to: path.join(__dirname, '../dist/data'), 79 | }, 80 | { 81 | from: path.join(__dirname, '../static'), 82 | to: path.join(__dirname, '../dist/static'), 83 | globOptions: { 84 | ignore: ['.*'], 85 | }, 86 | }, 87 | ], 88 | }), 89 | new webpack.LoaderOptionsPlugin({ 90 | minimize: true, 91 | }) 92 | ) 93 | } 94 | 95 | module.exports = config 96 | -------------------------------------------------------------------------------- /_icons/30pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/30pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/30pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/60pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/90pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/60pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/60pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/128pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/90pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/90pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/128pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/128pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/256pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/256pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/256pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_scripts/dev-runner.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = 'development' 2 | // process.env.ELECTRON_ENABLE_LOGGING = true 3 | 4 | const chalk = require('chalk') 5 | const electron = require('electron') 6 | const webpack = require('webpack') 7 | const WebpackDevServer = require('webpack-dev-server') 8 | const kill = require('tree-kill') 9 | 10 | const path = require('path') 11 | const { spawn } = require('child_process') 12 | 13 | const mainConfig = require('./webpack.main.config') 14 | const rendererConfig = require('./webpack.renderer.config') 15 | const workersConfig = require('./webpack.workers.config') 16 | 17 | let electronProcess = null 18 | let manualRestart = null 19 | const remoteDebugging = process.argv.includes('--remote-debug') 20 | 21 | if (remoteDebugging) { 22 | // disable dvtools open in electron 23 | process.env.RENDERER_REMOTE_DEBUGGING = true 24 | } 25 | 26 | async function killElectron(pid) { 27 | return new Promise((resolve, reject) => { 28 | if (pid) { 29 | kill(pid, 'SIGKILL', (err) => { 30 | if (err) reject(err) 31 | 32 | resolve() 33 | }) 34 | } else { 35 | resolve() 36 | } 37 | }) 38 | } 39 | 40 | async function restartElectron() { 41 | console.log(chalk.gray('\nStarting electron...')) 42 | 43 | const { pid } = electronProcess || {} 44 | await killElectron(pid) 45 | 46 | electronProcess = spawn(electron, [ 47 | path.join(__dirname, '../dist/main.js'), 48 | // '--enable-logging', // Enable to show logs from all electron processes 49 | remoteDebugging ? '--inspect=9222' : '', 50 | remoteDebugging ? '--remote-debugging-port=9223' : '', 51 | ]) 52 | 53 | electronProcess.stdout.on('data', (data) => { 54 | console.log(chalk.white(data.toString())) 55 | }) 56 | 57 | electronProcess.stderr.on('data', (data) => { 58 | console.error(chalk.red(data.toString())) 59 | }) 60 | 61 | electronProcess.on('exit', (code, signal) => { 62 | if (!manualRestart) process.exit(0) 63 | }) 64 | } 65 | 66 | function startMain() { 67 | const webpackSetup = webpack([mainConfig, workersConfig]) 68 | 69 | webpackSetup.compilers.forEach((compiler) => { 70 | const { name } = compiler 71 | 72 | switch (name) { 73 | case 'workers': 74 | compiler.hooks.afterEmit.tap('afterEmit', async () => { 75 | console.log(chalk.gray(`\nCompiled ${name} script!`)) 76 | console.log( 77 | chalk.gray(`\nWatching file changes for ${name} script...`) 78 | ) 79 | }) 80 | break 81 | case 'main': 82 | default: 83 | compiler.hooks.afterEmit.tap('afterEmit', async () => { 84 | console.log(chalk.gray(`\nCompiled ${name} script!`)) 85 | 86 | manualRestart = true 87 | await restartElectron() 88 | 89 | setTimeout(() => { 90 | manualRestart = false 91 | }, 2500) 92 | 93 | console.log( 94 | chalk.gray(`\nWatching file changes for ${name} script...`) 95 | ) 96 | }) 97 | break 98 | } 99 | }) 100 | 101 | webpackSetup.watch( 102 | { 103 | aggregateTimeout: 500, 104 | }, 105 | (err) => { 106 | if (err) console.error(chalk.red(err)) 107 | } 108 | ) 109 | } 110 | 111 | function startRenderer(callback) { 112 | const compiler = webpack(rendererConfig) 113 | const { name } = compiler 114 | 115 | compiler.hooks.afterEmit.tap('afterEmit', () => { 116 | console.log(chalk.gray(`\nCompiled ${name} script!`)) 117 | console.log(chalk.gray(`\nWatching file changes for ${name} script...`)) 118 | }) 119 | 120 | const server = new WebpackDevServer(compiler, { 121 | contentBase: path.join(__dirname, '../'), 122 | hot: true, 123 | noInfo: true, 124 | overlay: true, 125 | clientLogLevel: 'warning', 126 | }) 127 | 128 | server.listen(9080, '', (err) => { 129 | if (err) console.error(chalk.red(err)) 130 | 131 | callback() 132 | }) 133 | } 134 | 135 | startRenderer(startMain) 136 | -------------------------------------------------------------------------------- /_icons/512pxblack.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/512pxblue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/512pxwhite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Muhammad Ubaid Raza ", 3 | "bugs": { 4 | "url": "https://github.com/mubaidr/vue-electron-template/issues" 5 | }, 6 | "dependencies": { 7 | "@electron/remote": "^1.1.0", 8 | "bulma-fluent": "^0.4.3", 9 | "material-design-icons": "^3.0.1", 10 | "vue": "^2.6.12", 11 | "vue-electron": "^1.0.6", 12 | "vue-router": "^3.5.1", 13 | "vuex": "^3.6.2" 14 | }, 15 | "description": "An electron-vue project", 16 | "devDependencies": { 17 | "@babel/core": "^7.13.15", 18 | "@babel/plugin-proposal-class-properties": "^7.13.0", 19 | "@babel/plugin-proposal-object-rest-spread": "^7.13.8", 20 | "@babel/preset-env": "^7.13.15", 21 | "@types/babel__core": "^7.1.14", 22 | "@types/babel__preset-env": "^7.9.1", 23 | "@types/copy-webpack-plugin": "^6.4.1", 24 | "@types/electron-devtools-installer": "^2.2.0", 25 | "@types/eslint": "^7.2.9", 26 | "@types/eslint-plugin-prettier": "^3.1.0", 27 | "@types/file-loader": "^4.2.1", 28 | "@types/mini-css-extract-plugin": "^1.4.1", 29 | "@types/prettier": "^2.2.3", 30 | "@types/sass": "^1.16.0", 31 | "@typescript-eslint/eslint-plugin": "^4.22.0", 32 | "@typescript-eslint/parser": "^4.22.0", 33 | "babel-eslint": "^10.1.0", 34 | "babel-loader": "^8.2.2", 35 | "chalk": "^4.1.0", 36 | "copy-webpack-plugin": "^8.1.1", 37 | "css-loader": "^5.2.1", 38 | "electron": "^12.0.2", 39 | "electron-builder": "^22.10.5", 40 | "electron-debug": "^3.2.0", 41 | "electron-devtools-installer": "^3.1.1", 42 | "electron-rebuild": "^2.3.5", 43 | "eslint": "^7.24.0", 44 | "eslint-config-prettier": "^8.1.0", 45 | "eslint-plugin-prettier": "^3.3.1", 46 | "eslint-plugin-vue": "^7.9.0", 47 | "fast-glob": "^3.2.5", 48 | "file-loader": "^6.2.0", 49 | "html-webpack-plugin": "^5.3.1", 50 | "mini-css-extract-plugin": "^1.4.1", 51 | "node-loader": "^2.0.0", 52 | "npm-run-all": "^4.1.5", 53 | "prettier": "^2.2.1", 54 | "sass": "^1.32.8", 55 | "sass-loader": "^11.0.1", 56 | "style-loader": "^2.0.0", 57 | "tree-kill": "1.2.2", 58 | "ts-loader": "^8.1.0", 59 | "typescript": "^4.2.4", 60 | "url-loader": "^4.1.1", 61 | "vue-eslint-parser": "^7.6.0", 62 | "vue-loader": "^15.9.6", 63 | "vue-style-loader": "^4.1.3", 64 | "vue-template-compiler": "^2.6.12", 65 | "webpack": "^5.31.2", 66 | "webpack-cli": "^4.6.0", 67 | "webpack-dev-server": "^3.11.2" 68 | }, 69 | "license": "MIT", 70 | "main": "./dist/main.js", 71 | "name": "vue-electron-template", 72 | "private": true, 73 | "productName": "Vue Electron Template", 74 | "repository": { 75 | "type": "git", 76 | "url": "git+https://github.com/mubaidr/vue-electron-template.git" 77 | }, 78 | "scripts": { 79 | "build": "run-s rebuild:electron pack build-release", 80 | "build-release": "node _scripts/build.js", 81 | "debug": "run-s rebuild:electron debug-runner", 82 | "debug-runner": "node _scripts/dev-runner.js --remote-debug", 83 | "dev": "run-s rebuild:electron dev-runner", 84 | "dev-runner": "node _scripts/dev-runner.js", 85 | "electron-builder-install": "electron-builder install-app-deps", 86 | "electron-rebuild": "electron-rebuild", 87 | "jest": "jest", 88 | "jest:coverage": "jest --collect-coverage", 89 | "jest:watch": "jest --watch", 90 | "lint": "eslint --fix --ext .js,.ts,.vue ./ && npm run prettier", 91 | "pack": "run-p pack:main pack:renderer pack:workers", 92 | "pack:main": "webpack --mode=production --config _scripts/webpack.main.config.js", 93 | "pack:renderer": "webpack --mode=production --config _scripts/webpack.renderer.config.js", 94 | "pack:web": "webpack --mode=production --config _scripts/webpack.web.config.js", 95 | "pack:workers": "webpack --mode=production --config _scripts/webpack.workers.config.js", 96 | "postinstall": "electron-rebuild", 97 | "prettier": "prettier --write \"{src,_scripts}/**/*.{js,ts,vue}\"", 98 | "rebuild:electron": "run-s electron-builder-install electron-rebuild", 99 | "rebuild:node": "npm rebuild", 100 | "release": "run-s test build", 101 | "test": "run-s rebuild:node pack:workers jest", 102 | "test:watch": "run-s rebuild:node pack:workers jest:watch" 103 | }, 104 | "version": "0.0.1" 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | # Vue-Electron-Template 4 | 5 | [![Build Status](https://travis-ci.org/mubaidr/vue-electron-template.svg?branch=master)](https://travis-ci.org/mubaidr/vue-electron-template) 6 | [![Build status](https://ci.appveyor.com/api/projects/status/cjua6pdhjp9rqa1o?svg=true)](https://ci.appveyor.com/project/mubaidr/vue-electron-template) 7 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors) 8 | 9 | Template for building desktop applications using [Electronjs](https://electronjs.org) and [Vue.js](https://vuejs.org) 10 | 11 | ## NOTICE 12 | 13 | [Vue3 Support](https://github.com/mubaidr/vue-electron-template/issues/907) 14 | 15 | ## Overview 16 | 17 | This template takes advantage of `webpack-5` with `vue-loader`, `electron-builder`, and some of the most used plugins like `vue-router`, `vuex` and so much more to provide an easy to use development (with vscode debugging) enviroment with hot module replacement. 18 | 19 | ### Features 20 | 21 | - [Bulma-Fluent](https://mubaidr.github.io/bulma-fluent/), a theme suitable for desktop application based on [Bulma](https://bulma.io/) 22 | - [vue-router](https://github.com/vuejs/vue-router) 23 | - [vuex](https://github.com/vuejs/vuex) 24 | - [vue-electron](https://github.com/SimulatedGREG/vue-electron) 25 | - [material-design-icons](http://google.github.io/material-design-icons/) installed 26 | - Some built-in animaitons [animations.scss](src\renderer\assets\style\animations.scss) 27 | - `SCSS`/`SASS` support with [vue-loader](https://github.com/vuejs/vue-loader/) (removes unused css/styles during build) 28 | - `Typescript` support (for `Vuejs` as well) 29 | - Worker scripts (to perform CPU-intensive operations), to use with nodejs `child_process` module. [Sample Worker File](src\utilities\workerSample.ts) 30 | - Easily package your electron app using [electron-builder](https://github.com/electron-userland/electron-builder) 31 | - `vue-devtools` installed 32 | - `DEV`, `DEBUG` & `BUILD` NPM scripts 33 | - `Babel` configured 34 | - `ESLint` configured 35 | - `vscode` debug config for renderer process debugging 36 | - Process restarting when working in main process & hot module replacement for renderer 37 | - Generates web/browser build in the `dist/web` directory too 38 | - `--debug` paramter to enable dev tools in production build executeable 39 | 40 | ### Screenshot 41 | 42 |

43 | 44 | ### Getting Started 45 | 46 | Clone this repository, install dependencies and run using either `dev`, `debug` or `build` command. 47 | 48 | ```bash 49 | # Clone this repository 50 | git clone https://github.com/mubaidr/vue-electron 51 | 52 | # change directory to cloned path 53 | cd vue-electron 54 | 55 | # Install dependencies 56 | npm install 57 | 58 | # Run in `debug` mode, to debug app using VSCODE 59 | npm run debug 60 | 61 | # Run in `dev` mode 62 | npm run dev 63 | 64 | # Build installer for this app 65 | npm run build 66 | ``` 67 | 68 | ### Project structure 69 | 70 | `src/main` contains electron main script. 71 | 72 | `src/renderer` contains vue-js application. 73 | 74 | `src/utilities/workerSample.ts` a sample worker script. 75 | 76 | #### Credits 77 | 78 | All credits to authors of packages and tools used in the project. 79 | 80 | \* This template is inspired by [electron-vue](https://github.com/SimulatedGREG/electron-vue) 81 | 82 | ## Contributors 83 | 84 | Thanks goes to these wonderful people ([emoji key](https://github.com/all-contributors/all-contributors#emoji-key)): 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 |

Jibbie R. Eguna

🎨

eiurur

💻
95 | 96 | 97 | 98 | 99 | 100 | 101 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 102 | -------------------------------------------------------------------------------- /_scripts/webpack.renderer.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const HtmlWebpackPlugin = require('html-webpack-plugin') 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 5 | const CopyWebpackPlugin = require('copy-webpack-plugin') 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 7 | 8 | const { 9 | dependencies, 10 | devDependencies, 11 | productName, 12 | } = require('../package.json') 13 | 14 | const externals = Object.keys(dependencies).concat(Object.keys(devDependencies)) 15 | const isDevMode = process.env.NODE_ENV === 'development' 16 | const whiteListedModules = ['vue'] 17 | 18 | const config = { 19 | name: 'renderer', 20 | mode: process.env.NODE_ENV, 21 | devtool: isDevMode ? 'eval-source-map' : false, 22 | entry: { 23 | renderer: path.join(__dirname, '../src/renderer/main.js'), 24 | }, 25 | output: { 26 | libraryTarget: 'commonjs2', 27 | path: path.join(__dirname, '../dist'), 28 | filename: '[name].js', 29 | }, 30 | externals: externals.filter((d) => !whiteListedModules.includes(d)), 31 | module: { 32 | rules: [ 33 | { 34 | test: /\.tsx?$/, 35 | use: [ 36 | { 37 | loader: 'ts-loader', 38 | options: { 39 | appendTsSuffixTo: [/\.vue$/], 40 | }, 41 | }, 42 | ], 43 | exclude: /node_modules/, 44 | }, 45 | { 46 | test: /\.js$/, 47 | use: 'babel-loader', 48 | exclude: /node_modules/, 49 | }, 50 | { 51 | test: /\.node$/, 52 | use: 'node-loader', 53 | }, 54 | { 55 | test: /\.vue$/, 56 | loader: 'vue-loader', 57 | }, 58 | { 59 | test: /\.s(c|a)ss$/, 60 | use: [ 61 | { 62 | loader: MiniCssExtractPlugin.loader, 63 | }, 64 | { 65 | loader: 'css-loader', 66 | }, 67 | { 68 | loader: 'sass-loader', 69 | options: { 70 | // eslint-disable-next-line 71 | implementation: require('sass'), 72 | }, 73 | }, 74 | ], 75 | }, 76 | { 77 | test: /\.css$/, 78 | use: [ 79 | { 80 | loader: MiniCssExtractPlugin.loader, 81 | }, 82 | 'css-loader', 83 | ], 84 | }, 85 | { 86 | test: /\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\?.*)?$/, 87 | use: { 88 | loader: 'url-loader', 89 | options: { 90 | esModule: false, 91 | limit: 10000, 92 | name: 'imgs/[name]--[folder].[ext]', 93 | }, 94 | }, 95 | }, 96 | { 97 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 98 | use: { 99 | loader: 'url-loader', 100 | options: { 101 | esModule: false, 102 | limit: 10000, 103 | name: 'fonts/[name]--[folder].[ext]', 104 | }, 105 | }, 106 | }, 107 | ], 108 | }, 109 | node: { 110 | global: true, 111 | __dirname: isDevMode, 112 | __filename: isDevMode, 113 | }, 114 | plugins: [ 115 | // new WriteFilePlugin(), 116 | new HtmlWebpackPlugin({ 117 | excludeChunks: ['processTaskWorker'], 118 | filename: 'index.html', 119 | template: path.resolve(__dirname, '../src/index.ejs'), 120 | nodeModules: isDevMode 121 | ? path.resolve(__dirname, '../node_modules') 122 | : false, 123 | }), 124 | new VueLoaderPlugin(), 125 | new webpack.DefinePlugin({ 126 | 'process.env.PRODUCT_NAME': JSON.stringify(productName), 127 | }), 128 | new MiniCssExtractPlugin({ 129 | filename: '[name].css', 130 | chunkFilename: '[id].css', 131 | }), 132 | ], 133 | resolve: { 134 | alias: { 135 | vue$: 'vue/dist/vue.common.js', 136 | '@': path.join(__dirname, '../src/'), 137 | src: path.join(__dirname, '../src/'), 138 | icons: path.join(__dirname, '../_icons/'), 139 | }, 140 | extensions: ['.ts', '.js', '.vue', '.json'], 141 | }, 142 | target: 'electron-renderer', 143 | } 144 | 145 | /** 146 | * Adjust rendererConfig for production settings 147 | */ 148 | if (isDevMode) { 149 | // any dev only config 150 | config.plugins.push( 151 | new webpack.HotModuleReplacementPlugin(), 152 | new webpack.DefinePlugin({ 153 | __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, 154 | }) 155 | ) 156 | } else { 157 | config.plugins.push( 158 | new CopyWebpackPlugin({ 159 | patterns: [ 160 | { 161 | from: path.join(__dirname, '../static'), 162 | to: path.join(__dirname, '../dist/static'), 163 | globOptions: { 164 | ignore: ['.*'], 165 | }, 166 | }, 167 | ], 168 | }), 169 | new webpack.LoaderOptionsPlugin({ 170 | minimize: true, 171 | }) 172 | ) 173 | } 174 | 175 | module.exports = config 176 | -------------------------------------------------------------------------------- /src/renderer/assets/style/animations.scss: -------------------------------------------------------------------------------- 1 | /* Animation keyframes */ 2 | .animate-warn { 3 | animation-delay: 1s; 4 | animation-duration: 5s; 5 | animation-fill-mode: both; 6 | animation-iteration-count: infinite; 7 | animation-name: jump; 8 | transform-origin: 50%; 9 | will-change: transform; 10 | -webkit-animation-duration: 5s; 11 | -webkit-animation-fill-mode: both; 12 | -webkit-animation-name: jump; 13 | } 14 | 15 | .animate-danger { 16 | animation-delay: 1s; 17 | animation-duration: 5s; 18 | animation-fill-mode: both; 19 | animation-iteration-count: infinite; 20 | animation-name: shake; 21 | transform-origin: 50% 0; 22 | will-change: transform; 23 | -webkit-animation-duration: 5s; 24 | -webkit-animation-fill-mode: both; 25 | -webkit-animation-name: shake; 26 | } 27 | 28 | .animate-active { 29 | animation-delay: 1s; 30 | animation-duration: 5s; 31 | animation-fill-mode: both; 32 | animation-iteration-count: 1; 33 | animation-name: active; 34 | transform-origin: 50% 0; 35 | will-change: transform; 36 | -webkit-animation-duration: 5s; 37 | -webkit-animation-fill-mode: both; 38 | -webkit-animation-name: active; 39 | } 40 | 41 | @keyframes active { 42 | 0%, 43 | 100% { 44 | transform: rotate(0) scale(1); 45 | -webkit-transform: rotate(0) scale(1); 46 | } 47 | 50% { 48 | transform: rotate(0) scale(1.25); 49 | -webkit-transform: rotate(0) scale(1.25); 50 | } 51 | } 52 | 53 | @keyframes jump { 54 | 0%, 55 | 50%, 56 | 100% { 57 | transform: translateY(0); 58 | -webkit-transform: translateY(0); 59 | } 60 | 10%, 61 | 20%, 62 | 30%, 63 | 40% { 64 | transform: translateY(-3px); 65 | -webkit-transform: translateY(-3px); 66 | } 67 | 15%, 68 | 25%, 69 | 35%, 70 | 45% { 71 | transform: translateY(0); 72 | -webkit-transform: translateY(0); 73 | } 74 | } 75 | 76 | @keyframes shake { 77 | 0%, 78 | 100% { 79 | transform: translateX(0); 80 | -webkit-transform: translateX(0); 81 | } 82 | /* Fast Shake */ 83 | 1%, 84 | 3%, 85 | 5%, 86 | 7%, 87 | 9% { 88 | transform: translateX(-2px); 89 | -webkit-transform: translateX(-2px); 90 | } 91 | 2%, 92 | 4%, 93 | 6%, 94 | 8%, 95 | 10% { 96 | transform: translateX(2px); 97 | -webkit-transform: translateX(2px); 98 | } 99 | /* Medium Shake */ 100 | 12%, 101 | 16%, 102 | 20%, 103 | 24% { 104 | transform: translateX(-1px); 105 | -webkit-transform: translateX(-1px); 106 | } 107 | 14%, 108 | 18%, 109 | 22%, 110 | 26% { 111 | transform: translateX(1px); 112 | -webkit-transform: translateX(1px); 113 | } 114 | /* Slow Shake */ 115 | 30%, 116 | 38%, 117 | 46% { 118 | transform: translateX(-0.5px); 119 | -webkit-transform: translateX(-0.5px); 120 | } 121 | 34%, 122 | 42%, 123 | 50% { 124 | transform: translateX(0.5px); 125 | -webkit-transform: translateX(0.5px); 126 | } 127 | } 128 | 129 | /* Items List Transitions */ 130 | .list-in-enter-active, 131 | .list-in-leave-active { 132 | transition: all 0.25s ease; 133 | } 134 | 135 | .list-in-enter, 136 | .list-in-leave-to { 137 | opacity: 0; 138 | transform: scale(0.25); 139 | } 140 | 141 | /* List out */ 142 | .list-out-enter-active, 143 | .list-out-leave-active { 144 | transition: all 0.25s ease; 145 | } 146 | 147 | .list-out-enter, 148 | .list-out-leave-to { 149 | opacity: 0; 150 | transform: scale(1.5); 151 | } 152 | 153 | /* List out delayed */ 154 | .list-out-delayed-enter-active, 155 | .list-out-delayed-leave-active { 156 | transition: all 0.25s ease 0.1s; 157 | } 158 | 159 | .list-out-delayed-enter, 160 | .list-out-delayed-leave-to { 161 | opacity: 0; 162 | transform: scale(1.5); 163 | } 164 | 165 | /* Route change animations */ 166 | .slide-up-enter-active, 167 | .slide-up-leave-active { 168 | transition: all 0.25s ease-out; 169 | } 170 | 171 | .slide-up-enter, 172 | .slide-up-leave-to { 173 | opacity: 0; 174 | transform: translateY(-10px); 175 | } 176 | 177 | /* Route change animations */ 178 | .slide-down-enter-active, 179 | .slide-down-leave-active { 180 | transition: all 0.25s ease-out; 181 | } 182 | 183 | .slide-down-enter, 184 | .slide-down-leave-to { 185 | opacity: 0; 186 | transform: translateY(10px); 187 | } 188 | 189 | /* Test right */ 190 | .slide-right-enter-active, 191 | .slide-right-leave-active { 192 | transition: all 0.25s ease-out; 193 | } 194 | 195 | .slide-right-enter, 196 | .slide-right-leave-to { 197 | opacity: 0; 198 | transform: translateX(-10px); 199 | } 200 | 201 | /* Test left */ 202 | .slide-left-enter-active, 203 | .slide-left-leave-active { 204 | transition: all 0.25s ease-out; 205 | } 206 | 207 | .slide-left-enter, 208 | .slide-left-leave-to { 209 | opacity: 0; 210 | transform: translateX(10px); 211 | } 212 | 213 | /* List animation */ 214 | .list-complete-item { 215 | transition: all 0.25s; 216 | } 217 | 218 | .list-complete-enter, 219 | .list-complete-leave-to { 220 | opacity: 0; 221 | transform: translateY(30px); 222 | } 223 | 224 | .list-complete-leave-active { 225 | position: absolute; 226 | } 227 | 228 | /* Rotation */ 229 | @keyframes rotation { 230 | 0% { 231 | transform: rotate(0deg); 232 | } 233 | 100% { 234 | transform: rotate(360deg); 235 | } 236 | } 237 | 238 | .rotating { 239 | animation: rotation 0.5s infinite linear; 240 | } 241 | -------------------------------------------------------------------------------- /_scripts/webpack.web.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const HtmlWebpackPlugin = require('html-webpack-plugin') 4 | const VueLoaderPlugin = require('vue-loader/lib/plugin') 5 | const CopyWebpackPlugin = require('copy-webpack-plugin') 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin') 7 | 8 | const { productName } = require('../package.json') 9 | 10 | const isDevMode = process.env.NODE_ENV === 'development' 11 | 12 | const config = { 13 | name: 'web', 14 | mode: process.env.NODE_ENV, 15 | devtool: isDevMode ? 'eval-source-map' : false, 16 | entry: { 17 | web: path.join(__dirname, '../src/renderer/main.js'), 18 | }, 19 | output: { 20 | path: path.join(__dirname, '../dist/web'), 21 | filename: '[name].js', 22 | }, 23 | module: { 24 | rules: [ 25 | { 26 | test: /\.tsx?$/, 27 | use: [ 28 | { 29 | loader: 'ts-loader', 30 | options: { 31 | appendTsSuffixTo: [/\.vue$/], 32 | }, 33 | }, 34 | ], 35 | exclude: /node_modules/, 36 | }, 37 | { 38 | test: /\.js$/, 39 | use: 'babel-loader', 40 | exclude: /node_modules/, 41 | }, 42 | { 43 | test: /\.vue$/, 44 | use: { 45 | loader: 'vue-loader', 46 | options: { 47 | extractCSS: true, 48 | loaders: { 49 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', 50 | scss: 'vue-style-loader!css-loader!sass-loader', 51 | less: 'vue-style-loader!css-loader!less-loader', 52 | }, 53 | }, 54 | }, 55 | }, 56 | { 57 | test: /\.s(c|a)ss$/, 58 | use: [ 59 | { 60 | loader: MiniCssExtractPlugin.loader, 61 | }, 62 | { 63 | loader: 'css-loader', 64 | }, 65 | { 66 | loader: 'sass-loader', 67 | options: { 68 | // eslint-disable-next-line 69 | implementation: require('sass'), 70 | }, 71 | }, 72 | ], 73 | }, 74 | { 75 | test: /\.css$/, 76 | use: [ 77 | { 78 | loader: MiniCssExtractPlugin.loader, 79 | }, 80 | 'css-loader', 81 | ], 82 | }, 83 | { 84 | test: /\.html$/, 85 | use: 'vue-html-loader', 86 | }, 87 | { 88 | test: /\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\?.*)?$/, 89 | use: { 90 | loader: 'url-loader', 91 | options: { 92 | esModule: false, 93 | limit: 10000, 94 | name: 'imgs/[name]--[folder].[ext]', 95 | }, 96 | }, 97 | }, 98 | { 99 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 100 | use: { 101 | loader: 'url-loader', 102 | options: { 103 | esModule: false, 104 | limit: 10000, 105 | name: 'fonts/[name]--[folder].[ext]', 106 | }, 107 | }, 108 | }, 109 | ], 110 | }, 111 | node: { 112 | __dirname: isDevMode, 113 | __filename: isDevMode, 114 | }, 115 | resolve: { 116 | alias: { 117 | '@': path.join(__dirname, '../src/renderer'), 118 | vue$: 'vue/dist/vue.esm.js', 119 | src: path.join(__dirname, '../src/'), 120 | icons: path.join(__dirname, '../_icons/'), 121 | }, 122 | extensions: ['.ts', '.js', '.vue', '.json', '.css'], 123 | fallback: { 124 | // fs: false, 125 | // os: require.resolve('os-browserify/browser'), 126 | // path: require.resolve('path-browserify'), 127 | fs: false, 128 | os: false, 129 | path: false, 130 | }, 131 | }, 132 | plugins: [ 133 | // new WriteFilePlugin(), 134 | new HtmlWebpackPlugin({ 135 | excludeChunks: ['processTaskWorker'], 136 | filename: 'index.html', 137 | template: path.resolve(__dirname, '../src/index.ejs'), 138 | nodeModules: false, 139 | }), 140 | new VueLoaderPlugin(), 141 | new webpack.DefinePlugin({ 142 | 'process.env.PRODUCT_NAME': JSON.stringify(productName), 143 | }), 144 | new MiniCssExtractPlugin({ 145 | filename: '[name].css', 146 | chunkFilename: '[id].css', 147 | }), 148 | ], 149 | target: 'web', 150 | } 151 | 152 | /** 153 | * Adjust web for production settings 154 | */ 155 | if (isDevMode) { 156 | // any dev only config 157 | config.plugins.push( 158 | new webpack.HotModuleReplacementPlugin(), 159 | new webpack.DefinePlugin({ 160 | __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, 161 | }) 162 | ) 163 | } else { 164 | config.plugins.push( 165 | new CopyWebpackPlugin({ 166 | patterns: [ 167 | { 168 | from: path.join(__dirname, '../static'), 169 | to: path.join(__dirname, '../dist/static'), 170 | globOptions: { 171 | ignore: ['.*'], 172 | }, 173 | }, 174 | ], 175 | }), 176 | new webpack.LoaderOptionsPlugin({ 177 | minimize: true, 178 | }) 179 | ) 180 | } 181 | 182 | module.exports = config 183 | -------------------------------------------------------------------------------- /src/main/index.js: -------------------------------------------------------------------------------- 1 | import { app, BrowserWindow, Menu } from 'electron' 2 | import pkg from '../../package.json' 3 | 4 | require('@electron/remote/main').initialize() 5 | 6 | // set app name 7 | app.name = pkg.productName 8 | // to hide deprecation message 9 | app.allowRendererProcessReuse = true 10 | 11 | // disable electron warning 12 | process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = false 13 | 14 | const gotTheLock = app.requestSingleInstanceLock() 15 | const isDev = process.env.NODE_ENV === 'development' 16 | const isDebug = process.argv.includes('--debug') 17 | let mainWindow 18 | 19 | // only allow single instance of application 20 | if (!isDev) { 21 | if (gotTheLock) { 22 | app.on('second-instance', () => { 23 | // Someone tried to run a second instance, we should focus our window. 24 | if (mainWindow && mainWindow.isMinimized()) { 25 | mainWindow.restore() 26 | } 27 | mainWindow.focus() 28 | }) 29 | } else { 30 | app.quit() 31 | process.exit(0) 32 | } 33 | } else { 34 | // process.env.ELECTRON_ENABLE_LOGGING = true 35 | 36 | require('electron-debug')({ 37 | showDevTools: false, 38 | }) 39 | } 40 | 41 | async function installDevTools() { 42 | let installExtension = require('electron-devtools-installer') 43 | installExtension.default(installExtension.VUEJS_DEVTOOLS).catch((err) => { 44 | console.log('Unable to install `vue-devtools`: \n', err) 45 | }) 46 | } 47 | 48 | function createWindow() { 49 | /** 50 | * Initial window options 51 | */ 52 | mainWindow = new BrowserWindow({ 53 | backgroundColor: '#fff', 54 | width: 960, 55 | height: 540, 56 | minWidth: 960, 57 | minHeight: 540, 58 | // useContentSize: true, 59 | webPreferences: { 60 | nodeIntegration: true, 61 | nodeIntegrationInWorker: false, 62 | contextIsolation: false, 63 | webSecurity: false, 64 | }, 65 | show: false, 66 | }) 67 | 68 | // eslint-disable-next-line 69 | setMenu() 70 | 71 | // load root file/url 72 | if (isDev) { 73 | mainWindow.loadURL('http://localhost:9080') 74 | } else { 75 | mainWindow.loadFile(`${__dirname}/index.html`) 76 | 77 | global.__static = require('path') 78 | .join(__dirname, '/static') 79 | .replace(/\\/g, '\\\\') 80 | } 81 | 82 | // Show when loaded 83 | mainWindow.on('ready-to-show', () => { 84 | mainWindow.show() 85 | mainWindow.focus() 86 | }) 87 | 88 | mainWindow.on('closed', () => { 89 | console.log('\nApplication exiting...') 90 | }) 91 | } 92 | 93 | app.on('ready', () => { 94 | createWindow() 95 | 96 | if (isDev) { 97 | installDevTools() 98 | mainWindow.webContents.openDevTools() 99 | } 100 | 101 | if (isDebug) { 102 | mainWindow.webContents.openDevTools() 103 | } 104 | }) 105 | 106 | app.on('window-all-closed', () => { 107 | if (process.platform !== 'darwin') { 108 | app.quit() 109 | } 110 | }) 111 | 112 | app.on('activate', () => { 113 | if (mainWindow === null) { 114 | createWindow() 115 | } 116 | }) 117 | 118 | /** 119 | * Auto Updater 120 | * 121 | * Uncomment the following code below and install `electron-updater` to 122 | * support auto updating. Code Signing with a valid certificate is required. 123 | * https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating 124 | */ 125 | 126 | /* 127 | import { autoUpdater } from 'electron-updater' 128 | 129 | autoUpdater.on('update-downloaded', () => { 130 | autoUpdater.quitAndInstall() 131 | }) 132 | 133 | app.on('ready', () => { 134 | if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates() 135 | }) 136 | */ 137 | 138 | const sendMenuEvent = async (data) => { 139 | mainWindow.webContents.send('change-view', data) 140 | } 141 | 142 | const template = [ 143 | { 144 | label: app.name, 145 | submenu: [ 146 | { 147 | label: 'Home', 148 | accelerator: 'CommandOrControl+H', 149 | click() { 150 | sendMenuEvent({ route: '/' }) 151 | }, 152 | }, 153 | { type: 'separator' }, 154 | { role: 'minimize' }, 155 | { role: 'togglefullscreen' }, 156 | { type: 'separator' }, 157 | { role: 'quit', accelerator: 'Alt+F4' }, 158 | ], 159 | }, 160 | { 161 | role: 'help', 162 | submenu: [ 163 | { 164 | label: 'Get Help', 165 | role: 'help', 166 | accelerator: 'F1', 167 | click() { 168 | sendMenuEvent({ route: '/help' }) 169 | }, 170 | }, 171 | { 172 | label: 'About', 173 | role: 'about', 174 | accelerator: 'CommandOrControl+A', 175 | click() { 176 | sendMenuEvent({ route: '/about' }) 177 | }, 178 | }, 179 | ], 180 | }, 181 | ] 182 | 183 | function setMenu() { 184 | if (process.platform === 'darwin') { 185 | template.unshift({ 186 | label: app.name, 187 | submenu: [ 188 | { role: 'about' }, 189 | { type: 'separator' }, 190 | { role: 'services' }, 191 | { type: 'separator' }, 192 | { role: 'hide' }, 193 | { role: 'hideothers' }, 194 | { role: 'unhide' }, 195 | { type: 'separator' }, 196 | { role: 'quit' }, 197 | ], 198 | }) 199 | 200 | template.push({ 201 | role: 'window', 202 | }) 203 | 204 | template.push({ 205 | role: 'help', 206 | }) 207 | 208 | template.push({ role: 'services' }) 209 | } 210 | 211 | const menu = Menu.buildFromTemplate(template) 212 | Menu.setApplicationMenu(menu) 213 | } 214 | -------------------------------------------------------------------------------- /_icons/logotype1black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/logotype2black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/logotype1blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/logotype1white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/logotype2blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_icons/logotype2white.svg: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------