From ae1014ed7d8f2532c4ec33b530662665dc16b141 Mon Sep 17 00:00:00 2001 From: haraldox Date: Fri, 23 Feb 2018 12:12:54 +0100 Subject: complete titlebar for Windows & Linux --- .vscode/launch.json | 2 +- package.json | 2 +- src/components/layout/AppLayout.js | 4 +- src/environment.js | 1 + src/index.js | 4 +- src/lib/Menu.js | 318 +++++++++++++++++++++++++++++-------- 6 files changed, 263 insertions(+), 68 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index f6c20b520..98408278c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "protocol": "inspector", "env": { "NODE_ENV": "development", - "OS_PLATFORM": "win32" + // "OS_PLATFORM": "win32" } }, { diff --git a/package.json b/package.json index 7922eff03..78f7a3291 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "start": "electron ./build", "start:local": "cross-env LOCAL_API=1 yarn start", "start:live": "cross-env LIVE_API=1 yarn start", - "dev": "cross-env NODE_ENV=development OS_PLATFORM=win32 gulp dev", + "dev": "cross-env NODE_ENV=development gulp dev", "lint": "eslint src", "sign": "gulp sign", "prebuild": "gulp build", diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js index 6162840be..686476317 100644 --- a/src/components/layout/AppLayout.js +++ b/src/components/layout/AppLayout.js @@ -7,6 +7,8 @@ import { TitleBar } from 'electron-react-titlebar'; import InfoBar from '../ui/InfoBar'; import globalMessages from '../../i18n/globalMessages'; +import { isMac } from '../../environment'; + function createMarkup(HTMLString) { return { __html: HTMLString }; } @@ -88,7 +90,7 @@ export default class AppLayout extends Component { return (
- + {!isMac && }
{sidebar}
diff --git a/src/environment.js b/src/environment.js index 4dca0807d..e1762129b 100644 --- a/src/environment.js +++ b/src/environment.js @@ -14,6 +14,7 @@ export const isWindows = platform === 'win32'; export const isLinux = platform === 'linux'; export const ctrlKey = isMac ? '⌘' : 'Ctrl'; +export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; let api; if (!isDevMode || (isDevMode && useLiveAPI)) { diff --git a/src/index.js b/src/index.js index e8818af96..2acb8e2cb 100644 --- a/src/index.js +++ b/src/index.js @@ -4,7 +4,7 @@ import path from 'path'; import windowStateKeeper from 'electron-window-state'; -import { isDevMode, isWindows } from './environment'; +import { isDevMode, isMac, isWindows } from './environment'; import ipcApi from './electron/ipc-api'; import Tray from './lib/Tray'; import Settings from './electron/Settings'; @@ -72,7 +72,7 @@ const createWindow = () => { height: mainWindowState.height, minWidth: 600, minHeight: 500, - titleBarStyle: process.env.OS_PLATFORM || process.platform === 'win32' ? '' : 'hidden', + titleBarStyle: isMac ? 'hidden' : '', frame: false, backgroundColor: '#3498db', autoHideMenuBar: true, diff --git a/src/lib/Menu.js b/src/lib/Menu.js index 2bdd36b2c..475352bba 100644 --- a/src/lib/Menu.js +++ b/src/lib/Menu.js @@ -1,10 +1,14 @@ import { remote, shell } from 'electron'; import { autorun, computed, observable, toJS } from 'mobx'; -import { isMac } from '../environment'; +import { isMac, ctrlKey, cmdKey } from '../environment'; const { app, Menu, dialog } = remote; +function getActiveWebview() { + return window.franz.stores.services.active.webview; +} + const template = [ { label: 'Edit', @@ -114,8 +118,161 @@ const template = [ }, ]; +const titleBarTemplate = [ + { + label: 'Edit', + submenu: [ + { + label: 'Undo', + accelerator: `${ctrlKey}+Z`, + click() { + getActiveWebview().undo(); + }, + }, + { + label: 'Redo', + accelerator: `${ctrlKey}+Y`, + click() { + getActiveWebview().redo(); + }, + }, + { + type: 'separator', + }, + { + label: 'Cut', + accelerator: `${ctrlKey}+X`, + click() { + getActiveWebview().cut(); + }, + }, + { + label: 'Copy', + accelerator: `${ctrlKey}+C`, + click() { + getActiveWebview().copy(); + }, + }, + { + label: 'Paste', + accelerator: `${ctrlKey}+V`, + click() { + getActiveWebview().paste(); + }, + }, + { + label: 'Paste and Match Style', + accelerator: `${ctrlKey}+Shift+V`, + click() { + getActiveWebview().pasteAndMatchStyle(); + }, + }, + { + label: 'Delete', + click() { + getActiveWebview().delete(); + }, + }, + { + label: 'Select All', + accelerator: `${ctrlKey}+A`, + click() { + getActiveWebview().selectAll(); + }, + }, + ], + }, + { + label: 'View', + submenu: [ + { + type: 'separator', + }, + { + label: 'Reset Zoom', + accelerator: `${ctrlKey}+0`, + click() { + getActiveWebview().setZoomLevel(0); + }, + }, + { + label: 'Zoom in', + accelerator: `${ctrlKey}+=`, + click() { + getActiveWebview().getZoomLevel((zoomLevel) => { + getActiveWebview().setZoomLevel(zoomLevel === 5 ? zoomLevel : zoomLevel + 1); + }); + }, + }, + { + label: 'Zoom out', + accelerator: `${ctrlKey}+-`, + click() { + getActiveWebview().getZoomLevel((zoomLevel) => { + getActiveWebview().setZoomLevel(zoomLevel === -5 ? zoomLevel : zoomLevel - 1); + }); + }, + }, + ], + }, + { + label: 'Services', + submenu: [], + }, + { + label: 'Window', + submenu: [ + { + label: 'Minimize', + accelerator: 'Alt+M', + click(menuItem, browserWindow) { + browserWindow.minimize(); + }, + }, + { + label: 'Close', + accelerator: 'Alt+W', + click(menuItem, browserWindow) { + browserWindow.close(); + }, + }, + ], + }, + { + label: '?', + submenu: [ + { + label: 'Learn More', + click() { shell.openExternal('http://meetfranz.com'); }, + }, + { + label: 'Changelog', + click() { shell.openExternal('https://github.com/meetfranz/franz/blob/master/CHANGELOG.md'); }, + }, + { + type: 'separator', + }, + { + label: 'Support', + click() { shell.openExternal('http://meetfranz.com/support'); }, + }, + { + type: 'separator', + }, + { + label: 'Terms of Service', + click() { shell.openExternal('https://meetfranz.com/terms'); }, + }, + { + label: 'Privacy Statement', + click() { shell.openExternal('https://meetfranz.com/privacy'); }, + }, + ], + }, +]; + export default class FranzMenu { - @observable tpl = template; + @observable tpl = isMac ? template : titleBarTemplate; @observable currentTemplate = null; constructor(stores, actions) { @@ -133,10 +290,16 @@ export default class FranzMenu { const tpl = toJS(this.tpl); tpl[1].submenu.push({ - role: 'toggledevtools', + type: 'separator', + }, { + label: 'Toggle Developer Tools', + accelerator: `${cmdKey}+Alt+I`, + click: (menuItem, browserWindow) => { + browserWindow.webContents.toggleDevTools(); + }, }, { - label: 'Toggle Service Developer Tools', - accelerator: 'CmdOrCtrl+Shift+Alt+i', + label: 'Open Service Developer Tools', + accelerator: `${cmdKey}+Shift+Alt+I`, click: () => { this.actions.service.openDevToolsForActiveService(); }, @@ -145,7 +308,7 @@ export default class FranzMenu { tpl[1].submenu.unshift({ label: 'Reload Service', id: 'reloadService', - accelerator: 'CmdOrCtrl+R', + accelerator: `${cmdKey}+R`, click: () => { if (this.stores.user.isLoggedIn && this.stores.services.enabled.length > 0) { @@ -156,56 +319,69 @@ export default class FranzMenu { }, }, { label: 'Reload Franz', - accelerator: 'CmdOrCtrl+Shift+R', + accelerator: `${cmdKey}+Shift+R`, click: () => { window.location.reload(); }, }); - if (isMac) { - tpl.unshift({ - label: app.getName(), - submenu: [ - { - role: 'about', - }, - { - type: 'separator', - }, - { - label: 'Settings', - accelerator: 'CmdOrCtrl+,', - click: () => { - this.actions.ui.openSettings({ path: 'app' }); - }, - }, - { - type: 'separator', - }, - { - role: 'services', - submenu: [], - }, - { - type: 'separator', - }, - { - role: 'hide', - }, - { - role: 'hideothers', - }, - { - role: 'unhide', - }, - { - type: 'separator', - }, - { - role: 'quit', + tpl.unshift({ + label: isMac ? app.getName() : 'File', + submenu: [ + { + role: 'about', + }, + { + type: 'separator', + }, + { + label: 'Settings', + accelerator: 'CmdOrCtrl+,', + click: () => { + this.actions.ui.openSettings({ path: 'app' }); }, - ], - }); + }, + { + type: 'separator', + }, + { + role: 'services', + submenu: [], + }, + { + type: 'separator', + }, + { + role: 'hide', + }, + { + role: 'hideothers', + }, + { + role: 'unhide', + }, + { + type: 'separator', + }, + { + role: 'quit', + }, + ], + }); + + const about = { + label: 'About Franz', + click: () => { + dialog.showMessageBox({ + type: 'info', + title: 'Franz', + message: 'Franz', + detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, + }); + }, + }; + + if (isMac) { // Edit menu. tpl[1].submenu.push( { @@ -223,25 +399,41 @@ export default class FranzMenu { ], }, ); + + tpl[4].submenu.unshift(about, { + type: 'separator', + }); } else { - tpl[4].submenu.unshift({ - role: 'about', - click: () => { - dialog.showMessageBox({ - type: 'info', - title: 'Franz', - message: 'Franz', - detail: `Version: ${remote.app.getVersion()}\nRelease: ${process.versions.electron} / ${process.platform} / ${process.arch}`, - }); + tpl[0].submenu = [ + { + label: 'Preferences...', + accelerator: 'Ctrl+P', + click: () => { + this.actions.ui.openSettings({ path: 'app' }); + }, }, - }); + { + type: 'separator', + }, + { + label: 'Quit', + accelerator: 'Alt+F4', + click: () => { + app.quit(); + }, + }, + ]; + + tpl[5].submenu.push({ + type: 'separator', + }, about); } const serviceTpl = this.serviceTpl; serviceTpl.unshift({ label: 'Add new Service', - accelerator: 'CmdOrCtrl+N', + accelerator: `${cmdKey}+N`, click: () => { this.actions.ui.openSettings({ path: 'recipes' }); }, @@ -250,7 +442,7 @@ export default class FranzMenu { }); if (serviceTpl.length > 0) { - tpl[isMac ? 3 : 2].submenu = toJS(this.serviceTpl); + tpl[3].submenu = toJS(this.serviceTpl); } this.currentTemplate = tpl; @@ -264,7 +456,7 @@ export default class FranzMenu { if (this.stores.user.isLoggedIn) { return services.map((service, i) => ({ label: this._getServiceName(service), - accelerator: i <= 9 ? `CmdOrCtrl+${i + 1}` : null, + accelerator: i <= 9 ? `${cmdKey}+${i + 1}` : null, type: 'radio', checked: service.isActive, click: () => { -- cgit v1.2.3-70-g09d2