diff --git a/app/common/state/tabContentState/titleState.js b/app/common/state/tabContentState/titleState.js
index 6bdc5b75f47..1c21e294c35 100644
--- a/app/common/state/tabContentState/titleState.js
+++ b/app/common/state/tabContentState/titleState.js
@@ -8,6 +8,7 @@
const partitionState = require('../tabContentState/partitionState')
const privateState = require('../tabContentState/privateState')
const frameStateUtil = require('../../../../js/state/frameStateUtil')
+ const tabUIState = require('../tabUIState')
// Utils
const {isEntryIntersected} = require('../../../../app/renderer/lib/observerUtil')
@@ -26,11 +27,13 @@
const isActive = frameStateUtil.isFrameKeyActive(state, frameKey)
const isPartition = partitionState.isPartitionTab(state, frameKey)
const isPrivate = privateState.isPrivateTab(state, frameKey)
- const secondaryIconVisible = !isNewTabPage && (isPartition || isPrivate || isActive)
+ const secondaryIconVisible = !isNewTabPage &&
+ (isPartition || isPrivate || isActive) &&
+ tabUIState.showTabEndIcon(state, frameKey)
// If title is being intersected by ~half with other icons visible
// such as closeTab (activeTab) or session icons, do not show it
- if (isEntryIntersected(state, 'tabs', intersection.at45) && secondaryIconVisible) {
+ if (isEntryIntersected(state, 'tabs', intersection.at46) && secondaryIconVisible) {
return false
}
diff --git a/app/common/state/tabUIState.js b/app/common/state/tabUIState.js
index 072ff4f0d04..55159538bc9 100644
--- a/app/common/state/tabUIState.js
+++ b/app/common/state/tabUIState.js
@@ -6,8 +6,6 @@
const settings = require('../../../js/constants/settings')
// State helpers
-const partitionState = require('../../common/state/tabContentState/partitionState')
-const privateState = require('../../common/state/tabContentState/privateState')
const closeState = require('../../common/state/tabContentState/closeState')
const frameStateUtil = require('../../../js/state/frameStateUtil')
@@ -20,7 +18,6 @@ const {getSetting} = require('../../../js/settings')
// Styles
const {intersection} = require('../../renderer/components/styles/global')
-const {theme} = require('../../renderer/components/styles/theme')
module.exports.getThemeColor = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)
@@ -76,7 +73,7 @@ module.exports.showTabEndIcon = (state, frameKey) => {
return (
!closeState.hasFixedCloseIcon(state, frameKey) &&
!closeState.hasRelativeCloseIcon(state, frameKey) &&
- !isEntryIntersected(state, 'tabs', intersection.at40)
+ !isEntryIntersected(state, 'tabs', intersection.at46)
)
}
@@ -99,41 +96,3 @@ module.exports.centralizeTabIcons = (state, frameKey, isPinned) => {
return isPinned || isEntryIntersected(state, 'tabs', intersection.at40)
}
-
-module.exports.getTabEndIconBackgroundColor = (state, frameKey) => {
- const frame = frameStateUtil.getFrameByKey(state, frameKey)
-
- if (frame == null) {
- return false
- }
-
- const themeColor = module.exports.getThemeColor(state, frameKey)
- const isPrivate = privateState.isPrivateTab(state, frameKey)
- const isPartition = partitionState.isPartitionTab(state, frameKey)
- const isHover = frameStateUtil.getTabHoverState(state, frameKey)
- const isActive = frameStateUtil.isFrameKeyActive(state, frameKey)
- const hasCloseIcon = closeState.showCloseTabIcon(state, frameKey)
- const isIntersecting = isEntryIntersected(state, 'tabs', intersection.at40)
-
- let backgroundColor = theme.tab.background
-
- if (isActive && themeColor) {
- backgroundColor = themeColor
- }
- if (isActive && !themeColor) {
- backgroundColor = theme.tab.active.background
- }
- if (isIntersecting) {
- backgroundColor = 'transparent'
- }
- if (!isActive && isPrivate) {
- backgroundColor = theme.tab.private.background
- }
- if ((isActive || isHover) && isPrivate) {
- backgroundColor = theme.tab.active.private.background
- }
-
- return isPartition || isPrivate || hasCloseIcon
- ? `linear-gradient(to left, ${backgroundColor} 10px, transparent 40px)`
- : `linear-gradient(to left, ${backgroundColor} 0, transparent 12px)`
-}
diff --git a/app/extensions/brave/img/tabs/close_btn.svg b/app/extensions/brave/img/tabs/close_btn.svg
deleted file mode 100644
index 926636ea455..00000000000
--- a/app/extensions/brave/img/tabs/close_btn.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/app/renderer/components/frame/frame.js b/app/renderer/components/frame/frame.js
index 1ce7897ee17..230de5213a8 100644
--- a/app/renderer/components/frame/frame.js
+++ b/app/renderer/components/frame/frame.js
@@ -869,12 +869,14 @@ class Frame extends React.Component {
const contextMenu = currentWindow.get('contextMenuDetail')
const tab = tabId && tabId > -1 && tabState.getByTabId(state, tabId)
+ const previewFrameKey = currentWindow.get('previewFrameKey')
+
const props = {}
// used in renderer
props.transitionState = ownProps.transitionState
props.partition = frameStateUtil.getPartition(frame)
props.isFullScreen = frame.get('isFullScreen')
- props.isPreview = frame.get('key') === currentWindow.get('previewFrameKey')
+ props.isPreview = frame.get('key') === previewFrameKey
props.isActive = frameStateUtil.isFrameKeyActive(currentWindow, frame.get('key'))
props.showFullScreenWarning = frame.get('showFullScreenWarning')
props.location = location
@@ -956,8 +958,7 @@ class Frame extends React.Component {
}
{ this.webviewContainer = node }}
className={cx({
- webviewContainer: true,
- isPreview: this.props.isPreview
+ webviewContainer: true
})} />
{
diff --git a/app/renderer/components/main/main.js b/app/renderer/components/main/main.js
index 8dd21193cb1..b050ece37a9 100644
--- a/app/renderer/components/main/main.js
+++ b/app/renderer/components/main/main.js
@@ -574,6 +574,7 @@ class Main extends React.Component {
item.get('frameOrigin') ? activeOrigin === item.get('frameOrigin') : true).size > 0
props.showFindBar = activeFrame.get('findbarShown') && !activeFrame.get('isFullScreen')
props.sortedFrames = frameStateUtil.getSortedFrameKeys(currentWindow)
+ props.hasFramePreview = currentWindow.get('previewFrameKey') != null
props.showDownloadBar = currentWindow.getIn(['ui', 'downloadsToolbar', 'isVisible']) &&
state.get('downloads') && state.get('downloads').size > 0
props.title = activeFrame.get('title')
@@ -736,7 +737,10 @@ class Main extends React.Component {
}
{ this.tabNode = node }}
className={css(
styles.tabArea__tab,
-
// tab icon only (on pinned tab / small tab)
this.props.isPinnedTab && styles.tabArea__tab_pinned,
this.props.centralizeTabIcons && styles.tabArea__tab_centered,
- this.props.showAudioTopBorder && styles.tabArea__tab_audioTopBorder,
-
- // Windows specific style (color)
- isWindows && styles.tabArea__tab_forWindows,
-
- // Set background-color and color to active tab and private tab
- this.props.isActive && styles.tabArea__tab_active,
- this.props.isPrivateTab && styles.tabArea__tab_private,
- (this.props.isPrivateTab && this.props.isActive) && styles.tabArea__tab_private_active,
-
- // Apply themeColor if tab is active and not private
- isThemed && styles.tabArea__tab_themed
+ this.props.showAudioTopBorder && styles.tabArea__tab_audioTopBorder
)}
- style={instanceStyles}
data-test-id='tab'
data-test-active-tab={this.props.isActive}
data-test-pinned-tab={this.props.isPinnedTab}
data-test-private-tab={this.props.isPrivateTab}
data-frame-key={this.props.frameKey}
draggable
- title={this.props.title}
+ title={this.props.isPreview ? null : this.props.title}
onDrag={this.onDrag}
onDragStart={this.onDragStart}
onDragEnd={this.onDragEnd}
@@ -400,20 +451,61 @@ class Tab extends React.Component {
const styles = StyleSheet.create({
tabArea: {
boxSizing: 'border-box',
- display: 'inline-block',
position: 'relative',
- verticalAlign: 'top',
overflow: 'hidden',
- height: '-webkit-fill-available',
flex: '1 1 0',
-
+ '--tab-margin-top': `-${theme.tab.borderWidth}px`,
+ // put the top border underneath tab-stip top border, and
+ // the left border underneath the previous tab's right border
+ margin: `var(--tab-margin-top) 0 0 -${theme.tab.borderWidth}px`,
+ border: `solid var(--tab-border-width, ${theme.tab.borderWidth}px) var(--tab-border-color)`,
+ // Border bottom is added to the tabArea__tab so that we do not get
+ // 45-degree angles when the bottom border is different color from the side borders.
+ // This could change when we can put the tab's background on this element,
+ // which can happen when tab dragging does not introduce a left/right 'space' when a tab
+ // is dragged over.
+ borderBottomWidth: `0 !important`, // aphrodite puts this above the border defined in the previous line, so use important :-(
+ zIndex: 100,
+ transformOrigin: 'bottom center',
+ minWidth: 0,
+ width: 0,
// no-drag is applied to the button and tab area
// ref: tabs__tabStrip__newTabButton on tabs.js
WebkitAppRegion: 'no-drag',
-
// There's a special case that tabs should span the full width
// if there are a full set of them.
- maxWidth: '184px'
+ maxWidth: '184px',
+ // Use css variables for some transition options so that we can change them
+ // with other classes below, without having to re-define the whole property.
+ // Avoid aphrodite bug which will change css variables
+ // to --tab--webkit-transition-duration by calling it 'transit'.
+ '--tab-transit-duration': theme.tab.transitionDurationOut,
+ '--tab-transit-easing': theme.tab.transitionEasingOut,
+ // z-index should be delayed when it changes, so that preview tab stays on top until
+ // its scale transition has completed
+ '--tab-zindex-delay': theme.tab.transitionDurationOut,
+ transition: ['box-shadow', 'transform', 'border', 'margin', 'opacity']
+ .map(prop => `${prop} var(--tab-transit-duration) var(--tab-transit-easing) 0s`)
+ .join(',') +
+ ', z-index var(--tab-zindex-duration, 0s) linear var(--tab-zindex-delay)',
+ '--tab-background': theme.tab.background,
+ '--tab-color': theme.tab.color,
+ '--tab-border-color': theme.tab.borderColor,
+ '--tab-background-hover': theme.tab.hover.background,
+ '--tab-default-icon-color': theme.tab.defaultFaviconColor,
+ ':hover': {
+ '--tab-background': `var(--tab-background-hover)`,
+ '--tab-color': `var(--tab-color-hover, ${theme.tab.color})`,
+ '--tab-default-icon-color': `var(--tab-default-icon-color-hover, ${theme.tab.defaultFaviconColor})`,
+ '--tab-border-color': `var(--tab-border-color-hover, ${theme.tab.borderColor})`,
+ '--tab-transit-duration': theme.tab.transitionDurationIn,
+ '--tab-transit-easing': theme.tab.transitionEasingIn,
+ '--tab-mouse-opacity': '1'
+ }
+ },
+
+ tabArea_instantTransition: {
+ '--tab-transit-duration': '0 !important'
},
tabArea_dragging_left: {
@@ -431,35 +523,117 @@ const styles = StyleSheet.create({
},
tabArea_isPinned: {
- flex: 'initial'
+ flex: 'initial',
+ width: 'auto'
},
tabArea_partOfFullPageSet: {
maxWidth: 'initial'
},
+ tabArea_isActive: {
+ '--tab-color': theme.tab.active.colorDark,
+ '--tab-background': theme.tab.active.background,
+ '--tab-background-hover': theme.tab.hover.active.background,
+ '--tab-border-color-bottom': 'var(--tab-background)',
+ '--tab-mouse-opacity': '0 !important'
+ },
+
+ tabArea_isPreview: {
+ '--tab-background': theme.tab.preview.background,
+ '--tab-background-hover': theme.tab.preview.background,
+ '--tab-color': theme.tab.active.colorDark,
+ '--tab-color-hover': theme.tab.active.colorDark,
+ '--tab-border-color': theme.tab.preview.background,
+ '--tab-border-color-hover': theme.tab.preview.background,
+ zIndex: 110,
+ transform: `scale(${theme.tab.preview.scale})`,
+ boxShadow: theme.tab.preview.boxShadow,
+ // want the zindex to change immediately when previewing, but delay when un-previewing
+ '--tab-zindex-delay': '0s',
+ '--tab-zindex-duration': '0s',
+ '--tab-transit-duration': theme.tab.transitionDurationIn,
+ '--tab-transit-easing': theme.tab.transitionEasingIn
+ },
+
+ tabArea_siblingIsPreview: {
+ // when un-previewing, if there's still another tab previewed
+ // then we want to immediately have that tab on top of the last-previewed tab
+ // but have the last previewed tab wait to be underneath the next tab in the DOM
+ '--tab-zindex-delay': '0s',
+ '--tab-zindex-duration': '2s',
+ willChange: 'transform'
+ },
+
+ tabArea_isActive_siblingIsPreview: {
+ opacity: '.5'
+ },
+
+ tabArea_private: {
+ '--tab-background': theme.tab.private.background,
+ '--tab-background-hover': theme.tab.hover.private.background
+ },
+
+ tabArea_private_active: {
+ '--tab-background': theme.tab.active.private.background,
+ '--tab-color': theme.tab.active.private.color,
+ '--tab-background-hover': theme.tab.active.private.background,
+ '--tab-color-hover': theme.tab.active.private.color,
+ '--tab-default-icon-color': theme.tab.active.private.defaultFaviconColor
+ },
+
+ tabArea_themed: {
+ '--tab-color': `var(--theme-color-fg)`,
+ '--tab-background': `var(--theme-color-bg)`,
+ '--tab-background-hover': 'var(--theme-color-bg)',
+ '--tab-color-hover': 'var(--theme-color-fg)',
+ '--tab-default-icon-color': 'var(--theme-color-default-icon)'
+ },
+
tabArea__tab: {
- borderWidth: '0 1px 0 0',
- borderStyle: 'solid',
- borderColor: theme.tab.borderColor,
boxSizing: 'border-box',
- color: theme.tab.color,
+ background: `var(--tab-background, ${theme.tab.background})`,
+ // make sure the tab element which contains the background color
+ // has a new layer, so that the tab title text is rendered with subpixel antialiasing
+ // that knows about both the foreground and background colors
display: 'flex',
- transition: theme.tab.transition,
- height: '-webkit-fill-available',
- width: '-webkit-fill-available',
+ transition: ['background-color', 'color', 'border']
+ .map(prop => `${prop} var(--tab-transit-duration) var(--tab-transit-easing) 0s`)
+ .join(','),
+ height: '100%',
alignItems: 'center',
justifyContent: 'space-between',
position: 'relative',
+ color: `var(--tab-color, ${theme.tab.color})`,
+ borderBottom: `solid var(--tab-border-width, ${theme.tab.borderWidth}px) var(--tab-border-color-bottom, var(--tab-border-color))`,
- ':hover': {
- background: theme.tab.hover.background
+ // mouse-tracking radial gradient
+ '::before': {
+ content: '" "',
+ position: 'absolute',
+ left: 'var(--tab-mouse-x)',
+ top: 0,
+ bottom: 0,
+ width: 'calc(190px * var(--tab-mouse-opacity, 0))',
+ background: `radial-gradient(
+ circle farthest-corner,
+ var(--tab-background-hover),
+ transparent
+ )`,
+ filter: 'brightness(var(--tab-mouse-brightness, 106%))',
+ transform: 'translateX(-50%)',
+ transition: 'opacity var(--tab-transit-duration) ease, width 0s linear var(--tab-transit-duration)',
+ opacity: 'var(--tab-mouse-opacity, 0)'
+ },
+ ':hover:before': {
+ // Show immediately, and fade-in opacity,
+ // but when leaving, wait for fade-out to finish before hiding.
+ transitionDelay: '0s'
}
},
tabArea__tab_audioTopBorder: {
- '::before': {
- zIndex: globalStyles.zindex.zindexTabsAudioTopBorder,
+ '::after': {
content: `''`,
display: 'block',
position: 'absolute',
@@ -467,7 +641,7 @@ const styles = StyleSheet.create({
left: 0,
right: 0,
height: '2px',
- background: 'lightskyblue'
+ background: theme.tab.icon.audio.color
}
},
@@ -484,47 +658,6 @@ const styles = StyleSheet.create({
margin: 0
},
- // Windows specific style
- tabArea__tab_forWindows: {
- color: theme.tab.forWindows.color
- },
-
- tabArea__tab_active: {
- background: theme.tab.active.background,
-
- ':hover': {
- background: theme.tab.active.background
- }
- },
-
- tabArea__tab_private: {
- background: theme.tab.private.background,
-
- ':hover': {
- color: theme.tab.active.private.color,
- background: theme.tab.active.private.background
- }
- },
-
- tabArea__tab_private_active: {
- background: theme.tab.active.private.background,
- color: theme.tab.active.private.color,
-
- ':hover': {
- background: theme.tab.active.private.background
- }
- },
-
- tabArea__tab_themed: {
- color: `var(--theme-color-fg, inherit)`,
- background: `var(--theme-color-bg, inherit)`,
-
- ':hover': {
- color: `var(--theme-color-fg, inherit)`,
- background: `var(--theme-color-bg, inherit)`
- }
- },
-
// The sentinel is responsible to respond to tabs
// intersection state. This is an empty hidden element
// which `width` value shouldn't be changed unless the intersection
@@ -538,18 +671,21 @@ const styles = StyleSheet.create({
},
tabArea__tab__identity: {
- justifyContent: 'flex-start',
- alignItems: 'center',
- overflow: 'hidden',
- display: 'flex',
flex: '1',
minWidth: '0', // @see https://bugzilla.mozilla.org/show_bug.cgi?id=1108514#c5
- margin: `0 ${globalStyles.spacing.defaultTabMargin}`
+ margin: `calc(var(--tab-border-width, 0) * -1px) 6px 0 ${globalStyles.spacing.defaultTabMargin}`, // bring the right margin closer as we do fade-out
+ // make sure title text is not cut off, but is also vertically centered
+ // by giving it full height of favicon
+ height: theme.tab.identityHeight,
+ display: 'flex',
+ justifyContent: 'flex-start',
+ alignItems: 'center',
+ overflow: 'visible'
},
tabArea__tab__identity_centered: {
- justifyContent: 'center',
flex: 'auto',
+ justifyContent: 'center',
padding: 0,
margin: 0
}
diff --git a/app/renderer/components/tabs/tabs.js b/app/renderer/components/tabs/tabs.js
index afee41bdf53..ef61aef08f0 100644
--- a/app/renderer/components/tabs/tabs.js
+++ b/app/renderer/components/tabs/tabs.js
@@ -149,6 +149,7 @@ class Tabs extends React.Component {
const props = {}
// used in renderer
props.previewTabPageIndex = currentWindow.getIn(['ui', 'tabs', 'previewTabPageIndex'])
+ props.previewTabFrameKey = frameStateUtil.getPreviewFrameKey(currentWindow)
props.currentTabs = currentTabs
props.partOfFullPageSet = currentTabs.size === tabsPerTabPage
props.onNextPage = currentTabs.size >= tabsPerTabPage && totalPages > pageIndex + 1
@@ -165,6 +166,7 @@ class Tabs extends React.Component {
}
render () {
+ const isTabPreviewing = this.props.previewTabFrameKey != null
this.tabRefs = []
return
{
const div = document.createElement('div')
div.style.color = color
- return div.style.color.split('(')[1].split(')')[0].split(',')
+ const normalizedColor = div.style.color
+ if (typeof normalizedColor === 'string' &&
+ normalizedColor.includes('(') &&
+ normalizedColor.includes(')') &&
+ normalizedColor.includes(',')) {
+ return div.style.color.split('(')[1].split(')')[0].split(',')
+ }
+ return null
}
-module.exports.getTextColorForBackground = (color) => {
+module.exports.backgroundRequiresLightText = (color) => {
// Calculate text color based on contrast with background:
// https://24ways.org/2010/calculating-color-contrast/
const rgb = module.exports.parseColor(color)
@@ -17,5 +24,32 @@ module.exports.getTextColorForBackground = (color) => {
}
const [r, g, b] = rgb
const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000
- return yiq >= 128 ? 'black' : 'white'
+ return yiq < 128
+}
+
+module.exports.getTextColorForBackground = (color) => {
+ return module.exports.backgroundRequiresLightText(color) ? 'white' : 'black'
+}
+
+module.exports.removeAlphaChannelForBackground = (color, bR, bG, bB) => {
+ const rgba = module.exports.parseColor(color)
+ if (!rgba) {
+ return null
+ }
+ // handle no alpha channel
+ if (rgba.length !== 4 || Number.isNaN(rgba[3])) {
+ return color
+ }
+
+ // remove alpha channel, blending color with background
+ const [oR, oG, oB, oA] = rgba
+
+ const newR = blendChannel(oR, bR, oA)
+ const newG = blendChannel(oG, bG, oA)
+ const newB = blendChannel(oB, bB, oA)
+ return `rgb(${newR}, ${newG}, ${newB})`
+}
+
+function blendChannel (original, background, alpha) {
+ return Math.round((original * alpha) + ((1 - alpha) * background))
}
diff --git a/js/stores/windowStore.js b/js/stores/windowStore.js
index baa9ab4ece9..3b15b436ddf 100644
--- a/js/stores/windowStore.js
+++ b/js/stores/windowStore.js
@@ -16,6 +16,7 @@ const messages = require('../constants/messages')
const debounce = require('../lib/debounce')
const getSetting = require('../settings').getSetting
const UrlUtil = require('../lib/urlutil')
+const color = require('../lib/color')
const {l10nErrorText} = require('../../app/common/lib/httpUtil')
const { makeImmutable } = require('../../app/common/state/immutableUtil')
const {aboutUrls, getTargetAboutUrl, newFrameUrl} = require('../lib/appUrlUtil')
@@ -397,10 +398,13 @@ const doAction = (action) => {
{
const frameKey = action.frameProps.get('key')
if (action.themeColor !== undefined) {
- windowState = windowState.setIn(frameStateUtil.frameStatePath(windowState, frameKey).concat(['themeColor']), action.themeColor)
+ // remove alpha channel
+ const solidColor = color.removeAlphaChannelForBackground(action.themeColor, 255, 255, 255)
+ windowState = windowState.setIn(frameStateUtil.frameStatePath(windowState, frameKey).concat(['themeColor']), solidColor)
}
if (action.computedThemeColor !== undefined) {
- windowState = windowState.setIn(frameStateUtil.frameStatePath(windowState, frameKey).concat(['computedThemeColor']), action.computedThemeColor)
+ const solidColor = color.removeAlphaChannelForBackground(action.computedThemeColor, 255, 255, 255)
+ windowState = windowState.setIn(frameStateUtil.frameStatePath(windowState, frameKey).concat(['computedThemeColor']), solidColor)
}
break
}
diff --git a/less/window.less b/less/window.less
index 12ec648d38a..6848c79f42a 100644
--- a/less/window.less
+++ b/less/window.less
@@ -40,7 +40,7 @@ html,
}
.top {
- background: linear-gradient(to bottom, #eaeaea, #f2f2f4);
+ background: linear-gradient(to top, #e9e9ea 0%, #e9e9ea 27px, #f6f6f7 100%);
&.allowDragging {
-webkit-app-region: drag;
}
@@ -52,10 +52,30 @@ html,
flex-grow: 1;
box-shadow: 0 -1px 0 #bbb;
width: 100%;
-
+ z-index: 1;
.tabContainer {
flex-grow: 1;
position: relative;
+ &:after {
+ position: absolute;
+ content: ' ';
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: linear-gradient(to top, rgb(28, 27, 27) 0%, rgba(255, 255, 255, .3) 60%);
+ display: block;
+ opacity: 0;
+ transition: opacity .4s ease-in; // TODO: get from theme.tab
+ pointer-events: none;
+ will-change: opacity;
+ z-index: 1100;
+ }
+ &.hasFramePreview::after {
+ transition-timing-function: ease-out; // TODO: get from theme.tab
+ transition-duration: .2s; // TODO: get from theme.tab
+ opacity: 1;
+ }
}
}
@@ -91,17 +111,26 @@ html,
// Note that this value can be as large as we want, it does not
// need to match the timeout specified in the frame's element
// (in renderer main.js). However, there is no reason to set it higher than that.
- transition: visibility 0s linear 150ms;
- // 1000
- z-index: @zindexWindow;
+ --visibility-delay: .15s;
+ --frame-zIndex-delay: 0s;
+ transition: visibility 0s linear var(--visibility-delay), z-index 0s linear var(--frame-zIndex-delay);
+ // active frame z-index
+ z-index: 1000;
+
+ .hasFramePreview &.isActive {
+ // Move to below preview frame, but do so as part of 'preview' entry animation
+ // so that it is clear which frame is being previewed and which is active.
+ z-index: 993;
+ --frame-zIndex-delay: .2s;
+ }
+
&:not(.isActive) {
- // 900
- z-index: @zindexWindowNotActive;
+ // non-active always lower than active
+ z-index: 990;
}
&.isPreview {
background: #222;
- // 1100
- z-index: @zindexWindowIsPreview;
+ z-index: 995;
}
// show frame when active or preview
&.isActive,
@@ -111,7 +140,7 @@ html,
&.isExiting {
visibility: visible;
// show instantly
- transition-delay: 0s;
+ --visibility-delay: 0s;
}
// hide frame whilst it's figuring out which location to be
// note: that isEntering is timed-out at a value set in renderer main.js
@@ -119,7 +148,8 @@ html,
// has an actual location
&.isEntering.isBlankLocation {
visibility: hidden;
- transition-delay: 0s;
+ // hide instantly (at first)
+ --visibility-delay: 0s;
}
webview {
@@ -133,12 +163,6 @@ html,
.webviewContainer {
height: 100%;
width: 100%;
- &.isPreview {
- will-change: opacity;
- opacity: 0.5;
- animation: tabFadeIn 0.75s ease-in-out;
- animation-fill-mode: forwards;
- }
}
}
diff --git a/test/unit/app/common/state/tabContentStateTest/audioStateTest.js b/test/unit/app/common/state/tabContentStateTest/audioStateTest.js
index 19aec879344..0ac91b32b9f 100644
--- a/test/unit/app/common/state/tabContentStateTest/audioStateTest.js
+++ b/test/unit/app/common/state/tabContentStateTest/audioStateTest.js
@@ -156,7 +156,7 @@ describe('audioState unit tests', function () {
const state = defaultState
.setIn(['frames', index, 'audioPlaybackActive'], false)
.setIn(['frames', index, 'audioMuted'], false)
- .setIn(['ui', 'tabs', 'intersectionRatio'], intersection.at45)
+ .setIn(['ui', 'tabs', 'intersectionRatio'], intersection.at46)
const result = audioState.showAudioTopBorder(state, frameKey, false)
assert.equal(result, false)
})
diff --git a/test/unit/app/common/state/tabContentStateTest/closeStateTest.js b/test/unit/app/common/state/tabContentStateTest/closeStateTest.js
index 32f44f565c4..bd9619a6fb7 100644
--- a/test/unit/app/common/state/tabContentStateTest/closeStateTest.js
+++ b/test/unit/app/common/state/tabContentStateTest/closeStateTest.js
@@ -150,7 +150,7 @@ describe('closeState unit tests', function () {
it('returns false if tab is intersected and not active', function * () {
const state = defaultState
.set('activeFrameKey', 1337)
- .setIn(['ui', 'tabs', 'intersectionRatio', intersection.at45])
+ .setIn(['ui', 'tabs', 'intersectionRatio', intersection.at46])
const result = closeState.showCloseTabIcon(state, frameKey)
assert.equal(result, false)
})
diff --git a/test/unit/app/common/state/tabUIStateTest.js b/test/unit/app/common/state/tabUIStateTest.js
index 58a11a189bb..25de62604f2 100644
--- a/test/unit/app/common/state/tabUIStateTest.js
+++ b/test/unit/app/common/state/tabUIStateTest.js
@@ -8,7 +8,6 @@ const assert = require('assert')
const Immutable = require('immutable')
const mockery = require('mockery')
const fakeElectron = require('../../../lib/fakeElectron')
-const {theme} = require('../../../../../app/renderer/components/styles/theme')
const {intersection} = require('../../../../../app/renderer/components/styles/global')
const frameKey = 1
@@ -307,95 +306,4 @@ describe('tabUIState unit tests', function () {
assert.equal(result, true)
})
})
-
- describe('getTabEndIconBackgroundColor', function () {
- before(function () {
- // just a helper for results
- this.defaultResult = (bgColor, color1Size, color2Size) =>
- `linear-gradient(to left, ${bgColor} ${color1Size}, transparent ${color2Size})`
- })
-
- describe('when tab is private', function () {
- it('returns `tab.private.background` color if not active', function * () {
- const state = defaultState
- .set('activeFrameKey', 1337)
- .mergeIn(['frames', index], {
- themeColor: '#c0ff33',
- isPrivate: true
- })
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult(theme.tab.private.background, '10px', '40px')
- assert.equal(result, expected)
- })
-
- it('returns `tab.active.private.background` if tab is active', function * () {
- const state = defaultState
- .mergeIn(['frames', index], {
- themeColor: '#c0ff33',
- isPrivate: true
- })
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult(theme.tab.active.private.background, '10px', '40px')
- assert.equal(result, expected)
- })
-
- it('retuns active private color if tab is being hovered', function * () {
- const state = defaultState
- .mergeIn(['frames', index], {
- themeColor: '#c0ff33',
- isPrivate: true
- })
- .setIn(['ui', 'tabs', 'hoverTabIndex'], index)
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult(theme.tab.active.private.background, '10px', '40px')
- assert.equal(result, expected)
- })
- })
-
- describe('when tab is not private', function () {
- it('returns the themeColor if tab is active', function * () {
- const state = defaultState
- .setIn(['frames', index, 'themeColor'], '#c0ff33')
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult('#c0ff33', '0', '12px')
- assert.equal(result, expected)
- })
- it('returns `theme.tab.background` if tab is not active', function * () {
- const state = defaultState
- .set('activeFrameKey', 1337)
- .setIn(['frames', index, 'themeColor'], '#c0ff33')
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult(theme.tab.background, '0', '12px')
- assert.equal(result, expected)
- })
- })
-
- describe('returns `linear gradient` size', function () {
- it('at 10px/40px if tab is partitioned', function * () {
- const state = defaultState
- .mergeIn(['frames', index], {
- partitionNumber: 1337,
- themeColor: '#c0ff33'
- })
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult('#c0ff33', '10px', '40px')
- assert.equal(result, expected)
- })
- it('at 10px/40px gradient size if tab has a visible close icon', function * () {
- const state = defaultState
- .setIn(['frames', index, 'themeColor'], '#c0ff33')
- .setIn(['ui', 'tabs', 'hoverTabIndex'], index)
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult('#c0ff33', '10px', '40px')
- assert.equal(result, expected)
- })
- it('at 0/12px gradient size if is neither private, partition or has close icon visible', function * () {
- const state = defaultState
- .setIn(['frames', index, 'themeColor'], '#c0ff33')
- const result = tabUIState.getTabEndIconBackgroundColor(state, frameKey)
- const expected = this.defaultResult('#c0ff33', '0', '12px')
- assert.equal(result, expected)
- })
- })
- })
})
diff --git a/test/unit/app/renderer/components/tabs/content/closeTabIconTest.js b/test/unit/app/renderer/components/tabs/content/closeTabIconTest.js
index 76388f87a67..4c091b8b97c 100644
--- a/test/unit/app/renderer/components/tabs/content/closeTabIconTest.js
+++ b/test/unit/app/renderer/components/tabs/content/closeTabIconTest.js
@@ -64,7 +64,6 @@ describe('Tabs content - CloseTabIcon', function () {
useCleanCache: true
})
mockery.registerMock('electron', fakeElectron)
- mockery.registerMock('../../../../extensions/brave/img/tabs/close_btn.svg')
windowStore = require('../../../../../../../js/stores/windowStore')
appStore = require('../../../../../../../js/stores/appStoreRenderer')
CloseTabIcon = require('../../../../../../../app/renderer/components/tabs/content/closeTabIcon')