├── .npmrc
├── .gitattributes
├── .gitignore
├── app
├── templates
│ ├── gitattributes
│ ├── gitignore
│ ├── build
│ │ ├── icon.png
│ │ ├── background.png
│ │ └── background@2x.png
│ ├── static
│ │ └── icon.png
│ ├── config.js
│ ├── editorconfig
│ ├── index.html
│ ├── github
│ │ └── workflows
│ │ │ └── main.yml
│ ├── index.css
│ ├── readme.md
│ ├── license
│ ├── _package.json
│ ├── index.js
│ └── menu.js
└── index.js
├── screenshot.png
├── .editorconfig
├── .github
└── workflows
│ └── main.yml
├── test.js
├── license
├── package.json
└── readme.md
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn.lock
3 | temp
4 |
--------------------------------------------------------------------------------
/app/templates/gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/app/templates/gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | yarn.lock
3 | /dist
4 |
--------------------------------------------------------------------------------
/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sindresorhus/generator-electron/HEAD/screenshot.png
--------------------------------------------------------------------------------
/app/templates/build/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sindresorhus/generator-electron/HEAD/app/templates/build/icon.png
--------------------------------------------------------------------------------
/app/templates/static/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sindresorhus/generator-electron/HEAD/app/templates/static/icon.png
--------------------------------------------------------------------------------
/app/templates/build/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sindresorhus/generator-electron/HEAD/app/templates/build/background.png
--------------------------------------------------------------------------------
/app/templates/build/background@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sindresorhus/generator-electron/HEAD/app/templates/build/background@2x.png
--------------------------------------------------------------------------------
/app/templates/config.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const Store = require('electron-store');
3 |
4 | module.exports = new Store({
5 | defaults: {
6 | favoriteAnimal: '🦄',
7 | },
8 | });
9 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.yml]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/app/templates/editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = tab
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 |
10 | [*.yml]
11 | indent_style = space
12 | indent_size = 2
13 |
--------------------------------------------------------------------------------
/app/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | <%= appName %>
6 |
7 |
8 |
9 |
10 |
11 | <%= appName %>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/app/templates/github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | - push
4 | - pull_request
5 | jobs:
6 | test:
7 | name: Node.js ${{ matrix.node-version }}
8 | runs-on: macos-latest
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | node-version:
13 | - 16
14 | steps:
15 | - uses: actions/checkout@v3
16 | - uses: actions/setup-node@v3
17 | with:
18 | node-version: ${{ matrix.node-version }}
19 | - run: npm install
20 | - run: npm test
21 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | - push
4 | - pull_request
5 | jobs:
6 | test:
7 | name: Node.js ${{ matrix.node-version }}
8 | runs-on: ubuntu-latest
9 | strategy:
10 | fail-fast: false
11 | matrix:
12 | node-version:
13 | - 14
14 | - 12
15 | - 10
16 | - 8
17 | steps:
18 | - uses: actions/checkout@v4
19 | - uses: actions/setup-node@v4
20 | with:
21 | node-version: ${{ matrix.node-version }}
22 | - run: npm install
23 | - run: npm test
24 |
--------------------------------------------------------------------------------
/app/templates/index.css:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | padding: 0;
4 | margin: 0;
5 | background: transparent;
6 | }
7 |
8 | /* Use OS default fonts */
9 | body {
10 | font-family:
11 | system-ui,
12 | -apple-system,
13 | 'Segoe UI',
14 | Roboto,
15 | Helvetica,
16 | Arial,
17 | sans-serif,
18 | 'Apple Color Emoji',
19 | 'Segoe UI Emoji';
20 | text-rendering: optimizeLegibility;
21 | font-feature-settings: 'liga', 'clig', 'kern';
22 | }
23 |
24 | header {
25 | position: absolute;
26 | width: 500px;
27 | height: 250px;
28 | top: 50%;
29 | left: 50%;
30 | margin-top: -125px;
31 | margin-left: -250px;
32 | text-align: center;
33 | }
34 |
35 | header h1 {
36 | font-size: 60px;
37 | font-weight: 200;
38 | margin: 0;
39 | padding: 0;
40 | opacity: 0.7;
41 | }
42 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | import {promisify} from 'util';
2 | import path from 'path';
3 | import {serial as test} from 'ava';
4 | import helpers from 'yeoman-test';
5 | import assert from 'yeoman-assert';
6 |
7 | let generator;
8 |
9 | test.beforeEach(async () => {
10 | await promisify(helpers.testDirectory)(path.join(__dirname, 'temp'));
11 | generator = helpers.createGenerator('electron:app', ['../app'], undefined, {skipInstall: true});
12 | });
13 |
14 | test('generates expected files', async () => {
15 | helpers.mockPrompt(generator, {
16 | appName: 'test',
17 | githubUsername: 'test',
18 | website: 'test.com'
19 | });
20 |
21 | await generator.run();
22 |
23 | assert.file([
24 | '.editorconfig',
25 | '.gitattributes',
26 | '.gitignore',
27 | 'index.js',
28 | 'index.html',
29 | 'index.css',
30 | 'license',
31 | 'package.json',
32 | 'readme.md'
33 | ]);
34 | });
35 |
--------------------------------------------------------------------------------
/app/templates/readme.md:
--------------------------------------------------------------------------------
1 | # <%= appName %>
2 |
3 | > My <%= superb %> app
4 |
5 | ## Install
6 |
7 | *macOS 10.13+, Linux, and Windows 7+ are supported (64-bit only).*
8 |
9 | **macOS**
10 |
11 | [**Download**](<%= repoUrl %>/releases/latest) the `.dmg` file.
12 |
13 | **Linux**
14 |
15 | [**Download**](<%= repoUrl %>/releases/latest) the `.AppImage` or `.deb` file.
16 |
17 | *The AppImage needs to be [made executable](https://discourse.appimage.org/t/how-to-make-an-appimage-executable/80) after download.*
18 |
19 | **Windows**
20 |
21 | [**Download**](<%= repoUrl %>/releases/latest) the `.exe` file.
22 |
23 | ---
24 |
25 | ## Dev
26 |
27 | Built with [Electron](https://electronjs.org).
28 |
29 | ### Run
30 |
31 | ```sh
32 | npm install
33 | npm start
34 | ```
35 |
36 | ### Publish
37 |
38 | ```sh
39 | npm run release
40 | ```
41 |
42 | After the app is built, open the release draft it created and click "Publish".
43 |
--------------------------------------------------------------------------------
/app/templates/license:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) <%= name %> <<%= email %>> (<%= website %>)
4 |
5 | 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:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | 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.
10 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Sindre Sorhus (https://sindresorhus.com)
4 |
5 | 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:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | 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.
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "generator-electron",
3 | "version": "2.4.0",
4 | "description": "Scaffold out an Electron app",
5 | "license": "MIT",
6 | "repository": "sindresorhus/generator-electron",
7 | "funding": "https://github.com/sponsors/sindresorhus",
8 | "author": {
9 | "name": "Sindre Sorhus",
10 | "email": "sindresorhus@gmail.com",
11 | "url": "https://sindresorhus.com"
12 | },
13 | "sideEffects": false,
14 | "engines": {
15 | "node": ">=8"
16 | },
17 | "scripts": {
18 | "test": "xo && ava"
19 | },
20 | "files": [
21 | "app"
22 | ],
23 | "keywords": [
24 | "yeoman-generator",
25 | "boilerplate",
26 | "template",
27 | "scaffold",
28 | "node",
29 | "desktop",
30 | "app",
31 | "application",
32 | "electron"
33 | ],
34 | "dependencies": {
35 | "humanize-url": "^2.1.0",
36 | "normalize-url": "^4.3.0",
37 | "superb": "^4.0.0",
38 | "underscore.string": "^3.0.3",
39 | "yeoman-generator": "^4.0.2"
40 | },
41 | "devDependencies": {
42 | "ava": "^2.3.0",
43 | "xo": "^0.25.3",
44 | "yeoman-assert": "^3.0.0",
45 | "yeoman-test": "^2.0.0"
46 | },
47 | "xo": {
48 | "ignores": [
49 | "app/templates/**"
50 | ]
51 | },
52 | "ava": {
53 | "failWithoutAssertions": false
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # generator-electron
2 |
3 | > Scaffold out an Electron app
4 |
5 | See [awesome-electron](https://github.com/sindresorhus/awesome-electron) for more useful Electron resources.
6 |
7 | See [Caprine](https://github.com/sindresorhus/caprine) for a production app based on this boilerplate.
8 |
9 |
10 | ## Features
11 |
12 | - [`electron-builder`](https://www.electron.build) fully set up to create cross-platform builds
13 | - [Builds the app on Travis](https://www.electron.build/multi-platform-build.html)
14 | - [Silent auto-updates](https://www.electron.build/auto-update.html)
15 | - App menu that adheres to the system user interface guidelines
16 | - [Config handling](https://github.com/sindresorhus/electron-store)
17 | - [Context menu](https://github.com/sindresorhus/electron-context-menu)
18 | - [User-friendly handling of unhandled errors](https://github.com/sindresorhus/electron-unhandled)
19 | - Easily publish new versions to GitHub Releases
20 | - And much more!
21 |
22 |
23 | ## Install
24 |
25 | ```sh
26 | npm install --global yo generator-electron
27 | ```
28 |
29 |
30 | ## Usage
31 |
32 | With [yo](https://github.com/yeoman/yo):
33 |
34 | ```
35 | $ yo electron
36 | ```
37 |
38 |
39 | ## Related
40 |
41 | - [electron-boilerplate](https://github.com/sindresorhus/electron-boilerplate) - Electron app boilerplate
42 |
--------------------------------------------------------------------------------
/app/templates/_package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "<%= slugifiedAppName %>",
3 | "productName": "<%= appName %>",
4 | "version": "0.0.0",
5 | "description": "My <%= superb %> app",
6 | "license": "MIT",
7 | "repository": "<%= githubUsername %>/<%= slugifiedAppName %>",
8 | "author": {
9 | "name": "<%= name %>",
10 | "email": "<%= email %>",
11 | "url": "<%= humanizedWebsite %>"
12 | },
13 | "scripts": {
14 | "postinstall": "electron-builder install-app-deps",
15 | "lint": "xo",
16 | "test": "npm run lint",
17 | "start": "electron .",
18 | "pack": "electron-builder --dir",
19 | "dist": "electron-builder --macos --linux --windows",
20 | "release": "np"
21 | },
22 | "dependencies": {
23 | "electron-context-menu": "^3.4.0",
24 | "electron-debug": "^3.2.0",
25 | "electron-store": "^8.1.0",
26 | "electron-unhandled": "^4.0.1",
27 | "electron-updater": "^5.2.1",
28 | "electron-util": "^0.17.2"
29 | },
30 | "devDependencies": {
31 | "electron": "^13.0.0",
32 | "electron-builder": "^23.3.3",
33 | "np": "^7.6.2",
34 | "xo": "^0.51.0"
35 | },
36 | "xo": {
37 | "envs": [
38 | "node",
39 | "browser"
40 | ],
41 | "rules": {
42 | "unicorn/prefer-module": "off"
43 | }
44 | },
45 | "np": {
46 | "publish": false,
47 | "releaseDraft": false
48 | },
49 | "build": {
50 | "appId": "com.<%= githubUsername %>.<%= slugifiedAppName %>",
51 | "mac": {
52 | "category": "public.app-category.social-networking",
53 | "darkModeSupport": true
54 | },
55 | "dmg": {
56 | "iconSize": 160,
57 | "contents": [
58 | {
59 | "x": 180,
60 | "y": 170
61 | },
62 | {
63 | "x": 480,
64 | "y": 170,
65 | "type": "link",
66 | "path": "/Applications"
67 | }
68 | ]
69 | },
70 | "linux": {
71 | "target": [
72 | "AppImage",
73 | "deb"
74 | ],
75 | "category": "Network;Chat"
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/app/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const superb = require('superb');
3 | const normalizeUrl = require('normalize-url');
4 | const humanizeUrl = require('humanize-url');
5 | const Generator = require('yeoman-generator');
6 | const _s = require('underscore.string');
7 |
8 | module.exports = class extends Generator {
9 | async init() {
10 | const props = await this.prompt([{
11 | name: 'appName',
12 | message: 'What do you want to name your app?',
13 | default: this.appname
14 | }, {
15 | name: 'githubUsername',
16 | message: 'What is your GitHub username?',
17 | store: true,
18 | validate: x => x.length > 0 ? true : 'You have to provide a username'
19 | }, {
20 | name: 'website',
21 | message: 'What is the URL of your website?',
22 | store: true,
23 | validate: x => x.length > 0 ? true : 'You have to provide a website URL',
24 | filter: x => normalizeUrl(x)
25 | }]);
26 |
27 | const template = {
28 | appName: props.appName,
29 | slugifiedAppName: _s.slugify(props.appName),
30 | classifiedAppName: _s.classify(props.appName),
31 | githubUsername: props.githubUsername,
32 | repoUrl: `https://github.com/${props.githubUsername}/${props.slugifiedAppName}`,
33 | name: this.user.git.name(),
34 | email: this.user.git.email(),
35 | website: props.website,
36 | humanizedWebsite: humanizeUrl(props.website),
37 | superb: superb.random()
38 | };
39 |
40 | const moveDest = (from, to) => {
41 | this.fs.move(this.destinationPath(from), this.destinationPath(to));
42 | };
43 |
44 | const copy = (from, to) => {
45 | this.fs.copy(this.templatePath(from), this.destinationPath(to || from));
46 | };
47 |
48 | this.fs.copyTpl(`${this.templatePath()}/*`, this.destinationPath(), template);
49 | copy('build');
50 | copy('static');
51 | copy('github/workflows/main.yml', '.github/workflows/main.yml');
52 | moveDest('editorconfig', '.editorconfig');
53 | moveDest('gitattributes', '.gitattributes');
54 | moveDest('gitignore', '.gitignore');
55 | moveDest('_package.json', 'package.json');
56 | }
57 |
58 | install() {
59 | this.installDependencies({bower: false});
60 | }
61 | };
62 |
--------------------------------------------------------------------------------
/app/templates/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const path = require('path');
3 | const {app, BrowserWindow, Menu} = require('electron');
4 | /// const {autoUpdater} = require('electron-updater');
5 | const {is} = require('electron-util');
6 | const unhandled = require('electron-unhandled');
7 | const debug = require('electron-debug');
8 | const contextMenu = require('electron-context-menu');
9 | const config = require('./config.js');
10 | const menu = require('./menu.js');
11 | const packageJson = require('./package.json');
12 |
13 | unhandled();
14 | debug();
15 | contextMenu();
16 |
17 | app.setAppUserModelId(packageJson.build.appId);
18 |
19 | // Uncomment this before publishing your first version.
20 | // It's commented out as it throws an error if there are no published versions.
21 | // if (!is.development) {
22 | // const FOUR_HOURS = 1000 * 60 * 60 * 4;
23 | // setInterval(() => {
24 | // autoUpdater.checkForUpdates();
25 | // }, FOUR_HOURS);
26 | //
27 | // autoUpdater.checkForUpdates();
28 | // }
29 |
30 | // Prevent window from being garbage collected
31 | let mainWindow;
32 |
33 | const createMainWindow = async () => {
34 | const window_ = new BrowserWindow({
35 | title: app.name,
36 | show: false,
37 | width: 600,
38 | height: 400,
39 | });
40 |
41 | window_.on('ready-to-show', () => {
42 | window_.show();
43 | });
44 |
45 | window_.on('closed', () => {
46 | // Dereference the window
47 | // For multiple windows store them in an array
48 | mainWindow = undefined;
49 | });
50 |
51 | await window_.loadFile(path.join(__dirname, 'index.html'));
52 |
53 | return window_;
54 | };
55 |
56 | // Prevent multiple instances of the app
57 | if (!app.requestSingleInstanceLock()) {
58 | app.quit();
59 | }
60 |
61 | app.on('second-instance', () => {
62 | if (mainWindow) {
63 | if (mainWindow.isMinimized()) {
64 | mainWindow.restore();
65 | }
66 |
67 | mainWindow.show();
68 | }
69 | });
70 |
71 | app.on('window-all-closed', () => {
72 | if (!is.macos) {
73 | app.quit();
74 | }
75 | });
76 |
77 | app.on('activate', () => {
78 | if (!mainWindow) {
79 | mainWindow = createMainWindow();
80 | }
81 | });
82 |
83 | (async () => {
84 | await app.whenReady();
85 | Menu.setApplicationMenu(menu);
86 | mainWindow = await createMainWindow();
87 |
88 | const favoriteAnimal = config.get('favoriteAnimal');
89 | mainWindow.webContents.executeJavaScript(`document.querySelector('header p').textContent = 'Your favorite animal is ${favoriteAnimal}'`);
90 | })();
91 |
--------------------------------------------------------------------------------
/app/templates/menu.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const path = require('path');
3 | const {app, Menu, shell} = require('electron');
4 | const {
5 | is,
6 | appMenu,
7 | aboutMenuItem,
8 | openUrlMenuItem,
9 | openNewGitHubIssue,
10 | debugInfo,
11 | } = require('electron-util');
12 | const config = require('./config.js');
13 |
14 | const showPreferences = () => {
15 | // Show the app's preferences here
16 | };
17 |
18 | const helpSubmenu = [
19 | openUrlMenuItem({
20 | label: 'Website',
21 | url: '<%= repoUrl %>',
22 | }),
23 | openUrlMenuItem({
24 | label: 'Source Code',
25 | url: '<%= repoUrl %>',
26 | }),
27 | {
28 | label: 'Report an Issue…',
29 | click() {
30 | const body = `
31 |
32 |
33 |
34 | ---
35 |
36 | ${debugInfo()}`;
37 |
38 | openNewGitHubIssue({
39 | user: '<%= githubUsername %>',
40 | repo: '<%= slugifiedAppName %>',
41 | body,
42 | });
43 | },
44 | },
45 | ];
46 |
47 | if (!is.macos) {
48 | helpSubmenu.push(
49 | {
50 | type: 'separator',
51 | },
52 | aboutMenuItem({
53 | icon: path.join(__dirname, 'static', 'icon.png'),
54 | text: 'Created by <%= name %>',
55 | }),
56 | );
57 | }
58 |
59 | const debugSubmenu = [
60 | {
61 | label: 'Show Settings',
62 | click() {
63 | config.openInEditor();
64 | },
65 | },
66 | {
67 | label: 'Show App Data',
68 | click() {
69 | shell.openItem(app.getPath('userData'));
70 | },
71 | },
72 | {
73 | type: 'separator',
74 | },
75 | {
76 | label: 'Delete Settings',
77 | click() {
78 | config.clear();
79 | app.relaunch();
80 | app.quit();
81 | },
82 | },
83 | {
84 | label: 'Delete App Data',
85 | click() {
86 | shell.moveItemToTrash(app.getPath('userData'));
87 | app.relaunch();
88 | app.quit();
89 | },
90 | },
91 | ];
92 |
93 | const macosTemplate = [
94 | appMenu([
95 | {
96 | label: 'Preferences…',
97 | accelerator: 'Command+,',
98 | click() {
99 | showPreferences();
100 | },
101 | },
102 | ]),
103 | {
104 | role: 'fileMenu',
105 | submenu: [
106 | {
107 | label: 'Custom',
108 | },
109 | {
110 | type: 'separator',
111 | },
112 | {
113 | role: 'close',
114 | },
115 | ],
116 | },
117 | {
118 | role: 'editMenu',
119 | },
120 | {
121 | role: 'viewMenu',
122 | },
123 | {
124 | role: 'windowMenu',
125 | },
126 | {
127 | role: 'help',
128 | submenu: helpSubmenu,
129 | },
130 | ];
131 |
132 | // Linux and Windows
133 | const otherTemplate = [
134 | {
135 | role: 'fileMenu',
136 | submenu: [
137 | {
138 | label: 'Custom',
139 | },
140 | {
141 | type: 'separator',
142 | },
143 | {
144 | label: 'Settings',
145 | accelerator: 'Control+,',
146 | click() {
147 | showPreferences();
148 | },
149 | },
150 | {
151 | type: 'separator',
152 | },
153 | {
154 | role: 'quit',
155 | },
156 | ],
157 | },
158 | {
159 | role: 'editMenu',
160 | },
161 | {
162 | role: 'viewMenu',
163 | },
164 | {
165 | role: 'help',
166 | submenu: helpSubmenu,
167 | },
168 | ];
169 |
170 | const template = is.macos ? macosTemplate : otherTemplate;
171 |
172 | if (is.development) {
173 | template.push({
174 | label: 'Debug',
175 | submenu: debugSubmenu,
176 | });
177 | }
178 |
179 | module.exports = Menu.buildFromTemplate(template);
180 |
--------------------------------------------------------------------------------