diff --git a/app/extensions/brave/img/newtab/private_tab_pagearea_icon.svg b/app/extensions/brave/img/newtab/private_tab_pagearea_icon.svg new file mode 100644 index 00000000000..51917219b68 --- /dev/null +++ b/app/extensions/brave/img/newtab/private_tab_pagearea_icon.svg @@ -0,0 +1 @@ +private_tab_pagearea_icon \ No newline at end of file diff --git a/app/extensions/brave/locales/en-US/newtab.properties b/app/extensions/brave/locales/en-US/newtab.properties index d0a5c5633b4..2dd08c8b491 100644 --- a/app/extensions/brave/locales/en-US/newtab.properties +++ b/app/extensions/brave/locales/en-US/newtab.properties @@ -34,3 +34,7 @@ thumbRemoved=Thumb Removed. undoRemoved=Undo restoreAll=Restore All close.title=Close notification +privateTabTitle=This is a Private Tab +privateTabText1=Private tabs are not logged in page history. They are not counted in Brave Payments calculations and they can not be reopened with Command + Shift + T. +privateTabText2=If you click on a page link from within a Private Tab, it will also be private. You can open as many private tabs as you need and they will coexist with normal tabs. +privateTabText3=When you close Brave, all of your private tabs will vanish, forgotten forever. diff --git a/app/renderer/components/styles/global.js b/app/renderer/components/styles/global.js index 05aa5468e16..5d3a117f76e 100644 --- a/app/renderer/components/styles/global.js +++ b/app/renderer/components/styles/global.js @@ -5,6 +5,7 @@ const globalStyles = { breakpointExtensionButtonPadding: '720px', breakpointSmallWin32: '650px', breakpointTinyWin32: '500px', + breakpointNewPrivateTab: '890px', tab: { large: '120px', largeMedium: '83px', @@ -72,7 +73,8 @@ const globalStyles = { statsLightGray: '#999999', defaultIconBackground: '#F7F7F7', almostInvisible: 'rgba(255,255,255,0.01)', - urlBarOutline: '#bbb' + urlBarOutline: '#bbb', + alphaWhite: 'rgba(255,255,255,0.8)' }, radius: { borderRadius: '4px', @@ -124,7 +126,8 @@ const globalStyles = { dialogTopOffset: '30px', paymentsMargin: '20px', modalPanelHeaderMarginBottom: '.5em', - paddingHorizontal: '30px' + paddingHorizontal: '30px', + privateTabPadding: '40px' }, shadow: { switchShadow: 'inset 0 1px 4px rgba(0, 0, 0, 0.35)', diff --git a/js/about/newprivatetab.js b/js/about/newprivatetab.js new file mode 100644 index 00000000000..0c3411ebce5 --- /dev/null +++ b/js/about/newprivatetab.js @@ -0,0 +1,110 @@ +/* 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 React = require('react') +const {StyleSheet, css} = require('aphrodite') +const globalStyles = require('../../app/renderer/components/styles/global') +const Stats = require('./newTabComponents/stats') +const Clock = require('./newTabComponents/clock') +const privateTabIcon = require('../../app/extensions/brave/img/newtab/private_tab_pagearea_icon.svg') +// TODO: remove it once we use Aphrodite on stats and clock components +require('../../less/about/newtab.less') + +class NewPrivateTab extends React.Component { + render () { + if (!this.props.newTabData) { + return null + } + + return
+
+ + +
+
+
+
+

+

+

+

+

+
+
+ } +} + +const atBreakpoint = `@media screen and (max-width: ${globalStyles.breakpoint.breakpointNewPrivateTab})` +const styles = StyleSheet.create({ + newPrivateTab: { + background: `linear-gradient( + ${globalStyles.color.privateTabBackgroundActive}, + ${globalStyles.color.black100})`, + display: 'flex', + flexDirection: 'column', + alignItems: 'flex-start', + justifyContent: 'flex-start', + height: '100%', + minHeight: '100vh', + padding: '40px 60px', // same as newtab + + [atBreakpoint]: { + minHeight: '100%', + height: 'initial' + } + }, + + wrapper: { + display: 'flex', + alignSelf: 'center', + maxWidth: '840px', + padding: `${globalStyles.spacing.paddingHorizontal} 0`, + + [atBreakpoint]: { + flexDirection: 'column' + } + }, + + textWrapper: { + padding: `14px ${globalStyles.spacing.privateTabPadding}`, + + [atBreakpoint]: { + padding: '14px 0', + alignSelf: 'center', + display: 'flex', + flexDirection: 'column' + } + }, + + lionImage: { + backgroundImage: `url(${privateTabIcon})`, + backgroundRepeat: 'no-repeat', + backgroundPosition: 'center top', + backgroundSize: 'contain', + minWidth: '80px', + minHeight: '100px', + + [atBreakpoint]: { + alignSelf: 'center' + } + }, + + title: { + color: globalStyles.color.white100, + fontSize: '30px', + marginBottom: globalStyles.spacing.paddingHorizontal + }, + + text: { + paddingBottom: globalStyles.spacing.paddingHorizontal, + lineHeight: '1.5', + fontSize: '17px' + }, + + alphaWhite: { + color: globalStyles.color.alphaWhite + } +}) + +module.exports = NewPrivateTab diff --git a/js/about/newtab.js b/js/about/newtab.js index 13bcbddaa19..7dded4ae3da 100644 --- a/js/about/newtab.js +++ b/js/about/newtab.js @@ -20,6 +20,7 @@ const siteTags = require('../constants/siteTags') const config = require('../constants/config') const backgrounds = require('../data/backgrounds') const {random} = require('../../app/common/lib/randomUtil') +const NewPrivateTab = require('./newprivatetab') const ipc = window.chrome.ipcRenderer @@ -231,12 +232,12 @@ class NewTabPage extends React.Component { render () { // don't render if user prefers an empty page - if (this.state.showEmptyPage) { + if (this.state.showEmptyPage && !this.props.isIncognito) { return
} if (this.props.isIncognito) { - return
+ return } // don't render until object is found diff --git a/less/about/newtab.less b/less/about/newtab.less index e5abed29581..1aab1fd3db1 100644 --- a/less/about/newtab.less +++ b/less/about/newtab.less @@ -87,84 +87,6 @@ ul { min-height: 100vh; padding: 40px 60px; - .statsBar { - padding: 40px 0; - display: flex; - justify-content: space-between; - - .statsBlock { - margin-right: 40px; - margin-bottom: 20px; - - span { - display: block; - } - - .counter { - font-size: 44px; - line-height: 53px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; - max-width: 200px; - - &.trackers { - color: @statsOrange; - } - &.ads { - color: @statsRed; - } - &.https { - color: @statsBlue; - } - &.timeSaved { - color: @statsLightGray; - display: flex; - align-items: baseline; - } - - .text { - display: inline; - color: @statsLightGray; - font-size: 20px; - line-height: 24px; - margin-left: 3px; - } - } - - .statsText { - font-size: 13px; - color: #fff; - } - } - - .clock { - line-height: 1; - -webkit-user-select: none; - cursor: default; - - .time { - font-size: 75px; - font-weight: 200; - color: #fff; - } - - .timePeriod { - color: #fff; - display: inline-block; - font-size: 20px; - font-weight: 400; - margin-top: 6px; - vertical-align: top; - } - - .dayTime { - font-size: 51px; - color: #fff; - } - } - } - .topSitesContainer { width: 100%; text-align: right; @@ -421,6 +343,86 @@ ul { } } +.statsBar { + width: 100%; + padding: 40px 0; + display: flex; + justify-content: space-between; + + .statsBlock { + margin-right: 40px; + margin-bottom: 20px; + + span { + display: block; + } + + .counter { + font-size: 44px; + line-height: 53px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 200px; + + &.trackers { + color: @statsOrange; + } + &.ads { + color: @statsRed; + } + &.https { + color: @statsBlue; + } + &.timeSaved { + color: @statsLightGray; + display: flex; + align-items: baseline; + } + + .text { + display: inline; + color: @statsLightGray; + font-size: 20px; + line-height: 24px; + margin-left: 3px; + } + } + + .statsText { + font-size: 13px; + color: #fff; + } + } + + .clock { + line-height: 1; + -webkit-user-select: none; + cursor: default; + + .time { + font-size: 75px; + font-weight: 200; + color: #fff; + } + + .timePeriod { + color: #fff; + display: inline-block; + font-size: 20px; + font-weight: 400; + margin-top: 6px; + vertical-align: top; + } + + .dayTime { + font-size: 51px; + color: #fff; + } + } +} + + @media (max-width: 730px) { .dynamicBackground { min-height: 100%; @@ -434,26 +436,26 @@ ul { margin-bottom: 20px; } - .statsBar { - flex-direction: column-reverse; - padding-top: 0; + .topSitesContainer { + text-align: center; + padding-bottom: 20px; + } + } - .statsBlock { - margin: 0 0 15px; - width: 50%; - padding-right: 20px; - } + .statsBar { + flex-direction: column-reverse; + padding-top: 0; - .clock { - display: flex; - flex: 1; - justify-content: center; - padding-bottom: 20px; - } + .statsBlock { + margin: 0 0 15px; + width: 50%; + padding-right: 20px; } - .topSitesContainer { - text-align: center; + .clock { + display: flex; + flex: 1; + justify-content: center; padding-bottom: 20px; } } diff --git a/test/unit/about/newTabPageTest.js b/test/unit/about/newTabPageTest.js index 632576af26c..06233ecc69a 100644 --- a/test/unit/about/newTabPageTest.js +++ b/test/unit/about/newTabPageTest.js @@ -11,7 +11,7 @@ const assert = require('assert') const Immutable = require('immutable') const fakeElectron = require('../lib/fakeElectron') const _ = require('underscore') -let NewTabPage, randomSpy, Clock, Stats, FooterInfo +let NewTabPage, randomSpy, Clock, Stats, FooterInfo, NewPrivateTab require('../braveUnit') const randomWrapper = { @@ -35,6 +35,7 @@ describe('NewTab component unit tests', function () { Clock = require('../../../js/about/newTabComponents/clock') Stats = require('../../../js/about/newTabComponents/stats') FooterInfo = require('../../../js/about/newTabComponents/footerInfo') + NewPrivateTab = require('../../../js/about/newprivatetab') }) after(function () { @@ -151,8 +152,8 @@ describe('NewTab component unit tests', function () { assert.equal(wrapper.find('div.empty').length, 1) }) - it('renders an empty div if isIncognito props is true', function () { - assert.equal(incognitoWrapper.find('div.empty').length, 1) + it('renders newPrivateTab page if isIncognito props is true', function () { + assert.equal(incognitoWrapper.find(NewPrivateTab).length, 1) }) })