diff --git a/img/window-actions/linux/titlebutton-close-hover.png b/img/window-actions/linux/titlebutton-close-hover.png new file mode 100755 index 00000000000..73405fc1881 Binary files /dev/null and b/img/window-actions/linux/titlebutton-close-hover.png differ diff --git a/img/window-actions/linux/titlebutton-close.png b/img/window-actions/linux/titlebutton-close.png new file mode 100755 index 00000000000..65a9a23c5f8 Binary files /dev/null and b/img/window-actions/linux/titlebutton-close.png differ diff --git a/img/window-actions/linux/titlebutton-maximize-hover.png b/img/window-actions/linux/titlebutton-maximize-hover.png new file mode 100755 index 00000000000..2de4e7446c8 Binary files /dev/null and b/img/window-actions/linux/titlebutton-maximize-hover.png differ diff --git a/img/window-actions/linux/titlebutton-maximize.png b/img/window-actions/linux/titlebutton-maximize.png new file mode 100755 index 00000000000..9fb27510706 Binary files /dev/null and b/img/window-actions/linux/titlebutton-maximize.png differ diff --git a/img/window-actions/linux/titlebutton-minimize-hover.png b/img/window-actions/linux/titlebutton-minimize-hover.png new file mode 100755 index 00000000000..017991834cb Binary files /dev/null and b/img/window-actions/linux/titlebutton-minimize-hover.png differ diff --git a/img/window-actions/linux/titlebutton-minimize.png b/img/window-actions/linux/titlebutton-minimize.png new file mode 100755 index 00000000000..6ced316d820 Binary files /dev/null and b/img/window-actions/linux/titlebutton-minimize.png differ diff --git a/img/window-actions/windows/10/close-btn-white.svg b/img/window-actions/windows/10/close-btn-white.svg new file mode 100644 index 00000000000..72e603cbd55 --- /dev/null +++ b/img/window-actions/windows/10/close-btn-white.svg @@ -0,0 +1,63 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/img/window-actions/windows/10/close-btn.svg b/img/window-actions/windows/10/close-btn.svg new file mode 100644 index 00000000000..8dc9e16250f --- /dev/null +++ b/img/window-actions/windows/10/close-btn.svg @@ -0,0 +1,62 @@ + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/img/window-actions/windows/10/max-btn-fullscreen.svg b/img/window-actions/windows/10/max-btn-fullscreen.svg new file mode 100644 index 00000000000..c534778f540 --- /dev/null +++ b/img/window-actions/windows/10/max-btn-fullscreen.svg @@ -0,0 +1,79 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/img/window-actions/windows/10/max-btn.svg b/img/window-actions/windows/10/max-btn.svg new file mode 100644 index 00000000000..c6beccbfddb --- /dev/null +++ b/img/window-actions/windows/10/max-btn.svg @@ -0,0 +1,74 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/img/window-actions/windows/10/min-btn.svg b/img/window-actions/windows/10/min-btn.svg new file mode 100644 index 00000000000..22f67f36884 --- /dev/null +++ b/img/window-actions/windows/10/min-btn.svg @@ -0,0 +1,74 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/js/components/main.js b/js/components/main.js index e7a7b9d23d1..0930726664a 100644 --- a/js/components/main.js +++ b/js/components/main.js @@ -38,6 +38,7 @@ const ContextMenu = require('./contextMenu') const PopupWindow = require('./popupWindow') const NoScriptInfo = require('./noScriptInfo') const LongPressButton = require('./longPressButton') +const WindowActionBar = require('./windowActionBar') // Constants const config = require('../constants/config') @@ -584,11 +585,7 @@ class Main extends ImmutableComponent { if (!e.target.className.includes('navigatorWrapper')) { return } - if (currentWindow.isMaximized()) { - currentWindow.maximize() - } else { - currentWindow.unmaximize() - } + return (!currentWindow.isMaximized()) ? currentWindow.maximize() : currentWindow.unmaximize() } onMouseDown (e) { @@ -866,6 +863,7 @@ class Main extends ImmutableComponent { braveShieldsDown: !braverySettings.shieldsUp })} onClick={this.onBraveMenu} /> + {process.platform === 'darwin' ? null : } diff --git a/js/components/windowActionBar.js b/js/components/windowActionBar.js new file mode 100644 index 00000000000..3a763a06986 --- /dev/null +++ b/js/components/windowActionBar.js @@ -0,0 +1,71 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +const os = require('os') +const React = require('react') +const ImmutableComponent = require('./immutableComponent') +const currentWindow = require('../../app/renderer/currentWindow') + +class WindowActionBar extends ImmutableComponent { + constructor () { + super() + this.onDoubleClick = this.onDoubleClick.bind(this) + this.onMinimizeClick = this.onMinimizeClick.bind(this) + this.onMaximizeClick = this.onMaximizeClick.bind(this) + this.onCloseClick = this.onCloseClick.bind(this) + this.osClass = this.getPlatformCssClass() + } + + get buttonClass () { + return (this.props.windowMaximized ? 'fullscreen' : '') + } + + getPlatformCssClass () { + switch (os.platform()) { + case 'linux': + return 'linux' + case 'win32': + if (/10.0./.test(os.release())) { + return 'win-10' + } else if (/6.1./.test(os.release())) { + return 'win-7' + } else { + return 'win' + } + default: + return 'hidden' + } + } + + onMinimizeClick (e) { + currentWindow.minimize() + } + + onMaximizeClick (e) { + return (!currentWindow.isMaximized()) ? currentWindow.maximize() : currentWindow.unmaximize() + } + + onCloseClick (e) { + currentWindow.close() + } + + onDoubleClick (e) { + if (!e.target.className.includes('navigatorWrapper')) { + return + } + this.onMaximizeClick(e) + } + + render () { + return
+
+ + + +
+
+ } +} + +module.exports = WindowActionBar diff --git a/js/stores/appStore.js b/js/stores/appStore.js index f1ccd7f71d1..d121c33e665 100644 --- a/js/stores/appStore.js +++ b/js/stores/appStore.js @@ -134,7 +134,8 @@ const createWindow = (browserOpts, defaults, frameOpts, windowState) => { titleBarStyle: 'hidden-inset', autoHideMenuBar: autoHideMenuBarSetting, title: appConfig.name, - webPreferences: defaults.webPreferences + webPreferences: defaults.webPreferences, + frame: (process.platform === 'darwin') } if (process.platform === 'linux') { diff --git a/less/navigationBar.less b/less/navigationBar.less index 8f2a6f52949..0d0e36a4696 100644 --- a/less/navigationBar.less +++ b/less/navigationBar.less @@ -29,6 +29,137 @@ - (@navbarBraveButtonWidth + 2 * @navbarButtonSpacing); } +// Window Header +.window-header { + -webkit-user-select: none; + -webkit-app-region: drag; + height: 18px; + padding: 3px 0; + margin: 0px; + display: flex; + line-height: 30px; + + .hidden { + display: none; + } + + .title-bar-btns { + -webkit-app-region: no-drag; + } + + .win-7, .win-10 { + margin: -13px 3px 0 0; + + button.win-action-btn { + outline: 0; + cursor: pointer; + width: 45px; + height: 23px; + color: #b1acac; + background-size: 12px 12px!important; + background-position: center!important; + border: 1px solid #e1e1e1; + display: inline-block; + padding: 12px; + + &.fullscreen { + height:21px; + padding:6px; + } + + &.close-btn { + background: url('../img/window-actions/windows/10/close-btn.svg') no-repeat; + &:hover { + background: url('../img/window-actions/windows/10/close-btn-white.svg') no-repeat; + background-color: #e5182c; + } + &:active { + background: url('../img/window-actions/windows/10/close-btn-white.svg') no-repeat; + background-color: #ef717c; + } + } + + &.min-btn { + border-right: 0px; + border-bottom-left-radius: 5px; + background: url('../img/window-actions/windows/10/min-btn.svg') no-repeat; + &:hover { + background-color: #e5e5e5; + } + &:active { + background-color: #cacacb; + } + } + + &.max-btn { + background: url('../img/window-actions/windows/10/max-btn.svg') no-repeat; + border-right: 0px; + &:hover { + background-color: #e5e5e5; + } + &:active { + background-color: #cacacb; + } + &.fullscreen { + background: url('../img/window-actions/windows/10/max-btn-fullscreen.svg') no-repeat; + &:hover { + background-color: #e5e5e5; + } + &:active { + background-color: #cacacb; + } + } + } + } + + } + + .linux { + button { + outline: 0; + cursor: pointer; + width: 14px; + height: 14px; + color: transparent; + background-color: transparent; + background-position: center; + background-repeat: no-repeat; + border-width: 0; + border-radius: 50%; + display: inline-block; + padding: 0px; + margin-right: 15px; + } + + min-btn:backdrop, .max-btn:backdrop, .close-btn:backdrop { + opacity: 1; + } + + .close-btn { + background: url('../img/window-actions/linux/titlebutton-close.png') 0 0 / contain no-repeat; + } + + .min-btn { + background: url('../img/window-actions/linux/titlebutton-minimize.png') 0 0 / contain no-repeat; + } + + .max-btn { + background: url('../img/window-actions/linux/titlebutton-maximize.png') 0 0 / contain no-repeat; + } + + .close-btn:hover { + background: url('../img/window-actions/linux/titlebutton-close-hover.png') 0 0 / contain no-repeat; + } + + .min-btn:hover { + background: url('../img/window-actions/linux/titlebutton-minimize-hover.png') 0 0 / contain no-repeat; + } + + .max-btn:hover { + background: url('../img/window-actions/linux/titlebutton-maximize-hover.png') 0 0 / contain no-repeat; + } + } +} // Here I grouped the rules to keep the layout of the top bar consistent. // The tricky part is to keep the title in `#navigator` centered when the diff --git a/less/variables.less b/less/variables.less index 0ae0af1591e..74d87376aa5 100644 --- a/less/variables.less +++ b/less/variables.less @@ -66,7 +66,7 @@ @bookmarksFileIconSize: 13px; @bookmarksFolderIconSize: 15px; -@navbarButtonSpacing: 4px; +@navbarButtonSpacing: 14px; @navbarButtonWidth: 35px; @navbarBraveButtonWidth: 23px; @navbarBraveButtonMarginLeft: 80px; diff --git a/test/components/windowTest.js b/test/components/windowTest.js index fb255f5fec2..596322e3355 100644 --- a/test/components/windowTest.js +++ b/test/components/windowTest.js @@ -1,7 +1,7 @@ /* global describe, it, before */ const Brave = require('../lib/brave') -const {activeWebview} = require('../lib/selectors') +const {activeWebview, minimizeButton, maximizeButton, closeButton} = require('../lib/selectors') describe('application window', function () { describe('application launch', function () { @@ -146,6 +146,56 @@ describe('application window', function () { }) }) + if (process.platform !== 'darwin') { + describe('window top action buttons', function () { + Brave.beforeAll(this) + + before(function * () { + yield this.app.client + .waitUntilWindowLoaded() + .waitForUrl(Brave.newTabUrl) + .windowByIndex(0) + .resizeWindow(600, 700) + .waitUntilWindowLoaded() + }) + + it('should be maximized when maximize button is clicked', function * () { + yield this.app.client + .click(maximizeButton) + .windowByIndex(0) + .getWindowWidth().should.eventually.be.getPrimaryDisplayWidth() + .getWindowHeight().should.eventually.be.getPrimaryDisplayHeight() + }) + + it('should be minimized when minimize button is clicked', function * () { + yield this.app.client + .click(minimizeButton) + .waitUntil(function () { + return this.windowByIndex(0).isWindowMinimized() + }) + }) + + it('should close the new window when close button is clicked', function * () { + yield this.app.client + .windowByIndex(0) + .newWindowAction() + .waitUntil(function () { + return this.getWindowCount().then((count) => { + return count === 2 + }) + }) + .windowByIndex(1) + .waitUntilWindowLoaded() + .click(closeButton) + .waitUntil(function () { + return this.getWindowCount().then((count) => { + return count === 1 + }) + }) + }) + }) + } + describe('windw.open with click', function () { describe('with features', function () { Brave.beforeAll(this) diff --git a/test/lib/selectors.js b/test/lib/selectors.js index eb8c71de6eb..89a40088166 100644 --- a/test/lib/selectors.js +++ b/test/lib/selectors.js @@ -1,4 +1,7 @@ module.exports = { + minimizeButton: '.min-btn', + maximizeButton: '.max-btn', + closeButton: '.close-btn', urlInput: '#urlInput', activeWebview: '.frameWrapper.isActive webview', activeTab: '.tab.active',