diff options
-rw-r--r-- | .vscode/launch.json | 11 | ||||
-rw-r--r-- | package.json | 1 | ||||
-rw-r--r-- | src/components/layout/AppLayout.js | 122 | ||||
-rw-r--r-- | src/environment.js | 12 | ||||
-rw-r--r-- | src/index.html | 2 | ||||
-rw-r--r-- | src/index.js | 5 | ||||
-rw-r--r-- | src/lib/Menu.js | 330 | ||||
-rw-r--r-- | src/styles/layout.scss | 10 | ||||
-rw-r--r-- | src/styles/main.scss | 2 | ||||
-rw-r--r-- | src/styles/title-bar.scss | 7 | ||||
-rw-r--r-- | yarn.lock | 45 |
11 files changed, 411 insertions, 136 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index a8300f84f..5afc2d051 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json | |||
@@ -9,7 +9,8 @@ | |||
9 | "program": "${workspaceFolder}/build/index.js", | 9 | "program": "${workspaceFolder}/build/index.js", |
10 | "protocol": "inspector", | 10 | "protocol": "inspector", |
11 | "env": { | 11 | "env": { |
12 | "NODE_ENV": "development" | 12 | "NODE_ENV": "development", |
13 | "OS_PLATFORM": "win32" | ||
13 | } | 14 | } |
14 | }, | 15 | }, |
15 | { | 16 | { |
@@ -18,9 +19,10 @@ | |||
18 | "name": "Franz – Live API", | 19 | "name": "Franz – Live API", |
19 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", | 20 | "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", |
20 | "program": "${workspaceFolder}/build/index.js", | 21 | "program": "${workspaceFolder}/build/index.js", |
21 | "protocol": "inspector", | 22 | "protocol": "inspector", |
22 | "env": { | 23 | "env": { |
23 | "LIVE_API": "1" | 24 | "LIVE_API": "1", |
25 | "OS_PLATFORM": "win32" | ||
24 | } | 26 | } |
25 | }, | 27 | }, |
26 | { | 28 | { |
@@ -31,7 +33,8 @@ | |||
31 | "program": "${workspaceFolder}/build/index.js", | 33 | "program": "${workspaceFolder}/build/index.js", |
32 | "protocol": "inspector", | 34 | "protocol": "inspector", |
33 | "env": { | 35 | "env": { |
34 | "LOCAL_API": "1" | 36 | "LOCAL_API": "1", |
37 | "OS_PLATFORM": "win32" | ||
35 | } | 38 | } |
36 | } | 39 | } |
37 | ] | 40 | ] |
diff --git a/package.json b/package.json index fd96c602b..f35da9880 100644 --- a/package.json +++ b/package.json | |||
@@ -35,6 +35,7 @@ | |||
35 | "classnames": "^2.2.5", | 35 | "classnames": "^2.2.5", |
36 | "du": "^0.1.0", | 36 | "du": "^0.1.0", |
37 | "electron-fetch": "^1.1.0", | 37 | "electron-fetch": "^1.1.0", |
38 | "electron-react-titlebar": "^0.7.1", | ||
38 | "electron-spellchecker": "^1.1.2", | 39 | "electron-spellchecker": "^1.1.2", |
39 | "electron-updater": "^2.4.3", | 40 | "electron-updater": "^2.4.3", |
40 | "electron-window-state": "^4.1.0", | 41 | "electron-window-state": "^4.1.0", |
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 20dc2f764..686476317 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js | |||
@@ -2,10 +2,13 @@ import React, { Component } from 'react'; | |||
2 | import PropTypes from 'prop-types'; | 2 | import PropTypes from 'prop-types'; |
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | 3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; |
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { TitleBar } from 'electron-react-titlebar'; | ||
5 | 6 | ||
6 | import InfoBar from '../ui/InfoBar'; | 7 | import InfoBar from '../ui/InfoBar'; |
7 | import globalMessages from '../../i18n/globalMessages'; | 8 | import globalMessages from '../../i18n/globalMessages'; |
8 | 9 | ||
10 | import { isMac } from '../../environment'; | ||
11 | |||
9 | function createMarkup(HTMLString) { | 12 | function createMarkup(HTMLString) { |
10 | return { __html: HTMLString }; | 13 | return { __html: HTMLString }; |
11 | } | 14 | } |
@@ -87,64 +90,67 @@ export default class AppLayout extends Component { | |||
87 | return ( | 90 | return ( |
88 | <div> | 91 | <div> |
89 | <div className="app"> | 92 | <div className="app"> |
90 | {sidebar} | 93 | {!isMac && <TitleBar menu={window.franz.menu.template} icon={'assets/images/logo.svg'} />} |
91 | <div className="app__service"> | 94 | <div className="app__content"> |
92 | {news.length > 0 && news.map(item => ( | 95 | {sidebar} |
93 | <InfoBar | 96 | <div className="app__service"> |
94 | key={item.id} | 97 | {news.length > 0 && news.map(item => ( |
95 | position="top" | 98 | <InfoBar |
96 | type={item.type} | 99 | key={item.id} |
97 | sticky={item.sticky} | 100 | position="top" |
98 | onHide={() => removeNewsItem({ newsId: item.id })} | 101 | type={item.type} |
99 | > | 102 | sticky={item.sticky} |
100 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> | 103 | onHide={() => removeNewsItem({ newsId: item.id })} |
101 | </InfoBar> | 104 | > |
102 | ))} | 105 | <span dangerouslySetInnerHTML={createMarkup(item.message)} /> |
103 | {!isOnline && ( | 106 | </InfoBar> |
104 | <InfoBar | 107 | ))} |
105 | type="danger" | 108 | {!isOnline && ( |
106 | > | 109 | <InfoBar |
107 | <span className="mdi mdi-flash" /> | 110 | type="danger" |
108 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} | 111 | > |
109 | </InfoBar> | 112 | <span className="mdi mdi-flash" /> |
110 | )} | 113 | {intl.formatMessage(globalMessages.notConnectedToTheInternet)} |
111 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( | 114 | </InfoBar> |
112 | <InfoBar | 115 | )} |
113 | type="danger" | 116 | {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( |
114 | ctaLabel="Try again" | 117 | <InfoBar |
115 | ctaLoading={areRequiredRequestsLoading} | 118 | type="danger" |
116 | sticky | 119 | ctaLabel="Try again" |
117 | onClick={retryRequiredRequests} | 120 | ctaLoading={areRequiredRequestsLoading} |
118 | > | 121 | sticky |
119 | <span className="mdi mdi-flash" /> | 122 | onClick={retryRequiredRequests} |
120 | {intl.formatMessage(messages.requiredRequestsFailed)} | 123 | > |
121 | </InfoBar> | 124 | <span className="mdi mdi-flash" /> |
122 | )} | 125 | {intl.formatMessage(messages.requiredRequestsFailed)} |
123 | {showServicesUpdatedInfoBar && ( | 126 | </InfoBar> |
124 | <InfoBar | 127 | )} |
125 | type="primary" | 128 | {showServicesUpdatedInfoBar && ( |
126 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} | 129 | <InfoBar |
127 | onClick={reloadServicesAfterUpdate} | 130 | type="primary" |
128 | sticky | 131 | ctaLabel={intl.formatMessage(messages.buttonReloadServices)} |
129 | > | 132 | onClick={reloadServicesAfterUpdate} |
130 | <span className="mdi mdi-power-plug" /> | 133 | sticky |
131 | {intl.formatMessage(messages.servicesUpdated)} | 134 | > |
132 | </InfoBar> | 135 | <span className="mdi mdi-power-plug" /> |
133 | )} | 136 | {intl.formatMessage(messages.servicesUpdated)} |
134 | {appUpdateIsDownloaded && ( | 137 | </InfoBar> |
135 | <InfoBar | 138 | )} |
136 | type="primary" | 139 | {appUpdateIsDownloaded && ( |
137 | ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)} | 140 | <InfoBar |
138 | onClick={installAppUpdate} | 141 | type="primary" |
139 | sticky | 142 | ctaLabel={intl.formatMessage(messages.buttonInstallUpdate)} |
140 | > | 143 | onClick={installAppUpdate} |
141 | <span className="mdi mdi-information" /> | 144 | sticky |
142 | {intl.formatMessage(messages.updateAvailable)} <a href="https://meetfranz.com/changelog" target="_blank"> | 145 | > |
143 | <u>{intl.formatMessage(messages.changelog)}</u> | 146 | <span className="mdi mdi-information" /> |
144 | </a> | 147 | {intl.formatMessage(messages.updateAvailable)} <a href="https://meetfranz.com/changelog" target="_blank"> |
145 | </InfoBar> | 148 | <u>{intl.formatMessage(messages.changelog)}</u> |
146 | )} | 149 | </a> |
147 | {services} | 150 | </InfoBar> |
151 | )} | ||
152 | {services} | ||
153 | </div> | ||
148 | </div> | 154 | </div> |
149 | </div> | 155 | </div> |
150 | {children} | 156 | {children} |
diff --git a/src/environment.js b/src/environment.js index e185120c0..e1762129b 100644 --- a/src/environment.js +++ b/src/environment.js | |||
@@ -4,11 +4,17 @@ export const isDevMode = Boolean(process.execPath.match(/[\\/]electron/)); | |||
4 | export const useLiveAPI = process.env.LIVE_API; | 4 | export const useLiveAPI = process.env.LIVE_API; |
5 | export const useLocalAPI = process.env.LOCAL_API; | 5 | export const useLocalAPI = process.env.LOCAL_API; |
6 | 6 | ||
7 | export const isMac = process.platform === 'darwin'; | 7 | let platform = process.platform; |
8 | export const isWindows = process.platform === 'win32'; | 8 | if (process.env.OS_PLATFORM) { |
9 | export const isLinux = process.platform === 'linux'; | 9 | platform = process.env.OS_PLATFORM; |
10 | } | ||
11 | |||
12 | export const isMac = platform === 'darwin'; | ||
13 | export const isWindows = platform === 'win32'; | ||
14 | export const isLinux = platform === 'linux'; | ||
10 | 15 | ||
11 | export const ctrlKey = isMac ? '⌘' : 'Ctrl'; | 16 | export const ctrlKey = isMac ? '⌘' : 'Ctrl'; |
17 | export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; | ||
12 | 18 | ||
13 | let api; | 19 | let api; |
14 | if (!isDevMode || (isDevMode && useLiveAPI)) { | 20 | if (!isDevMode || (isDevMode && useLiveAPI)) { |
diff --git a/src/index.html b/src/index.html index 9e5acd705..6c259e5be 100644 --- a/src/index.html +++ b/src/index.html | |||
@@ -11,7 +11,7 @@ | |||
11 | <div class="dev-warning">DEV MODE</div> | 11 | <div class="dev-warning">DEV MODE</div> |
12 | <div id="root"></div> | 12 | <div id="root"></div> |
13 | <script> | 13 | <script> |
14 | document.querySelector('body').classList.add(process.platform); | 14 | document.querySelector('body').classList.add(process.env.OS_PLATFORM ? process.env.OS_PLATFORM : process.platform); |
15 | 15 | ||
16 | const { isDevMode } = require('./environment'); | 16 | const { isDevMode } = require('./environment'); |
17 | if (isDevMode) { | 17 | if (isDevMode) { |
diff --git a/src/index.js b/src/index.js index f82bb3590..2acb8e2cb 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -4,7 +4,7 @@ import path from 'path'; | |||
4 | 4 | ||
5 | import windowStateKeeper from 'electron-window-state'; | 5 | import windowStateKeeper from 'electron-window-state'; |
6 | 6 | ||
7 | import { isDevMode, isWindows } from './environment'; | 7 | import { isDevMode, isMac, isWindows } from './environment'; |
8 | import ipcApi from './electron/ipc-api'; | 8 | import ipcApi from './electron/ipc-api'; |
9 | import Tray from './lib/Tray'; | 9 | import Tray from './lib/Tray'; |
10 | import Settings from './electron/Settings'; | 10 | import Settings from './electron/Settings'; |
@@ -72,7 +72,8 @@ const createWindow = () => { | |||
72 | height: mainWindowState.height, | 72 | height: mainWindowState.height, |
73 | minWidth: 600, | 73 | minWidth: 600, |
74 | minHeight: 500, | 74 | minHeight: 500, |
75 | titleBarStyle: 'hidden', | 75 | titleBarStyle: isMac ? 'hidden' : '', |
76 | frame: false, | ||
76 | backgroundColor: '#3498db', | 77 | backgroundColor: '#3498db', |
77 | autoHideMenuBar: true, | 78 | autoHideMenuBar: true, |
78 | }); | 79 | }); |
diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 6962f22fe..50196af96 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { remote, shell } from 'electron'; | 1 | import { remote, shell } from 'electron'; |
2 | import { autorun, computed } from 'mobx'; | 2 | import { observable, autorun, computed } from 'mobx'; |
3 | import { defineMessages } from 'react-intl'; | 3 | import { defineMessages } from 'react-intl'; |
4 | 4 | ||
5 | import { isMac } from '../environment'; | 5 | import { isMac, ctrlKey, cmdKey } from '../environment'; |
6 | 6 | ||
7 | const { app, Menu, dialog } = remote; | 7 | const { app, Menu, dialog } = remote; |
8 | 8 | ||
@@ -13,7 +13,11 @@ const menuItems = defineMessages({ | |||
13 | }, | 13 | }, |
14 | }); | 14 | }); |
15 | 15 | ||
16 | const _makeTemplate = intl => [ | 16 | function getActiveWebview() { |
17 | return window.franz.stores.services.active.webview; | ||
18 | } | ||
19 | |||
20 | const _templateFactory = intl => [ | ||
17 | { | 21 | { |
18 | label: intl.formatMessage(menuItems.edit), | 22 | label: intl.formatMessage(menuItems.edit), |
19 | submenu: [ | 23 | submenu: [ |
@@ -122,7 +126,162 @@ const _makeTemplate = intl => [ | |||
122 | }, | 126 | }, |
123 | ]; | 127 | ]; |
124 | 128 | ||
129 | const _titleBarTemplateFactory = intl => [ | ||
130 | { | ||
131 | label: 'Edit', | ||
132 | submenu: [ | ||
133 | { | ||
134 | label: 'Undo', | ||
135 | accelerator: `${ctrlKey}+Z`, | ||
136 | click() { | ||
137 | getActiveWebview().undo(); | ||
138 | }, | ||
139 | }, | ||
140 | { | ||
141 | label: 'Redo', | ||
142 | accelerator: `${ctrlKey}+Y`, | ||
143 | click() { | ||
144 | getActiveWebview().redo(); | ||
145 | }, | ||
146 | }, | ||
147 | { | ||
148 | type: 'separator', | ||
149 | }, | ||
150 | { | ||
151 | label: 'Cut', | ||
152 | accelerator: `${ctrlKey}+X`, | ||
153 | click() { | ||
154 | getActiveWebview().cut(); | ||
155 | }, | ||
156 | }, | ||
157 | { | ||
158 | label: 'Copy', | ||
159 | accelerator: `${ctrlKey}+C`, | ||
160 | click() { | ||
161 | getActiveWebview().copy(); | ||
162 | }, | ||
163 | }, | ||
164 | { | ||
165 | label: 'Paste', | ||
166 | accelerator: `${ctrlKey}+V`, | ||
167 | click() { | ||
168 | getActiveWebview().paste(); | ||
169 | }, | ||
170 | }, | ||
171 | { | ||
172 | label: 'Paste and Match Style', | ||
173 | accelerator: `${ctrlKey}+Shift+V`, | ||
174 | click() { | ||
175 | getActiveWebview().pasteAndMatchStyle(); | ||
176 | }, | ||
177 | }, | ||
178 | { | ||
179 | label: 'Delete', | ||
180 | click() { | ||
181 | getActiveWebview().delete(); | ||
182 | }, | ||
183 | }, | ||
184 | { | ||
185 | label: 'Select All', | ||
186 | accelerator: `${ctrlKey}+A`, | ||
187 | click() { | ||
188 | getActiveWebview().selectAll(); | ||
189 | }, | ||
190 | }, | ||
191 | ], | ||
192 | }, | ||
193 | { | ||
194 | label: 'View', | ||
195 | submenu: [ | ||
196 | { | ||
197 | type: 'separator', | ||
198 | }, | ||
199 | { | ||
200 | label: 'Reset Zoom', | ||
201 | accelerator: `${ctrlKey}+0`, | ||
202 | click() { | ||
203 | getActiveWebview().setZoomLevel(0); | ||
204 | }, | ||
205 | }, | ||
206 | { | ||
207 | label: 'Zoom in', | ||
208 | accelerator: `${ctrlKey}+=`, | ||
209 | click() { | ||
210 | getActiveWebview().getZoomLevel((zoomLevel) => { | ||
211 | getActiveWebview().setZoomLevel(zoomLevel === 5 ? zoomLevel : zoomLevel + 1); | ||
212 | }); | ||
213 | }, | ||
214 | }, | ||
215 | { | ||
216 | label: 'Zoom out', | ||
217 | accelerator: `${ctrlKey}+-`, | ||
218 | click() { | ||
219 | getActiveWebview().getZoomLevel((zoomLevel) => { | ||
220 | getActiveWebview().setZoomLevel(zoomLevel === -5 ? zoomLevel : zoomLevel - 1); | ||
221 | }); | ||
222 | }, | ||
223 | }, | ||
224 | ], | ||
225 | }, | ||
226 | { | ||
227 | label: 'Services', | ||
228 | submenu: [], | ||
229 | }, | ||
230 | { | ||
231 | label: 'Window', | ||
232 | submenu: [ | ||
233 | { | ||
234 | label: 'Minimize', | ||
235 | accelerator: 'Alt+M', | ||
236 | click(menuItem, browserWindow) { | ||
237 | browserWindow.minimize(); | ||
238 | }, | ||
239 | }, | ||
240 | { | ||
241 | label: 'Close', | ||
242 | accelerator: 'Alt+W', | ||
243 | click(menuItem, browserWindow) { | ||
244 | browserWindow.close(); | ||
245 | }, | ||
246 | }, | ||
247 | ], | ||
248 | }, | ||
249 | { | ||
250 | label: '?', | ||
251 | submenu: [ | ||
252 | { | ||
253 | label: 'Learn More', | ||
254 | click() { shell.openExternal('http://meetfranz.com'); }, | ||
255 | }, | ||
256 | { | ||
257 | label: 'Changelog', | ||
258 | click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, | ||
259 | }, | ||
260 | { | ||
261 | type: 'separator', | ||
262 | }, | ||
263 | { | ||
264 | label: 'Support', | ||
265 | click() { shell.openExternal('http://meetfranz.com/support'); }, | ||
266 | }, | ||
267 | { | ||
268 | type: 'separator', | ||
269 | }, | ||
270 | { | ||
271 | label: 'Terms of Service', | ||
272 | click() { shell.openExternal('https://meetfranz.com/terms'); }, | ||
273 | }, | ||
274 | { | ||
275 | label: 'Privacy Statement', | ||
276 | click() { shell.openExternal('https://meetfranz.com/privacy'); }, | ||
277 | }, | ||
278 | ], | ||
279 | }, | ||
280 | ]; | ||
281 | |||
125 | export default class FranzMenu { | 282 | export default class FranzMenu { |
283 | @observable currentTemplate = []; | ||
284 | |||
126 | constructor(stores, actions) { | 285 | constructor(stores, actions) { |
127 | this.stores = stores; | 286 | this.stores = stores; |
128 | this.actions = actions; | 287 | this.actions = actions; |
@@ -134,6 +293,10 @@ export default class FranzMenu { | |||
134 | this._build(); | 293 | this._build(); |
135 | } | 294 | } |
136 | 295 | ||
296 | get template() { | ||
297 | return this.currentTemplate.toJS(); | ||
298 | } | ||
299 | |||
137 | _build() { | 300 | _build() { |
138 | // console.log(window.franz); | 301 | // console.log(window.franz); |
139 | const serviceTpl = Object.assign([], this.serviceTpl); // need to clone object so we don't modify computed (cached) object | 302 | const serviceTpl = Object.assign([], this.serviceTpl); // need to clone object so we don't modify computed (cached) object |
@@ -142,13 +305,20 @@ export default class FranzMenu { | |||
142 | return; | 305 | return; |
143 | } | 306 | } |
144 | 307 | ||
145 | const tpl = _makeTemplate(window.franz.intl); | 308 | const intl = window.franz.intl; |
309 | const tpl = isMac ? _templateFactory(intl) : _titleBarTemplateFactory(intl); | ||
146 | 310 | ||
147 | tpl[1].submenu.push({ | 311 | tpl[1].submenu.push({ |
148 | role: 'toggledevtools', | 312 | type: 'separator', |
313 | }, { | ||
314 | label: 'Toggle Developer Tools', | ||
315 | accelerator: `${cmdKey}+Alt+I`, | ||
316 | click: (menuItem, browserWindow) => { | ||
317 | browserWindow.webContents.toggleDevTools(); | ||
318 | }, | ||
149 | }, { | 319 | }, { |
150 | label: 'Toggle Service Developer Tools', | 320 | label: 'Open Service Developer Tools', |
151 | accelerator: 'CmdOrCtrl+Shift+Alt+i', | 321 | accelerator: `${cmdKey}+Shift+Alt+I`, |
152 | click: () => { | 322 | click: () => { |
153 | this.actions.service.openDevToolsForActiveService(); | 323 | this.actions.service.openDevToolsForActiveService(); |
154 | }, | 324 | }, |
@@ -157,7 +327,7 @@ export default class FranzMenu { | |||
157 | tpl[1].submenu.unshift({ | 327 | tpl[1].submenu.unshift({ |
158 | label: 'Reload Service', | 328 | label: 'Reload Service', |
159 | id: 'reloadService', | 329 | id: 'reloadService', |
160 | accelerator: 'CmdOrCtrl+R', | 330 | accelerator: `${cmdKey}+R`, |
161 | click: () => { | 331 | click: () => { |
162 | if (this.stores.user.isLoggedIn | 332 | if (this.stores.user.isLoggedIn |
163 | && this.stores.services.enabled.length > 0) { | 333 | && this.stores.services.enabled.length > 0) { |
@@ -168,56 +338,69 @@ export default class FranzMenu { | |||
168 | }, | 338 | }, |
169 | }, { | 339 | }, { |
170 | label: 'Reload Franz', | 340 | label: 'Reload Franz', |
171 | accelerator: 'CmdOrCtrl+Shift+R', | 341 | accelerator: `${cmdKey}+Shift+R`, |
172 | click: () => { | 342 | click: () => { |
173 | window.location.reload(); | 343 | window.location.reload(); |
174 | }, | 344 | }, |
175 | }); | 345 | }); |
176 | 346 | ||
177 | if (isMac) { | 347 | tpl.unshift({ |
178 | tpl.unshift({ | 348 | label: isMac ? app.getName() : 'File', |
179 | label: app.getName(), | 349 | submenu: [ |
180 | submenu: [ | 350 | { |
181 | { | 351 | role: 'about', |
182 | role: 'about', | 352 | }, |
183 | }, | 353 | { |
184 | { | 354 | type: 'separator', |
185 | type: 'separator', | 355 | }, |
186 | }, | 356 | { |
187 | { | 357 | label: 'Settings', |
188 | label: 'Settings', | 358 | accelerator: 'CmdOrCtrl+,', |
189 | accelerator: 'CmdOrCtrl+,', | 359 | click: () => { |
190 | click: () => { | 360 | this.actions.ui.openSettings({ path: 'app' }); |
191 | this.actions.ui.openSettings({ path: 'app' }); | ||
192 | }, | ||
193 | }, | ||
194 | { | ||
195 | type: 'separator', | ||
196 | }, | ||
197 | { | ||
198 | role: 'services', | ||
199 | submenu: [], | ||
200 | }, | ||
201 | { | ||
202 | type: 'separator', | ||
203 | }, | ||
204 | { | ||
205 | role: 'hide', | ||
206 | }, | ||
207 | { | ||
208 | role: 'hideothers', | ||
209 | }, | ||
210 | { | ||
211 | role: 'unhide', | ||
212 | }, | ||
213 | { | ||
214 | type: 'separator', | ||
215 | }, | ||
216 | { | ||
217 | role: 'quit', | ||
218 | }, | 361 | }, |
219 | ], | 362 | }, |
220 | }); | 363 | { |
364 | type: 'separator', | ||
365 | }, | ||
366 | { | ||
367 | role: 'services', | ||
368 | submenu: [], | ||
369 | }, | ||
370 | { | ||
371 | type: 'separator', | ||
372 | }, | ||
373 | { | ||
374 | role: 'hide', | ||
375 | }, | ||
376 | { | ||
377 | role: 'hideothers', | ||
378 | }, | ||
379 | { | ||
380 | role: 'unhide', | ||
381 | }, | ||
382 | { | ||
383 | type: 'separator', | ||
384 | }, | ||
385 | { | ||
386 | role: 'quit', | ||
387 | }, | ||
388 | ], | ||
389 | }); | ||
390 | |||
391 | const about = { | ||
392 | label: 'About Franz', | ||
393 | click: () => { | ||
394 | dialog.showMessageBox({ | ||
395 | type: 'info', | ||
396 | title: 'Franz', | ||
397 | message: 'Franz', | ||
398 | detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, | ||
399 | }); | ||
400 | }, | ||
401 | }; | ||
402 | |||
403 | if (isMac) { | ||
221 | // Edit menu. | 404 | // Edit menu. |
222 | tpl[1].submenu.push( | 405 | tpl[1].submenu.push( |
223 | { | 406 | { |
@@ -235,23 +418,39 @@ export default class FranzMenu { | |||
235 | ], | 418 | ], |
236 | }, | 419 | }, |
237 | ); | 420 | ); |
421 | |||
422 | tpl[4].submenu.unshift(about, { | ||
423 | type: 'separator', | ||
424 | }); | ||
238 | } else { | 425 | } else { |
239 | tpl[4].submenu.unshift({ | 426 | tpl[0].submenu = [ |
240 | role: 'about', | 427 | { |
241 | click: () => { | 428 | label: 'Preferences...', |
242 | dialog.showMessageBox({ | 429 | accelerator: 'Ctrl+P', |
243 | type: 'info', | 430 | click: () => { |
244 | title: 'Franz', | 431 | this.actions.ui.openSettings({ path: 'app' }); |
245 | message: 'Franz', | 432 | }, |
246 | detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, | ||
247 | }); | ||
248 | }, | 433 | }, |
249 | }); | 434 | { |
435 | type: 'separator', | ||
436 | }, | ||
437 | { | ||
438 | label: 'Quit', | ||
439 | accelerator: 'Alt+F4', | ||
440 | click: () => { | ||
441 | app.quit(); | ||
442 | }, | ||
443 | }, | ||
444 | ]; | ||
445 | |||
446 | tpl[5].submenu.push({ | ||
447 | type: 'separator', | ||
448 | }, about); | ||
250 | } | 449 | } |
251 | 450 | ||
252 | serviceTpl.unshift({ | 451 | serviceTpl.unshift({ |
253 | label: 'Add new Service', | 452 | label: 'Add new Service', |
254 | accelerator: 'CmdOrCtrl+N', | 453 | accelerator: `${cmdKey}+N`, |
255 | click: () => { | 454 | click: () => { |
256 | this.actions.ui.openSettings({ path: 'recipes' }); | 455 | this.actions.ui.openSettings({ path: 'recipes' }); |
257 | }, | 456 | }, |
@@ -260,9 +459,10 @@ export default class FranzMenu { | |||
260 | }); | 459 | }); |
261 | 460 | ||
262 | if (serviceTpl.length > 0) { | 461 | if (serviceTpl.length > 0) { |
263 | tpl[isMac ? 3 : 2].submenu = serviceTpl; | 462 | tpl[3].submenu = serviceTpl; |
264 | } | 463 | } |
265 | 464 | ||
465 | this.currentTemplate = tpl; | ||
266 | const menu = Menu.buildFromTemplate(tpl); | 466 | const menu = Menu.buildFromTemplate(tpl); |
267 | Menu.setApplicationMenu(menu); | 467 | Menu.setApplicationMenu(menu); |
268 | } | 468 | } |
@@ -273,7 +473,7 @@ export default class FranzMenu { | |||
273 | if (this.stores.user.isLoggedIn) { | 473 | if (this.stores.user.isLoggedIn) { |
274 | return services.map((service, i) => ({ | 474 | return services.map((service, i) => ({ |
275 | label: this._getServiceName(service), | 475 | label: this._getServiceName(service), |
276 | accelerator: i <= 9 ? `CmdOrCtrl+${i + 1}` : null, | 476 | accelerator: i <= 9 ? `${cmdKey}+${i + 1}` : null, |
277 | type: 'radio', | 477 | type: 'radio', |
278 | checked: service.isActive, | 478 | checked: service.isActive, |
279 | click: () => { | 479 | click: () => { |
diff --git a/src/styles/layout.scss b/src/styles/layout.scss index afdd7dec7..964a9fcea 100644 --- a/src/styles/layout.scss +++ b/src/styles/layout.scss | |||
@@ -6,7 +6,11 @@ html { | |||
6 | 6 | ||
7 | .app { | 7 | .app { |
8 | display: flex; | 8 | display: flex; |
9 | flex-direction: row; | 9 | flex-direction: column; |
10 | |||
11 | .app__content { | ||
12 | display: flex; | ||
13 | } | ||
10 | 14 | ||
11 | .app__service { | 15 | .app__service { |
12 | display: flex; | 16 | display: flex; |
@@ -15,6 +19,10 @@ html { | |||
15 | } | 19 | } |
16 | } | 20 | } |
17 | 21 | ||
22 | .electron-app-title-bar { | ||
23 | z-index: 99999999; | ||
24 | } | ||
25 | |||
18 | .window-draggable { | 26 | .window-draggable { |
19 | position: absolute; | 27 | position: absolute; |
20 | width: 100%; | 28 | width: 100%; |
diff --git a/src/styles/main.scss b/src/styles/main.scss index 446bdca14..784a04d3d 100644 --- a/src/styles/main.scss +++ b/src/styles/main.scss | |||
@@ -4,6 +4,7 @@ $mdi-font-path: '../node_modules/mdi/fonts'; | |||
4 | } | 4 | } |
5 | 5 | ||
6 | @import './node_modules/mdi/scss/materialdesignicons.scss'; | 6 | @import './node_modules/mdi/scss/materialdesignicons.scss'; |
7 | @import './node_modules/electron-react-titlebar/assets/style'; | ||
7 | 8 | ||
8 | // modules | 9 | // modules |
9 | @import './reset.scss'; | 10 | @import './reset.scss'; |
@@ -28,6 +29,7 @@ $mdi-font-path: '../node_modules/mdi/fonts'; | |||
28 | @import './subscription-popup.scss'; | 29 | @import './subscription-popup.scss'; |
29 | @import './content-tabs.scss'; | 30 | @import './content-tabs.scss'; |
30 | @import './invite.scss'; | 31 | @import './invite.scss'; |
32 | @import './title-bar.scss'; | ||
31 | 33 | ||
32 | // form | 34 | // form |
33 | @import './input.scss'; | 35 | @import './input.scss'; |
diff --git a/src/styles/title-bar.scss b/src/styles/title-bar.scss new file mode 100644 index 000000000..67bf97008 --- /dev/null +++ b/src/styles/title-bar.scss | |||
@@ -0,0 +1,7 @@ | |||
1 | #electron-app-title-bar span { | ||
2 | line-height: normal; | ||
3 | } | ||
4 | |||
5 | #electron-app-title-bar div { | ||
6 | height: auto; | ||
7 | } | ||
@@ -1367,7 +1367,7 @@ circular-json@^0.3.1: | |||
1367 | version "0.3.3" | 1367 | version "0.3.3" |
1368 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" | 1368 | resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" |
1369 | 1369 | ||
1370 | classnames@^2.2.0, classnames@^2.2.5: | 1370 | classnames@^2.2.0, classnames@^2.2.3, classnames@^2.2.5: |
1371 | version "2.2.5" | 1371 | version "2.2.5" |
1372 | resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" | 1372 | resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" |
1373 | 1373 | ||
@@ -1766,6 +1766,10 @@ doctrine@^2.0.0: | |||
1766 | esutils "^2.0.2" | 1766 | esutils "^2.0.2" |
1767 | isarray "^1.0.0" | 1767 | isarray "^1.0.0" |
1768 | 1768 | ||
1769 | "dom-helpers@^2.4.0 || ^3.0.0": | ||
1770 | version "3.3.1" | ||
1771 | resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" | ||
1772 | |||
1769 | dom-helpers@^3.2.0: | 1773 | dom-helpers@^3.2.0: |
1770 | version "3.2.1" | 1774 | version "3.2.1" |
1771 | resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" | 1775 | resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a" |
@@ -1995,6 +1999,13 @@ electron-publish@19.15.0: | |||
1995 | fs-extra-p "^4.3.0" | 1999 | fs-extra-p "^4.3.0" |
1996 | mime "^1.3.6" | 2000 | mime "^1.3.6" |
1997 | 2001 | ||
2002 | electron-react-titlebar@^0.7.1: | ||
2003 | version "0.7.1" | ||
2004 | resolved "https://registry.yarnpkg.com/electron-react-titlebar/-/electron-react-titlebar-0.7.1.tgz#d56517d01ef0e935caa994e9b577dfd63a56c66c" | ||
2005 | dependencies: | ||
2006 | lodash "^4.17.4" | ||
2007 | react-virtualized "^9.7.6" | ||
2008 | |||
1998 | electron-rebuild@^1.6.0: | 2009 | electron-rebuild@^1.6.0: |
1999 | version "1.6.0" | 2010 | version "1.6.0" |
2000 | resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.6.0.tgz#e8d26f4d8e9fe5388df35864b3658e5cfd4dcb7e" | 2011 | resolved "https://registry.yarnpkg.com/electron-rebuild/-/electron-rebuild-1.6.0.tgz#e8d26f4d8e9fe5388df35864b3658e5cfd4dcb7e" |
@@ -2450,6 +2461,18 @@ fast-levenshtein@~2.0.4: | |||
2450 | version "2.0.6" | 2461 | version "2.0.6" |
2451 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" | 2462 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" |
2452 | 2463 | ||
2464 | fbjs@^0.8.16: | ||
2465 | version "0.8.16" | ||
2466 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" | ||
2467 | dependencies: | ||
2468 | core-js "^1.0.0" | ||
2469 | isomorphic-fetch "^2.1.1" | ||
2470 | loose-envify "^1.0.0" | ||
2471 | object-assign "^4.1.0" | ||
2472 | promise "^7.1.1" | ||
2473 | setimmediate "^1.0.5" | ||
2474 | ua-parser-js "^0.7.9" | ||
2475 | |||
2453 | fbjs@^0.8.9: | 2476 | fbjs@^0.8.9: |
2454 | version "0.8.14" | 2477 | version "0.8.14" |
2455 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.14.tgz#d1dbe2be254c35a91e09f31f9cd50a40b2a0ed1c" | 2478 | resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.14.tgz#d1dbe2be254c35a91e09f31f9cd50a40b2a0ed1c" |
@@ -4058,7 +4081,7 @@ longest@^1.0.1: | |||
4058 | version "1.0.1" | 4081 | version "1.0.1" |
4059 | resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" | 4082 | resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" |
4060 | 4083 | ||
4061 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1: | 4084 | loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.0, loose-envify@^1.3.1: |
4062 | version "1.3.1" | 4085 | version "1.3.1" |
4063 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" | 4086 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" |
4064 | dependencies: | 4087 | dependencies: |
@@ -4948,6 +4971,14 @@ prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8: | |||
4948 | fbjs "^0.8.9" | 4971 | fbjs "^0.8.9" |
4949 | loose-envify "^1.3.1" | 4972 | loose-envify "^1.3.1" |
4950 | 4973 | ||
4974 | prop-types@^15.6.0: | ||
4975 | version "15.6.0" | ||
4976 | resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.0.tgz#ceaf083022fc46b4a35f69e13ef75aed0d639856" | ||
4977 | dependencies: | ||
4978 | fbjs "^0.8.16" | ||
4979 | loose-envify "^1.3.1" | ||
4980 | object-assign "^4.1.1" | ||
4981 | |||
4951 | proxy-middleware@~0.15.0: | 4982 | proxy-middleware@~0.15.0: |
4952 | version "0.15.0" | 4983 | version "0.15.0" |
4953 | resolved "https://registry.yarnpkg.com/proxy-middleware/-/proxy-middleware-0.15.0.tgz#a3fdf1befb730f951965872ac2f6074c61477a56" | 4984 | resolved "https://registry.yarnpkg.com/proxy-middleware/-/proxy-middleware-0.15.0.tgz#a3fdf1befb730f951965872ac2f6074c61477a56" |
@@ -5126,6 +5157,16 @@ react-transition-group@^1.2.0: | |||
5126 | prop-types "^15.5.6" | 5157 | prop-types "^15.5.6" |
5127 | warning "^3.0.0" | 5158 | warning "^3.0.0" |
5128 | 5159 | ||
5160 | react-virtualized@^9.7.6: | ||
5161 | version "9.18.5" | ||
5162 | resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.18.5.tgz#42dd390ebaa7ea809bfcaf775d39872641679b89" | ||
5163 | dependencies: | ||
5164 | babel-runtime "^6.26.0" | ||
5165 | classnames "^2.2.3" | ||
5166 | dom-helpers "^2.4.0 || ^3.0.0" | ||
5167 | loose-envify "^1.3.0" | ||
5168 | prop-types "^15.6.0" | ||
5169 | |||
5129 | react@^15.4.1: | 5170 | react@^15.4.1: |
5130 | version "15.6.1" | 5171 | version "15.6.1" |
5131 | resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df" | 5172 | resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df" |