summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--app/app.js18
-rw-r--r--app/components/Tray.js28
-rw-r--r--app/containers/Tray.js14
-rw-r--r--app/lib/components/TrayMenu.js122
-rw-r--r--app/main.js4
-rw-r--r--app/tray.js24
6 files changed, 178 insertions, 32 deletions
diff --git a/app/app.js b/app/app.js
index 101014e9b1..eb71a8201b 100644
--- a/app/app.js
+++ b/app/app.js
@@ -3,18 +3,28 @@ import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, hashHistory } from 'react-router';
import { syncHistoryWithStore } from 'react-router-redux';
+import { remote } from 'electron';
+import path from 'path';
import routes from './routes';
import configureStore from './store';
+import Tray from './containers/Tray';
+
+const iconPath = path.join(__dirname, 'assets/trayicon.png');
+const tray = new remote.Tray(iconPath);
const initialState = {};
const store = configureStore(initialState);
const routerHistory = syncHistoryWithStore(hashHistory, store);
-
const rootElement = document.querySelector(document.currentScript.getAttribute('data-container'));
ReactDOM.render(
- <Provider store={store}>
- <Router history={routerHistory} routes={routes} />
- </Provider>,
+ <div>
+ <Provider store={store}>
+ <Router history={routerHistory} routes={routes} />
+ </Provider>
+ <Provider store={store}>
+ <Tray handle={tray} history={routerHistory} />
+ </Provider>
+ </div>,
rootElement
);
diff --git a/app/components/Tray.js b/app/components/Tray.js
new file mode 100644
index 0000000000..69f14cb7ca
--- /dev/null
+++ b/app/components/Tray.js
@@ -0,0 +1,28 @@
+import React, { Component, PropTypes } from 'react';
+import { TrayMenu, TrayItem } from '../lib/components/TrayMenu';
+
+export default class Tray extends Component {
+
+ static propTypes = {
+ handle: PropTypes.object.isRequired,
+ }
+
+ logout() {
+ this.props.login({ username: '', loggedIn: false });
+ this.props.history.push('/');
+ }
+
+ render() {
+ const loggedIn = this.props.user && this.props.user.loggedIn;
+
+ return (
+ <TrayMenu tray={this.props.handle}>
+ {<TrayItem label="Log out" click={::this.logout} visible={loggedIn} />}
+ {<TrayItem type="separator" visible={loggedIn} />}
+ <TrayItem label="Privacy Policy" />
+ <TrayItem label="Visit homepage" />
+ </TrayMenu>
+ );
+ }
+
+} \ No newline at end of file
diff --git a/app/containers/Tray.js b/app/containers/Tray.js
new file mode 100644
index 0000000000..3916263d0d
--- /dev/null
+++ b/app/containers/Tray.js
@@ -0,0 +1,14 @@
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import Tray from '../components/Tray';
+import userActions from '../actions/user';
+
+const mapStateToProps = (state) => {
+ return state;
+};
+
+const mapDispatchToProps = (dispatch) => {
+ return bindActionCreators(userActions, dispatch);
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Tray);
diff --git a/app/lib/components/TrayMenu.js b/app/lib/components/TrayMenu.js
new file mode 100644
index 0000000000..bd4a68458a
--- /dev/null
+++ b/app/lib/components/TrayMenu.js
@@ -0,0 +1,122 @@
+/**
+ * Declarative Tray implementation for React + Electron
+ */
+
+import React, { Component, PropTypes } from 'react';
+import { remote } from 'electron';
+
+const { Menu, MenuItem } = remote;
+
+/**
+ * Tray menu component
+ *
+ * Example:
+ *
+ * const tray = new remote.Tray('/path/to/icon');
+ *
+ * return (
+ * <TrayMenu tray={tray}>
+ * <TrayItem label="Visit homepage" />
+ * </TrayMenu>
+ * )
+ */
+class TrayMenu extends Component {
+
+ static childContextTypes = {
+ menu: PropTypes.object.isRequired
+ };
+
+ static propTypes = {
+ tray: PropTypes.object.isRequired,
+ children: PropTypes.arrayOf(PropTypes.element).isRequired
+ };
+
+ _contextMenu = null;
+
+ getChildContext() {
+ return { menu: this._contextMenu };
+ }
+
+ componentDidMount() {
+ this.props.tray.setContextMenu(this._contextMenu);
+ }
+
+ componentDidUpdate() {
+ this.props.tray.setContextMenu(this._contextMenu);
+ }
+
+ render() {
+ // create new menu during each rendering
+ // see: https://github.com/electron/electron/issues/8598
+ this._contextMenu = new Menu();
+
+ return (
+ <div>{this.props.children}</div>
+ );
+ }
+
+}
+
+/**
+ * Submenu component
+ *
+ * Example:
+ *
+ * <TrayMenu tray={this.props.handle}>
+ * <TraySubmenu label="Resources">
+ * <TrayItem label="Homepage" />
+ * </TraySubmenu>
+ * </TrayMenu>
+ *
+ */
+class TraySubmenu extends Component {
+
+ static contextTypes = {
+ menu: PropTypes.object.isRequired
+ };
+
+ static childContextTypes = {
+ menu: PropTypes.object.isRequired
+ };
+
+ static propTypes = {
+ children: PropTypes.arrayOf(PropTypes.element).isRequired
+ };
+
+ _contextMenu = null;
+
+ getChildContext() {
+ return { menu: this._contextMenu };
+ }
+
+ render() {
+ // create new menu during each rendering
+ // see: https://github.com/electron/electron/issues/8598
+ this.contextMenu = new Menu();
+
+ this.context.menu.append(new MenuItem({ ...this.props, submenu: this._contextMenu }));
+
+ return (
+ <div>{this.props.children}</div>
+ );
+ }
+
+}
+
+/**
+ * Item component
+ */
+class TrayItem extends Component {
+
+ static contextTypes = {
+ menu: PropTypes.object.isRequired
+ };
+
+ render() {
+ this.context.menu.append(new MenuItem(this.props));
+ return null;
+ }
+
+}
+
+export { TrayMenu, TraySubmenu, TrayItem };
diff --git a/app/main.js b/app/main.js
index 001a28c863..e923df1a8b 100644
--- a/app/main.js
+++ b/app/main.js
@@ -1,7 +1,6 @@
import path from 'path';
import url from 'url';
import {app, crashReporter, BrowserWindow, Menu} from 'electron';
-import trayMenu from './tray';
const isDevelopment = (process.env.NODE_ENV === 'development');
@@ -52,9 +51,6 @@ app.on('ready', async () => {
show: false
});
- // initialize tray menu
- trayMenu.setup();
-
mainWindow.loadURL(url.format({
pathname: path.join(__dirname, 'index.html'),
protocol: 'file:',
diff --git a/app/tray.js b/app/tray.js
deleted file mode 100644
index c93b207d0d..0000000000
--- a/app/tray.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import path from 'path';
-import { app, Menu, Tray } from 'electron';
-
-class TrayMenu {
-
- trayImpl = null;
-
- setup() {
- const iconPath = path.join(__dirname, "assets/trayicon.png");
- this.trayImpl = new Tray(iconPath);
-
- const contextMenu = Menu.buildFromTemplate([
- {label: 'Item1', type: 'radio'},
- {label: 'Item2', type: 'radio'},
- {label: 'Item3', type: 'radio', checked: true},
- {label: 'Item4', type: 'radio'}
- ]);
-
- this.trayImpl.setContextMenu(contextMenu);
- }
-
-}
-
-module.exports = new TrayMenu();