;
14 | });
15 |
16 | var _navbar = runtime.routes.filter(function (r) {
17 | return r.navbar;
18 | });
19 |
20 | const App = React.createClass({
21 | mixins: [ Navigation ],
22 |
23 | componentDidMount() {
24 | var ipc = window.require('ipc');
25 | ipc.on('transitionTo', function(routeName) {
26 | //this.transitionTo(routeName, { the: 'params' }, { the: 'query' });
27 | this.transitionTo(routeName);
28 | }.bind(this));
29 | },
30 |
31 | render() {
32 | var links = _navbar.map(function (r) {
33 | return (
34 | {r.text}
35 | );
36 | });
37 | return (
38 |
39 |
40 |
48 |
49 |
50 |
51 |
52 | );
53 | }
54 | });
55 |
56 | var routes = (
57 |
58 |
59 |
60 |
61 | { _routes }
62 |
63 | );
64 |
65 | Router.run(routes, function (Handler) {
66 | React.render(, document.body);
67 | });
68 |
--------------------------------------------------------------------------------
/components/pages/AboutPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class AboutPage extends React.Component {
4 |
5 | render() {
6 | return (
7 | About Page
8 | );
9 | }
10 |
11 | }
12 |
13 | export default AboutPage;
14 |
--------------------------------------------------------------------------------
/components/pages/ContactPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class ContactPage extends React.Component {
4 |
5 | render() {
6 | return (
7 | Contact Page
8 | );
9 | }
10 |
11 | }
12 |
13 | export default ContactPage;
14 |
--------------------------------------------------------------------------------
/components/pages/HomePage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class HomePage extends React.Component {
4 |
5 | render() {
6 | return (
7 | Home Page
8 | );
9 | }
10 |
11 | }
12 |
13 | export default HomePage;
14 |
--------------------------------------------------------------------------------
/components/pages/index.js:
--------------------------------------------------------------------------------
1 | import HomePage from './HomePage';
2 | import AboutPage from './AboutPage';
3 | import ContactPage from './ContactPage';
4 |
5 | export default {
6 | HomePage,
7 | AboutPage,
8 | ContactPage
9 | };
10 |
--------------------------------------------------------------------------------
/core/app-menu/index.js:
--------------------------------------------------------------------------------
1 | var menu = null;
2 |
3 | if (process.platform === 'darwin') {
4 | menu = require('./menu-mac');
5 | } else {
6 | menu = require('./menu-win');
7 | }
8 |
9 | module.exports = menu;
10 |
--------------------------------------------------------------------------------
/core/app-menu/menu-mac.js:
--------------------------------------------------------------------------------
1 | var app = require('app'),
2 | BrowserWindow = require('browser-window'),
3 | runtime = require('../runtime');
4 |
5 | function getMainWindow () {
6 | var id = runtime.windowId;
7 |
8 | if (id) {
9 | var instance = BrowserWindow.fromId(id);
10 | return instance;
11 | }
12 |
13 | return null;
14 | }
15 |
16 | var _App = {
17 | label: 'Electron',
18 | submenu: [
19 | {
20 | label: 'About Electron',
21 | selector: 'orderFrontStandardAboutPanel:'
22 | },
23 | {
24 | type: 'separator'
25 | },
26 | {
27 | label: 'Services',
28 | submenu: []
29 | },
30 | {
31 | type: 'separator'
32 | },
33 | {
34 | label: 'Hide Electron',
35 | accelerator: 'Command+H',
36 | selector: 'hide:'
37 | },
38 | {
39 | label: 'Hide Others',
40 | accelerator: 'Command+Shift+H',
41 | selector: 'hideOtherApplications:'
42 | },
43 | {
44 | label: 'Show All',
45 | selector: 'unhideAllApplications:'
46 | },
47 | {
48 | type: 'separator'
49 | },
50 | {
51 | label: 'Quit',
52 | accelerator: 'Command+Q',
53 | click: function () {
54 | app.quit();
55 | }
56 | },
57 | ]
58 | };
59 |
60 | var _Edit = {
61 | label: 'Edit',
62 | submenu: [
63 | {
64 | label: 'Undo',
65 | accelerator: 'Command+Z',
66 | selector: 'undo:'
67 | },
68 | {
69 | label: 'Redo',
70 | accelerator: 'Shift+Command+Z',
71 | selector: 'redo:'
72 | },
73 | {
74 | type: 'separator'
75 | },
76 | {
77 | label: 'Cut',
78 | accelerator: 'Command+X',
79 | selector: 'cut:'
80 | },
81 | {
82 | label: 'Copy',
83 | accelerator: 'Command+C',
84 | selector: 'copy:'
85 | },
86 | {
87 | label: 'Paste',
88 | accelerator: 'Command+V',
89 | selector: 'paste:'
90 | },
91 | {
92 | label: 'Select All',
93 | accelerator: 'Command+A',
94 | selector: 'selectAll:'
95 | },
96 | ]
97 | };
98 |
99 | var _Page = {
100 | label: 'Page',
101 | submenu: [
102 | {
103 | label: 'Home',
104 | click: function () {
105 | var mainWindow = getMainWindow();
106 | if (mainWindow) {
107 | mainWindow.webContents.send('transitionTo', 'home');
108 | }
109 | }
110 | },
111 | {
112 | label: 'About',
113 | click: function () {
114 | var mainWindow = getMainWindow();
115 | if (mainWindow) {
116 | mainWindow.webContents.send('transitionTo', 'about');
117 | }
118 | }
119 | },
120 | {
121 | label: 'Contact',
122 | click: function () {
123 | var mainWindow = getMainWindow();
124 | if (mainWindow) {
125 | mainWindow.webContents.send('transitionTo', 'contact');
126 | }
127 | }
128 | }
129 | ]
130 | };
131 |
132 | var _View = {
133 | label: 'View',
134 | submenu: [
135 | {
136 | label: 'Toggle Fullscreen',
137 | click: function () {
138 | var mainWindow = getMainWindow();
139 | if (mainWindow) {
140 | mainWindow.setFullScreen(!mainWindow.isFullScreen());
141 | }
142 | }
143 | }
144 | ]
145 | };
146 |
147 | var _Window = {
148 | label: 'Window',
149 | submenu: [
150 | {
151 | label: 'Minimize',
152 | accelerator: 'Command+M',
153 | selector: 'performMiniaturize:'
154 | },
155 | {
156 | label: 'Close',
157 | accelerator: 'Command+W',
158 | selector: 'performClose:'
159 | },
160 | {
161 | type: 'separator'
162 | },
163 | {
164 | label: 'Bring All to Front',
165 | selector: 'arrangeInFront:'
166 | },
167 | ]
168 | };
169 |
170 | var menu = {
171 | App: _App,
172 | Edit: _Edit,
173 | Page: _Page,
174 | View: _View,
175 | Window: _Window,
176 | template: [
177 | _App,
178 | _Edit,
179 | _Page,
180 | _View,
181 | _Window
182 | ]
183 | };
184 |
185 | module.exports = menu;
186 |
--------------------------------------------------------------------------------
/core/app-menu/menu-win.js:
--------------------------------------------------------------------------------
1 | var app = require('app'),
2 | BrowserWindow = require('browser-window'),
3 | runtime = require('../runtime');
4 |
5 | function getMainWindow() {
6 | var id = runtime.windowId;
7 |
8 | if (id) {
9 | var instance = BrowserWindow.fromId(id);
10 | return instance;
11 | }
12 |
13 | return null;
14 | }
15 |
16 | var _File = {
17 | label: '&File',
18 | submenu: [
19 | {
20 | label: '&Open',
21 | accelerator: 'Ctrl+O',
22 | },
23 | {
24 | label: '&Close',
25 | accelerator: 'Ctrl+W',
26 | click: function() {
27 | var mainWindow = getMainWindow();
28 | if (mainWindow) {
29 | mainWindow.close();
30 | }
31 | }
32 | },
33 | ]
34 | };
35 |
36 | var _Page = {
37 | label: 'Page',
38 | submenu: [
39 | {
40 | label: 'Home',
41 | click: function () {
42 | var mainWindow = getMainWindow();
43 | if (mainWindow) {
44 | mainWindow.webContents.send('transitionTo', 'home');
45 | }
46 | }
47 | },
48 | {
49 | label: 'About',
50 | click: function () {
51 | var mainWindow = getMainWindow();
52 | if (mainWindow) {
53 | mainWindow.webContents.send('transitionTo', 'about');
54 | }
55 | }
56 | },
57 | {
58 | label: 'Contact',
59 | click: function () {
60 | var mainWindow = getMainWindow();
61 | if (mainWindow) {
62 | mainWindow.webContents.send('transitionTo', 'contact');
63 | }
64 | }
65 | }
66 | ]
67 | };
68 |
69 | var _View = {
70 | label: '&View',
71 | submenu: [
72 | {
73 | label: 'Toggle &Fullscreen',
74 | click: function() {
75 | var mainWindow = getMainWindow();
76 | if (mainWindow) {
77 | mainWindow.setFullScreen(!mainWindow.isFullScreen());
78 | }
79 | }
80 | }
81 | ]
82 | };
83 |
84 | var menu = {
85 | File: _File,
86 | Page: _Page,
87 | View: _View,
88 | template: [
89 | _File,
90 | _Page,
91 | _View,
92 | ]
93 | };
94 |
95 | module.exports = menu;
96 |
--------------------------------------------------------------------------------
/core/modules/devtools/index.js:
--------------------------------------------------------------------------------
1 | function setupAppMenu (runtime, appMenu) {
2 |
3 | var mainWindow = runtime.getMainWindow();
4 |
5 | appMenu.View.submenu.push({
6 | label: '&Reload',
7 | accelerator: 'CmdOrCtrl+R',
8 | click: function () {
9 | mainWindow.restart();
10 | }
11 | });
12 |
13 | appMenu.View.submenu.push({
14 | label: '&Toggle Developer Tools',
15 | accelerator: 'Alt+CmdOrCtrl+I',
16 | click: function () {
17 | mainWindow.toggleDevTools();
18 | }
19 | });
20 | }
21 |
22 | var init = function (runtime) {
23 | if (runtime) {
24 | runtime.once(runtime.events.INIT_APP_MENU, function (appMenu) {
25 | setupAppMenu(runtime, appMenu);
26 | });
27 | }
28 | };
29 |
30 | module.exports = init;
31 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/dist/components/header.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 | var React = require('react');
3 |
4 | var MyHeader = React.createClass({displayName: "MyHeader",
5 |
6 | render: function() {
7 | return (
8 | React.createElement("h2", null, "Header")
9 | );
10 | }
11 |
12 | });
13 |
14 | module.exports = MyHeader;
15 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/dist/components/page1.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var Header = require('./header');
5 |
6 | var Page1 = React.createClass({displayName: "Page1",
7 |
8 | render: function() {
9 | return (
10 | React.createElement("div", null,
11 | React.createElement(Header, null),
12 | React.createElement("div", null, "Page 1 Content"),
13 | React.createElement("small", null, "This page was loaded from external module.")
14 | )
15 | );
16 | }
17 |
18 | });
19 |
20 | module.exports = Page1;
21 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/dist/components/page2.js:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var Header = require('./header');
5 |
6 | var Page2 = React.createClass({displayName: "Page2",
7 |
8 | render: function() {
9 | return (
10 | React.createElement("div", null,
11 | React.createElement(Header, null),
12 | React.createElement("div", null, "Page 2 Content"),
13 | React.createElement("small", null, "This page was loaded from external module.")
14 | )
15 | );
16 | }
17 |
18 | });
19 |
20 | module.exports = Page2;
21 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | var init = function (runtime) {
4 | if (runtime) {
5 | // setup routes
6 | runtime.once(runtime.events.INIT_ROUTES, function () {
7 | runtime.routes.push({
8 | route: 'test1',
9 | text: 'Test 1',
10 | navbar: true,
11 | handler: path.join(__dirname, '/dist/components/page1')
12 | });
13 | runtime.routes.push({
14 | route: 'test2',
15 | text: 'Test 2',
16 | navbar: true,
17 | handler: path.join(__dirname, '/dist/components/page2')
18 | });
19 | });
20 | }
21 | };
22 |
23 | module.exports = init;
24 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/src/components/header.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 | var React = require('react');
3 |
4 | var MyHeader = React.createClass({
5 |
6 | render: function() {
7 | return (
8 | Header
9 | );
10 | }
11 |
12 | });
13 |
14 | module.exports = MyHeader;
15 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/src/components/page1.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var Header = require('./header');
5 |
6 | var Page1 = React.createClass({
7 |
8 | render: function() {
9 | return (
10 |
11 |
12 |
Page 1 Content
13 |
This page was loaded from external module.
14 |
15 | );
16 | }
17 |
18 | });
19 |
20 | module.exports = Page1;
21 |
--------------------------------------------------------------------------------
/core/modules/extra-pages/src/components/page2.jsx:
--------------------------------------------------------------------------------
1 | /** @jsx React.DOM */
2 |
3 | var React = require('react');
4 | var Header = require('./header');
5 |
6 | var Page2 = React.createClass({
7 |
8 | render: function() {
9 | return (
10 |
11 |
12 |
Page 2 Content
13 |
This page was loaded from external module.
14 |
15 | );
16 | }
17 |
18 | });
19 |
20 | module.exports = Page2;
21 |
--------------------------------------------------------------------------------
/core/modules/help-md/content/folder/page2.md:
--------------------------------------------------------------------------------
1 | # Page2.md
2 | _This page is stored within a folder._
3 |
4 | Markdown content for page 2 comes here...
5 |
--------------------------------------------------------------------------------
/core/modules/help-md/content/index.md:
--------------------------------------------------------------------------------
1 | ## Index.md
2 |
3 | This is just a simple example of markdown content.
4 |
5 | [Page 1](page1)
6 |
7 | [Page 2](folder/page2)
8 |
--------------------------------------------------------------------------------
/core/modules/help-md/content/page1.md:
--------------------------------------------------------------------------------
1 | # Page1.md
2 |
3 | Markdown content for page 1 comes here...
4 |
--------------------------------------------------------------------------------
/core/modules/help-md/dist/components/help.js:
--------------------------------------------------------------------------------
1 | var React = require('react'),
2 | fs = require('fs'),
3 | path = require('path');
4 |
5 | var md = require('markdown-it')({
6 | replaceLink: function (link, env) {
7 | return '#/help?page=' + link;
8 | }
9 | }).use(require('markdown-it-replace-link'));
10 |
11 | var Help = React.createClass({displayName: "Help",
12 | getPageContent: function (page) {
13 | var root = path.join(__dirname, '../../content');
14 | var content = fs.readFileSync(path.join(root, page), 'utf8');
15 | return {
16 | __html: md.render(content)
17 | };
18 | },
19 | render: function() {
20 | var page = (this.props.query.page || 'index') + '.md';
21 | return (
22 | React.createElement("div", null,
23 | React.createElement("div", {dangerouslySetInnerHTML: this.getPageContent(page)})
24 | )
25 | );
26 | }
27 |
28 | });
29 |
30 | module.exports = Help;
31 |
--------------------------------------------------------------------------------
/core/modules/help-md/index.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | function setupAppMenu (runtime, appMenu) {
4 | var mainWindow = runtime.getMainWindow();
5 |
6 | appMenu.Page.submenu.push({
7 | label: 'Help',
8 | click: function () {
9 | if (mainWindow) {
10 | mainWindow.webContents.send('transitionTo', 'help');
11 | }
12 | }
13 | });
14 | }
15 |
16 | function setupRoutes (runtime) {
17 | runtime.routes.push({
18 | route: 'help',
19 | text: 'Help',
20 | navbar: true,
21 | handler: path.join(__dirname, '/dist/components/help')
22 | });
23 | }
24 |
25 | var init = function (runtime) {
26 | if (runtime) {
27 | runtime.once(runtime.events.INIT_APP_MENU, function (appMenu) {
28 | setupAppMenu(runtime, appMenu);
29 | });
30 |
31 | runtime.once(runtime.events.INIT_ROUTES, function () {
32 | setupRoutes(runtime);
33 | });
34 | }
35 | };
36 |
37 | module.exports = init;
38 |
--------------------------------------------------------------------------------
/core/modules/help-md/src/components/help.jsx:
--------------------------------------------------------------------------------
1 | var React = require('react'),
2 | fs = require('fs'),
3 | path = require('path');
4 |
5 | var md = require('markdown-it')({
6 | replaceLink: function (link, env) {
7 | return '#/help?page=' + link;
8 | }
9 | }).use(require('markdown-it-replace-link'));
10 |
11 | var Help = React.createClass({
12 | getPageContent: function (page) {
13 | var root = path.join(__dirname, '../../content');
14 | var content = fs.readFileSync(path.join(root, page), 'utf8');
15 | return {
16 | __html: md.render(content)
17 | };
18 | },
19 | render: function() {
20 | var page = (this.props.query.page || 'index') + '.md';
21 | return (
22 |
25 | );
26 | }
27 |
28 | });
29 |
30 | module.exports = Help;
31 |
--------------------------------------------------------------------------------
/core/modules/index.js:
--------------------------------------------------------------------------------
1 | var fs = require('fs'),
2 | path = require('path');
3 |
4 | var loader = {
5 | load: function (context) {
6 | //debug('Starting external modules...');
7 | fs.readdirSync(__dirname).forEach(function(file) {
8 | var p = path.join(__dirname, file);
9 | var stats = fs.statSync(p);
10 | if (stats.isDirectory()) {
11 | //debug('Loading module ' + file);
12 | require(p)(context);
13 | }
14 | });
15 | }
16 | };
17 |
18 | module.exports = loader;
19 |
--------------------------------------------------------------------------------
/core/runtime.js:
--------------------------------------------------------------------------------
1 | var events = require('events'),
2 | BrowserWindow = require('browser-window');
3 |
4 | function RuntimeContext () {
5 | events.EventEmitter.call(this);
6 |
7 | this.events = {
8 | INIT_APP_MENU: 'INIT_APP_MENU',
9 | INIT_ROUTES: 'INIT_ROUTES'
10 | };
11 |
12 | this.routes = [];
13 |
14 | // Main window id
15 | this.windowId = null;
16 | }
17 |
18 | // Extend runtime context class so that we can use on() and emit()
19 | RuntimeContext.prototype = Object.create(events.EventEmitter.prototype);
20 |
21 | RuntimeContext.prototype.getMainWindow = function () {
22 | if (this.windowId) {
23 | return BrowserWindow.fromId(this.windowId);
24 | }
25 | return null;
26 | };
27 |
28 | module.exports = new RuntimeContext();
29 |
--------------------------------------------------------------------------------
/dist/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
4 | .navbar-fixed-top > .container-fluid {
5 | padding-left: 0;
6 | padding-right: 0;
7 | }
8 |
--------------------------------------------------------------------------------
/img/electron-react-osx.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DenysVuika/electron-react/5452c8abf3f55c455e575980f62a5449510c866d/img/electron-react-osx.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Electron React Template
6 |
7 |
8 |
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/less/app.less:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | }
4 |
5 | .navbar-fixed-top {
6 | & > .container-fluid {
7 | padding-left: 0;
8 | padding-right: 0;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | var app = require('app'),
2 | BrowserWindow = require('browser-window'),
3 | Menu = require('menu'),
4 | runtime = require('./core/runtime'),
5 | appMenu = require('./core/app-menu');
6 |
7 | require('crash-reporter').start();
8 |
9 | // Load external modules
10 | var mods = require('./core/modules');
11 | mods.load(runtime);
12 |
13 | var mainWindow = null;
14 | var menu = null;
15 |
16 | app.on('window-all-closed', function () {
17 | //if (process.platform !== 'darwin') {
18 | app.quit();
19 | //}
20 | });
21 |
22 | app.on('ready', function () {
23 |
24 | runtime.emit(runtime.events.INIT_ROUTES, appMenu);
25 |
26 | mainWindow = new BrowserWindow({
27 | width: 800,
28 | height: 600
29 | });
30 |
31 | // initialize runtime reference to main window
32 | runtime.windowId = mainWindow.id;
33 |
34 | mainWindow.loadUrl('file://' + __dirname + '/index.html');
35 | mainWindow.focus();
36 |
37 | mainWindow.on('closed', function () {
38 | mainWindow = null;
39 | });
40 |
41 | // Dock Menu (Mac)
42 | if (process.platform === 'darwin') {
43 | var dockMenu = Menu.buildFromTemplate([
44 | { label: 'New Window', click: function() { console.log('New Window'); } },
45 | { label: 'New Window with Settings', submenu: [
46 | { label: 'Basic' },
47 | { label: 'Pro'},
48 | ]},
49 | { label: 'New Command...'},
50 | ]);
51 | app.dock.setMenu(dockMenu);
52 | }
53 |
54 | // Application Menu
55 | runtime.emit(runtime.events.INIT_APP_MENU, appMenu);
56 |
57 | var template = appMenu.template;
58 | menu = Menu.buildFromTemplate(template);
59 |
60 | if (process.platform === 'darwin') {
61 | Menu.setApplicationMenu(menu);
62 | } else {
63 | mainWindow.setMenu(menu);
64 | }
65 | });
66 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "electron-react",
3 | "version": "0.2.0",
4 | "description": "Project template for Electron with React support",
5 | "main": "main.js",
6 | "scripts": {
7 | "win": "node_modules\\electron-prebuilt\\dist\\electron .",
8 | "osx": "node_modules/electron-prebuilt/dist/Electron.app/Contents/MacOS/Electron ."
9 | },
10 | "author": "Denis Vuyka ",
11 | "license": "MIT",
12 | "dependencies": {
13 | "markdown-it": "^4.2.1",
14 | "markdown-it-replace-link": "^1.0.0",
15 | "react": "^0.13.3",
16 | "react-bootstrap": "^0.25.1",
17 | "react-router": "^0.13.3",
18 | "react-router-bootstrap": "^0.18.1"
19 | },
20 | "devDependencies": {
21 | "babelify": "^6.1.0",
22 | "browserify": "^11.0.1",
23 | "electron-prebuilt": "^0.31.2",
24 | "grunt": "^0.4.5",
25 | "grunt-browserify": "^4.0.1",
26 | "grunt-contrib-less": "^1.0.1",
27 | "grunt-contrib-uglify": "^0.9.1",
28 | "grunt-contrib-watch": "^0.6.1",
29 | "grunt-react": "^0.12.2"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------