diff --git a/_locales/en/messages.json b/_locales/en/messages.json index c23068f07..ec921e741 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -458,9 +458,6 @@ "summary_description_not_scanned_2": { "message": "Navigate to another page and I promise I'll deliver the goods." }, - "summary_custom_settings": { - "message": "Custom Settings" - }, "summary_trust_site": { "message": "Trust Site" }, @@ -482,9 +479,6 @@ "summary_pause_ghostery_tooltip": { "message": "Pause Ghostery extension." }, - "summary_pause_ghostery_ab_pause": { - "message": "Pause" - }, "pause_30_min": { "message": "for 30 min" }, @@ -509,9 +503,6 @@ "summary_resume_ghostery_tooltip": { "message": "Ghostery extension paused. Click to resume." }, - "summary_resume_ghostery_ab_pause": { - "message": "Resume" - }, "summary_show_menu": { "message": "show menu" }, @@ -1092,6 +1083,12 @@ "page_load": { "message": "Page Load:" }, + "requests_modified": { + "message": "Requests Modified:" + }, + "requests_modified_tooltip": { + "message": "Total number of tracking requests & elements modified by Anti-Tracking and Ad Blocking" + }, "trackers_blocked": { "message": "Trackers Blocked:" }, @@ -1284,9 +1281,6 @@ "tooltip_restrict_on": { "message": "Trackers blocked and Anti-Tracking enabled on site. Click to Undo." }, - "tooltip_custom_settings": { - "message": "Use my selected tracker settings." - }, "tooltip_pause": { "message": "Pause Ghostery" }, @@ -2212,5 +2206,11 @@ }, "panel_stats_pitch_modal_tooltip": { "message": "Erase all statistics history up until this point in time." + }, + "cliqz_feature_status_on": { + "message": "On" + }, + "cliqz_feature_status_off": { + "message": "Off" } } diff --git a/app/images/panel/green-upgrade-banner-small.svg b/app/images/panel/green-upgrade-banner-small.svg new file mode 100644 index 000000000..210cc4245 --- /dev/null +++ b/app/images/panel/green-upgrade-banner-small.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/panel/components/BuildingBlocks/CliqzFeature.jsx b/app/panel/components/BuildingBlocks/CliqzFeature.jsx new file mode 100644 index 000000000..93d786c15 --- /dev/null +++ b/app/panel/components/BuildingBlocks/CliqzFeature.jsx @@ -0,0 +1,124 @@ +/** + * Cliqz Features Component + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +import React from 'react'; +import ClassNames from 'classnames'; +import Tooltip from '../Tooltip'; + +/** + * @class Implements rendering and interaction for Cliqz feature icon toggles + * @memberof PanelBuildingBlocks + */ +class CliqzFeature extends React.Component { + constructor(props) { + super(props); + + this.clickCliqzFeature = this.clickCliqzFeature.bind(this); + } + + /** + * Handles clicks on the Cliqz feature icon, toggling it on/off + */ + clickCliqzFeature() { + const { + active, + clickButton, + cliqzInactive, + type + } = this.props; + + if (cliqzInactive) { + return; + } + + const featureType = type === 'anti_track' ? 'anti_tracking' : type; + + clickButton({ + feature: `enable_${featureType}`, + status: active, + text: this._getAlertText(active, type), + }); + } + + _getStatus(active) { + return active ? t('cliqz_feature_status_on') : t('cliqz_feature_status_off'); + } + + _getTooltipBodyText(active, isTooltipBody, type) { + if (!isTooltipBody) return false; + + return active ? + t(`tooltip_${type}_body_on`) : + t(`tooltip_${type}_body`); + } + + _getTooltipHeaderText(isTooltipHeader, type) { + return isTooltipHeader ? t(`tooltip_${type}`) : false; + } + + _getAlertText(active, type) { + return active ? + t(`alert_${type}_off`) : + t(`alert_${type}_on`); + } + + /** + * React's required render function. Returns JSX + * @return {JSX} JSX for rendering a Cliqz Feature icon toggle + */ + render() { + const { + active, + cliqzInactive, + isSmaller, + isCondensed, + isTooltipBody, + isTooltipHeader, + tooltipPosition, + type, + } = this.props; + + const cliqzFeatureClassNames = ClassNames('CliqzFeature', { + 'CliqzFeature--normal': !isSmaller && !isCondensed, + 'CliqzFeature--smaller': isSmaller, + 'CliqzFeature--condensed': isCondensed, + 'CliqzFeature--active': active, + 'CliqzFeature--inactive': !active, + clickable: !cliqzInactive, + 'not-clickable': cliqzInactive, + }); + const cssTypeName = `CliqzFeature__icon--${type.replace('_', '-')}`; + const iconClassNames = ClassNames('CliqzFeature__icon', cssTypeName, 'g-tooltip'); + + const featureType = type === 'anti_track' ? 'anti_tracking' : type; + const featureName = t(`drawer_title_enable_${featureType}`); + + return ( +
+
{this._getStatus(active)}
+
+ +
+
+ {featureName} +
+
+ ); + } +} + +export default CliqzFeature; diff --git a/app/panel/components/BuildingBlocks/CliqzFeatures.jsx b/app/panel/components/BuildingBlocks/CliqzFeatures.jsx deleted file mode 100644 index 393959f0c..000000000 --- a/app/panel/components/BuildingBlocks/CliqzFeatures.jsx +++ /dev/null @@ -1,194 +0,0 @@ -/** - * Cliqz Features Component - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2019 Ghostery, Inc. All rights reserved. - * - * 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 - */ - -import React from 'react'; -import ClassNames from 'classnames'; -import Tooltip from '../Tooltip'; - -/** - * @class Implements buttons to render and toggle for Cliqz's features on/off. - * @memberof PanelBuildingBlocks - */ -class CliqzFeatures extends React.Component { - constructor(props) { - super(props); - - // Event Bindings - this.getAntiTrackingTotal = this.getAntiTrackingTotal.bind(this); - this.getAdBlockingTotal = this.getAdBlockingTotal.bind(this); - this.getSmartBlockingTotal = this.getSmartBlockingTotal.bind(this); - this.clickAntiTracking = this.clickAntiTracking.bind(this); - this.clickAdBlocking = this.clickAdBlocking.bind(this); - this.clickSmartBlocking = this.clickSmartBlocking.bind(this); - } - - /** - * Calculates the text for above the Ad Blocking feature icon - * @return {String | Int} The text for above the Ad Blocking icon - */ - getAdBlockingTotal() { - if (!this.props.adBlockingActive) { - return '-'; - } - return this.props.adBlocking && this.props.adBlocking.totalCount || 0; - } - - /** - * Calculates the text for above the Smart Blocking feature icon - * @return {String | Int} The text for above the Smart Blocking icon - */ - getSmartBlockingTotal() { - if (!this.props.smartBlockingActive) { - return '-'; - } - const blockedCount = this.props.smartBlocking && Object.keys(this.props.smartBlocking.blocked).length || 0; - const unblockedCount = this.props.smartBlocking && Object.keys(this.props.smartBlocking.unblocked).length || 0; - - return blockedCount + unblockedCount; - } - - /** - * Calculates the text for above the Anti Tracking feature icon - * @return {String | Int} The text for above the Anit Tracking icon - */ - getAntiTrackingTotal() { - if (!this.props.antiTrackingActive) { - return '-'; - } - return this.props.antiTracking && this.props.antiTracking.totalUnsafeCount || 0; - } - - /** - * Handles the click event for the AdBlocking button - */ - clickAdBlocking() { - if (this.props.isInactive) { - return; - } - this.props.clickButton({ - feature: 'enable_ad_block', - status: this.props.adBlockingActive, - text: !this.props.adBlockingActive ? t('alert_ad_block_on') : t('alert_ad_block_off'), - }); - } - - /** - * Handles the click event for the SmartBlocking button - */ - clickSmartBlocking() { - if (this.props.isInactive) { - return; - } - this.props.clickButton({ - feature: 'enable_smart_block', - status: this.props.smartBlockingActive, - text: !this.props.smartBlockingActive ? t('alert_smart_block_on') : t('alert_smart_block_off'), - }); - } - - /** - * Handles the click event for the AntiTracking button - */ - clickAntiTracking() { - if (this.props.isInactive) { - return; - } - this.props.clickButton({ - feature: 'enable_anti_tracking', - status: this.props.antiTrackingActive, - text: !this.props.antiTrackingActive ? t('alert_anti_track_on') : t('alert_anti_track_off'), - }); - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Cliqz Features portion of the Summary View - */ - render() { - const { - isSmaller, - isCondensed, - isInactive, - antiTrackingActive, - adBlockingActive, - smartBlockingActive, - } = this.props; - - const cliqzFeaturesClassNames = ClassNames('sub-component', 'cliqz-features', { - smaller: isSmaller, - condensed: isCondensed, - inactive: isInactive, - }); - const antiTrackingClassNames = ClassNames('anti-tracking', 'cliqz-feature', { - active: antiTrackingActive, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - const adBlockingClassNames = ClassNames('ad-blocking', 'cliqz-feature', { - active: adBlockingActive, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - const smartBlockingClassNames = ClassNames('smart-blocking', 'cliqz-feature', { - active: smartBlockingActive, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - - return ( -
-
-
{this.getAntiTrackingTotal()}
-
- -
-
- { t('drawer_title_enable_anti_tracking') } -
-
-
-
{this.getAdBlockingTotal()}
-
- -
-
- { t('drawer_title_enable_ad_block') } -
-
-
-
{this.getSmartBlockingTotal()}
-
- -
-
- { t('drawer_title_enable_smart_block') } -
-
-
- ); - } -} - -export default CliqzFeatures; diff --git a/app/panel/components/BuildingBlocks/DonutGraph.jsx b/app/panel/components/BuildingBlocks/DonutGraph.jsx index a4af6d4e0..127ac4551 100644 --- a/app/panel/components/BuildingBlocks/DonutGraph.jsx +++ b/app/panel/components/BuildingBlocks/DonutGraph.jsx @@ -216,7 +216,7 @@ class DonutGraph extends React.Component { categories.forEach((cat) => { const tooltip = document.getElementById(`${cat.id}_tooltip`); if (tooltip) { - tooltip.classList.remove('show'); + tooltip.classList.remove('DonutGraph__tooltip--show'); } }); @@ -268,13 +268,13 @@ class DonutGraph extends React.Component { if (tooltip) { tooltip.style.left = `${pX - (tooltip.offsetWidth / 2)}px`; tooltip.style.top = `${pY - (tooltip.offsetHeight + 8)}px`; - tooltip.classList.add('show'); + tooltip.classList.add('DonutGraph__tooltip--show'); } }) .on('mouseout', (d) => { const tooltip = this.grabTooltip(d); if (tooltip) { - tooltip.classList.remove('show'); + tooltip.classList.remove('DonutGraph__tooltip--show'); } }) .on('click', (d) => { @@ -314,23 +314,24 @@ class DonutGraph extends React.Component { */ render() { const { isSmall, totalCount } = this.props; - const componentClasses = ClassNames('sub-component', 'donut-graph', { - small: isSmall, - big: !isSmall, + const componentClasses = ClassNames('DonutGraph', { + 'DonutGraph--big': !isSmall, + 'DonutGraph--small': isSmall, }); + // TODO Foundation dependency: tooltip return (
-
+
{this.props.categories.map(cat => ( - + {cat.name} ))}
-
{ this.node = node; }} /> -
-
+
{ this.node = node; }} /> +
+
{totalCount} + + + {this._getButtonText(sitePolicy, showText, type)} + + + +
+ ); + } +} + +export default GhosteryFeature; diff --git a/app/panel/components/BuildingBlocks/GhosteryFeatures.jsx b/app/panel/components/BuildingBlocks/GhosteryFeatures.jsx deleted file mode 100644 index cb0b9a851..000000000 --- a/app/panel/components/BuildingBlocks/GhosteryFeatures.jsx +++ /dev/null @@ -1,170 +0,0 @@ -/** - * Ghostery Features Component - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2019 Ghostery, Inc. All rights reserved. - * - * 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 - */ - -import React from 'react'; -import ClassNames from 'classnames'; -import Tooltip from '../Tooltip'; - -/** - * @class Implements buttons to render and toggle for Ghostery's features on/off. - * @memberof PanelBuildingBlocks - */ -class GhosteryFeatures extends React.Component { - constructor(props) { - super(props); - - // Event Bindings - this.clickTrustButton = this.clickTrustButton.bind(this); - this.clickCustomButton = this.clickCustomButton.bind(this); - this.clickRestrictButton = this.clickRestrictButton.bind(this); - this.getTrustText = this.getTrustText.bind(this); - this.getRestrictText = this.getRestrictText.bind(this); - } - - /** - * Gets the text for the Trust Button under different conditions - * @return {String} The text for the Trust Button as a string - */ - getTrustText() { - if (this.props.isCondensed) { - return ''; - } else if (this.props.sitePolicy === 2) { - return t('summary_trust_site_active'); - } - return t('summary_trust_site'); - } - - /** - * Gets the text for the Restrict Button under different conditions - * @return {String} The text for the Restrict Button as a string - */ - getRestrictText() { - if (this.props.isCondensed) { - return ''; - } else if (this.props.sitePolicy === 1) { - return t('summary_restrict_site_active'); - } - return t('summary_restrict_site'); - } - - /** - * Handles the click event for the Trust Site button - */ - clickTrustButton() { - if (this.props.isInactive) { - return; - } - this.props.clickButton('trust'); - } - - /** - * Handles the click event for the Custom Settings button - */ - clickCustomButton() { - if (this.props.isInactive) { - return; - } - this.props.clickButton('custom'); - } - - /** - * Handles the click event for the Restrict Site button - */ - clickRestrictButton() { - if (this.props.isInactive) { - return; - } - this.props.clickButton('restrict'); - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Ghostery Features portion of the Summary View - */ - render() { - const { - isAbPause, - isInactive, - isStacked, - isCondensed, - sitePolicy - } = this.props; - - const buttonGroupClassNames = ClassNames('button-group', { - inactive: isInactive, - stacked: isStacked, - }); - const trustClassNames = ClassNames('button', 'button-trust', 'g-tooltip', { - 'ab-pause': isAbPause, - 'button-left': isAbPause && !isStacked, - 'button-top': (isAbPause || isCondensed) && isStacked, - condensed: isCondensed, - active: sitePolicy === 2, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - const customClassNames = ClassNames('button', 'button-custom', 'g-tooltip', { - 'ab-pause': isAbPause, - 'button-center': isAbPause && true, - condensed: isCondensed, - active: !sitePolicy, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - const restrictClassNames = ClassNames('button', 'button-restrict', 'g-tooltip', { - 'ab-pause': isAbPause, - 'button-right': isAbPause && !isStacked, - 'button-bottom': isAbPause && isStacked, - 'button-center': !isAbPause && isCondensed && isStacked, - condensed: isCondensed, - active: sitePolicy === 1, - clickable: !isInactive, - 'not-clickable': isInactive, - }); - - return ( -
-
-
- - - {this.getTrustText()} - - - -
- {isAbPause && ( -
- - - {t('summary_custom_settings')} - - - -
- )} -
- - - {this.getRestrictText()} - - - -
-
-
- ); - } -} - -export default GhosteryFeatures; diff --git a/app/panel/components/BuildingBlocks/PauseButton.jsx b/app/panel/components/BuildingBlocks/PauseButton.jsx index f95c0bc1a..589d09786 100644 --- a/app/panel/components/BuildingBlocks/PauseButton.jsx +++ b/app/panel/components/BuildingBlocks/PauseButton.jsx @@ -109,17 +109,10 @@ class PauseButton extends React.Component { const { isPaused, isCondensed, - isAbPause, } = this.props; let buttonEl; if (isCondensed) { buttonEl = ; - } else if (isAbPause) { - buttonEl = ( - - {isPaused ? t('summary_resume_ghostery_ab_pause') : t('summary_pause_ghostery_ab_pause')} - - ); } else { buttonEl = ( @@ -139,56 +132,66 @@ class PauseButton extends React.Component { * @return {JSX} JSX for rendering the Pause Button on the Summary View */ render() { - const pauseButtonClassNames = ClassNames('button', 'button-left', 'button-pause', { - 'g-tooltip': !this.props.isAbPause, - active: this.props.isPaused, - smaller: !this.props.isCentered, - smallest: this.props.isCentered && this.props.isCondensed, - 'no-border-radius': this.props.isCentered && this.props.isCondensed, - 'dropdown-open': this.state.showDropdown, + const { + isPaused, + isCentered, + isCondensed + } = this.props; + const { showDropdown } = this.state; + const centeredAndCondensed = isCentered && isCondensed; + + const sharedClassNames = { + button: true, + smaller: !isCentered, + smallest: centeredAndCondensed, + 'no-border-radius': centeredAndCondensed, + 'dropdown-open': showDropdown, + }; + const pauseButtonClassNames = ClassNames('button-left', 'button-pause', 'g-tooltip', sharedClassNames, { + active: isPaused, }); - const dropdownButtonClassNames = ClassNames('button', 'button-right', 'button-caret', { - active: this.state.showDropdown, - smaller: !this.props.isCentered, - smallest: this.props.isCentered && this.props.isCondensed, - 'no-border-radius': this.props.isCentered && this.props.isCondensed, - 'dropdown-open': this.state.showDropdown, + const dropdownButtonClassNames = ClassNames('button-right', 'button-caret', sharedClassNames, { + active: showDropdown, }); const dropdownContainerClassNames = ClassNames('button-group', 'dropdown-container', { - centered: this.props.isCentered, + centered: isCentered, }); - const dropdownContainerStyles = { - left: `${(this.props.isCentered && this.props.isAbPause) ? this.pauseLeft : 0}px`, - }; + + const togglePauseButton = ( +
{ this.pauseWidth = node && node.clientWidth; }} + > + {this.renderPauseButtonText()} + +
+ ); + + const pauseDurationSelectionDropdownCaret = ( +
+ + {t('summary_show_menu')} + +
+ ); + + const pauseDurationSelectionDropdown = ( +
+ {this.renderDropdown()} +
+ ); return (
-
{ - this.pauseWidth = node && node.clientWidth; - this.pauseLeft = node && node.offsetLeft; - }} - > - {this.renderPauseButtonText()} - {!this.props.isAbPause && ( - - )} -
-
- - {t('summary_show_menu')} - -
-
-
- {this.state.showDropdown && this.renderDropdown()} + {togglePauseButton} + {pauseDurationSelectionDropdownCaret}
+ {showDropdown && pauseDurationSelectionDropdown}
); } diff --git a/app/panel/components/BuildingBlocks/index.js b/app/panel/components/BuildingBlocks/index.js index 76554d518..e689a77de 100644 --- a/app/panel/components/BuildingBlocks/index.js +++ b/app/panel/components/BuildingBlocks/index.js @@ -15,9 +15,9 @@ * @namespace PanelBuildingBlocks */ import ClickOutside from './ClickOutside'; -import CliqzFeatures from './CliqzFeatures'; +import CliqzFeature from './CliqzFeature'; import DonutGraph from './DonutGraph'; -import GhosteryFeatures from './GhosteryFeatures'; +import GhosteryFeature from './GhosteryFeature'; import NotScanned from './NotScanned'; import PauseButton from './PauseButton'; import ToggleSlider from './ToggleSlider'; @@ -26,9 +26,9 @@ import RewardListItem from './RewardListItem'; export { ClickOutside, - CliqzFeatures, + CliqzFeature, DonutGraph, - GhosteryFeatures, + GhosteryFeature, NotScanned, PauseButton, ToggleSlider, diff --git a/app/panel/components/Summary.jsx b/app/panel/components/Summary.jsx index 1ae9a3bb6..658876818 100644 --- a/app/panel/components/Summary.jsx +++ b/app/panel/components/Summary.jsx @@ -20,15 +20,17 @@ import { DynamicUIPortContext } from '../contexts/DynamicUIPortContext'; import { sendMessage } from '../utils/msg'; import globals from '../../../src/classes/Globals'; import { - CliqzFeatures, + CliqzFeature, DonutGraph, - GhosteryFeatures, + GhosteryFeature, NotScanned, PauseButton } from './BuildingBlocks'; -const { IS_CLIQZ } = globals; -const AB_PAUSE_BUTTON = false; +const { + IS_CLIQZ, + BLACKLISTED, WHITELISTED, +} = globals; /** * @class Implements the Summary View, which is displayed as the entire panel @@ -45,17 +47,17 @@ class Summary extends React.Component { this.state = { trackerLatencyTotal: 0, disableBlocking: false, - abPause: AB_PAUSE_BUTTON, }; // Event Bindings - this.toggleExpert = this.toggleExpert.bind(this); - this.clickPauseButton = this.clickPauseButton.bind(this); + this.clickCliqzFeature = this.clickCliqzFeature.bind(this); this.clickDonut = this.clickDonut.bind(this); - this.clickTrackersCount = this.clickTrackersCount.bind(this); - this.clickTrackersBlocked = this.clickTrackersBlocked.bind(this); + this.clickPauseButton = this.clickPauseButton.bind(this); this.clickSitePolicy = this.clickSitePolicy.bind(this); - this.clickCliqzFeature = this.clickCliqzFeature.bind(this); + this.clickTrackersBlocked = this.clickTrackersBlocked.bind(this); + this.clickTrackersCount = this.clickTrackersCount.bind(this); + this.clickUpgradeBannerOrGoldPlusIcon = this.clickUpgradeBannerOrGoldPlusIcon.bind(this); + this.toggleExpert = this.toggleExpert.bind(this); this.handlePortMessage = this.handlePortMessage.bind(this); this.pauseOptions = [ @@ -69,8 +71,8 @@ class Summary extends React.Component { * Lifecycle event */ componentDidMount() { - this.setTrackerLatency(this.props); - this.updateSiteNotScanned(this.props); + this._setTrackerLatency(this.props); + this._updateSiteNotScanned(this.props); this._dynamicUIPort = this.context; this._dynamicUIPort.onMessage.addListener(this.handlePortMessage); @@ -81,8 +83,8 @@ class Summary extends React.Component { * Lifecycle event */ componentWillReceiveProps(nextProps) { - this.setTrackerLatency(nextProps); - this.updateSiteNotScanned(nextProps); + this._setTrackerLatency(nextProps); + this._updateSiteNotScanned(nextProps); // Set page title for Firefox for Android window.document.title = `Ghostery's findings for ${this.props.pageUrl}`; @@ -97,61 +99,31 @@ class Summary extends React.Component { } /** - * Calculates total tracker latency and sets it to state - * @param {Object} props Summary's props, either this.props or nextProps. - */ - setTrackerLatency(props) { - const { performanceData } = props; - let pageLatency = 0; - let unfixedLatency = 0; - - // calculate and display page speed - if (performanceData) { - const { timing } = performanceData; - // format number of decimal places to use - unfixedLatency = Number(timing.loadEventEnd - timing.navigationStart) / 1000; - if (unfixedLatency >= 100) { // > 100 no decimal - pageLatency = (Number(timing.loadEventEnd - timing.navigationStart) / 1000).toFixed(); - } else if (unfixedLatency >= 10 && unfixedLatency < 100) { // 100 > 10 use one decimal - pageLatency = (Number(timing.loadEventEnd - timing.navigationStart) / 1000).toFixed(1); - } else if (unfixedLatency < 10 && unfixedLatency >= 0) { // < 10s use two decimals - pageLatency = (Number(timing.loadEventEnd - timing.navigationStart) / 1000).toFixed(2); - } - this.setState({ trackerLatencyTotal: pageLatency }); - // reset page load value if page is reloaded while panel is open - } else if (this.props.performanceData && !performanceData) { - this.setState({ trackerLatencyTotal: pageLatency }); - } - } - - /** - * Handles messages from dynamic UI port to background + * Handles clicking on Cliqz Features: AntiTracking, AdBlocking, SmartBlocking + * @param {Object} options options including: + * feature: enable_anti_tracking, enable_ad_block, enable_smart_block + * status: whether the feature should be turned on or off + * text: the text for the notification. */ - handlePortMessage(msg) { - if (msg.to !== 'summary' || !msg.body) { return; } - - const { body } = msg; - - if (body.adblock || body.antitracking) { - this.props.actions.updateCliqzModuleData(body); - } else { - this.props.actions.updateSummaryData(body); - } + clickCliqzFeature(options) { + const { feature, status, text } = options; + this.props.actions.showNotification({ + updated: feature, + reload: true, + text, + }); + this.props.actions.toggleCliqzFeature(feature, status); } /** - * Disable controls when Ghostery cannot or has not yet scanned a page. - * @param {Object} props Summary's props, either this.props or nextProps. + * Handles clicking on any part of the Donut graph + * @param {Object} data Properties of the click and resulting filter */ - updateSiteNotScanned(props) { - const { siteNotScanned, categories } = props; - const pageUrl = props.pageUrl || ''; - - if (siteNotScanned || !categories || pageUrl.search(/http|chrome-extension|moz-extension|ms-browser-extension|newtab|chrome:\/\/startpage\//) === -1) { - this.setState({ disableBlocking: true }); - } else { - this.setState({ disableBlocking: false }); + clickDonut(data) { + if (!this.props.is_expert) { + this.toggleExpert(); } + this.props.actions.filterTrackers(data); } /** @@ -179,14 +151,56 @@ class Summary extends React.Component { } /** - * Handles clicking on any part of the Donut graph - * @param {Object} data Properties of the click and resulting filter + * Handles clicking on Ghostery Features: Trust Site, Restrict Site + * @param {String} button The button that was clicked: trust, restrict */ - clickDonut(data) { - if (!this.props.is_expert) { - this.toggleExpert(); + clickSitePolicy(button) { + const { sitePolicy } = this.props; + let type; + let text; + let classes; + + if (button === 'trust') { + sendMessage('ping', 'trust_site'); + type = 'whitelist'; + text = (sitePolicy === WHITELISTED) ? t('alert_site_trusted_off') : t('alert_site_trusted'); + classes = (sitePolicy === WHITELISTED) ? 'warning' : 'success'; + } else if (button === 'restrict') { + sendMessage('ping', 'restrict_site'); + type = 'blacklist'; + text = (sitePolicy === BLACKLISTED) ? t('alert_site_restricted_off') : t('alert_site_restricted'); + classes = (sitePolicy === BLACKLISTED) ? 'warning' : 'alert'; + } else { + return; + } + + this.props.actions.updateSitePolicy({ + type, + }); + + this.props.actions.filterTrackers({ type: 'trackers', name: 'all' }); + + this.props.actions.showNotification({ + updated: type, + reload: true, + classes, + text, + }); + } + + /** + * Handles clicking on Trackers Blocked. Triggers a filter action + */ + clickTrackersBlocked() { + const { sitePolicy, is_expert } = this.props; + + if (!is_expert) { return; } + + if (sitePolicy === BLACKLISTED) { + this.props.actions.filterTrackers({ type: 'trackers', name: 'all' }); + } else { + this.props.actions.filterTrackers({ type: 'trackers', name: 'blocked' }); } - this.props.actions.filterTrackers(data); } /** @@ -196,6 +210,15 @@ class Summary extends React.Component { this.props.actions.filterTrackers({ type: 'trackers', name: 'all' }); } + /** + * Handles clicking on the green upgrade banner or gold subscriber badge + */ + clickUpgradeBannerOrGoldPlusIcon() { + sendMessage('ping', 'plus_panel_from_badge'); + + this.props.history.push(this._isPlusSubscriber() ? '/subscription/info' : `/subscribe/${!!this.props.user}`); + } + /** * Toggle between Simple and Detailed Views. */ @@ -209,178 +232,233 @@ class Summary extends React.Component { } /** - * Handles clicking on Trackers Blocked. Triggers a filter action + * Calculates total tracker latency and sets it to state + * @param {Object} props Summary's props, either this.props or nextProps. */ - clickTrackersBlocked() { - const { sitePolicy, is_expert } = this.props; - if (is_expert) { - if (sitePolicy === 1) { - this.props.actions.filterTrackers({ type: 'trackers', name: 'all' }); - } else { - this.props.actions.filterTrackers({ type: 'trackers', name: 'blocked' }); + _setTrackerLatency(props) { + const { performanceData } = props; + let pageLatency = 0; + + // calculate and display page speed + if (performanceData) { + const { timing } = performanceData; + const { loadEventEnd, navigationStart } = timing; + // format number of decimal places to use + const unfixedLatency = Number(loadEventEnd - navigationStart) / 1000; + if (unfixedLatency >= 100) { // > 100 no decimal + pageLatency = unfixedLatency.toFixed(); + } else if (unfixedLatency >= 10 && unfixedLatency < 100) { // 100 > 10 use one decimal + pageLatency = unfixedLatency.toFixed(1); + } else if (unfixedLatency < 10 && unfixedLatency >= 0) { // < 10s use two decimals + pageLatency = unfixedLatency.toFixed(2); } + this.setState({ trackerLatencyTotal: pageLatency }); + // reset page load value if page is reloaded while panel is open + } else if (this.props.performanceData && !performanceData) { + this.setState({ trackerLatencyTotal: pageLatency }); } } - /** - * Handles clicking on Ghostery Features: Trust Site, Restrict Site, Custom Settings - * @param {String} button The button that was clicked: trust, restrict, custom + * Disable controls when Ghostery cannot or has not yet scanned a page. + * @param {Object} props Summary's props, either this.props or nextProps. */ - clickSitePolicy(button) { - const { paused_blocking, sitePolicy } = this.props; - let type; - let text; - let classes; + _updateSiteNotScanned(props) { + const { siteNotScanned, categories } = props; + const pageUrl = props.pageUrl || ''; - if (this.state.disableBlocking || paused_blocking) { - return; + if (siteNotScanned || !categories || pageUrl.search(/http|chrome-extension|moz-extension|ms-browser-extension|newtab|chrome:\/\/startpage\//) === -1) { + this.setState({ disableBlocking: true }); + } else { + this.setState({ disableBlocking: false }); } + } - if (button === 'trust' || (button === 'custom' && sitePolicy === 2)) { - sendMessage('ping', 'trust_site'); - type = 'whitelist'; - text = (sitePolicy === 2) ? t('alert_site_trusted_off') : t('alert_site_trusted'); - classes = (sitePolicy === 2) ? 'warning' : 'success'; - } else if (button === 'restrict' || (button === 'custom' && sitePolicy === 1)) { - sendMessage('ping', 'restrict_site'); - type = 'blacklist'; - text = (sitePolicy === 1) ? t('alert_site_restricted_off') : t('alert_site_restricted'); - classes = (sitePolicy === 1) ? 'warning' : 'alert'; + /** + * Handles messages from dynamic UI port to background + * @param {Object} msg updated findings sent from the background by PanelData + */ + handlePortMessage(msg) { + if (msg.to !== 'summary' || !msg.body) { return; } + + const { body } = msg; + + if (body.adblock || body.antitracking) { + this.props.actions.updateCliqzModuleData(body); } else { - return; + this.props.actions.updateSummaryData(body); } + } - this.props.actions.updateSitePolicy({ - type, - }); - - this.props.actions.filterTrackers({ type: 'trackers', name: 'all' }); + _isPlusSubscriber() { + const { user } = this.props; - this.props.actions.showNotification({ - updated: type, - reload: true, - classes, - text, - }); + return user && user.subscriptionsPlus; } - /** - * Handles clicking on Cliqz Features: AntiTracking, AdBlocking, SmartBlocking - * @param {Object} options options including: - * feature: enable_anti_tracking, enable_ad_block, enable_smart_block - * status: whether the feature should be turned on or off - * text: the text for the notification. - */ - clickCliqzFeature(options) { - const { feature, status, text } = options; - this.props.actions.showNotification({ - updated: feature, - reload: true, - text, - }); - this.props.actions.toggleCliqzFeature(feature, status); + _pageHost() { + return this.props.pageHost || 'page_host'; } - /** - * Handles clicking on the green upgrade banner or gold subscriber badge - */ - clickUpgradeBannerOrGoldPlusIcon = () => { - // TODO check whether this is the message we want to be sending now - sendMessage('ping', 'plus_panel_from_badge'); - const { user } = this.props; - const plusSubscriber = user && user.subscriptionsPlus; - this.props.history.push(plusSubscriber ? '/subscription/info' : `/subscribe/${!!user}`); + _hidePageHost(host = null) { + const pageHost = host || this._pageHost(); + + return (pageHost.split('.').length < 2); } - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Summary View of the panel - */ - render() { - const { abPause } = this.state; + _adBlockBlocked() { const { - is_expert, - is_expanded, - enable_anti_tracking, + adBlock, enable_ad_block, - enable_smart_block, + } = this.props; + + return enable_ad_block && adBlock && adBlock.totalCount || 0; + } + + _antiTrackUnsafe() { + const { antiTracking, - adBlock, - smartBlock, - paused_blocking, - sitePolicy, - trackerCounts, - user + enable_anti_tracking, } = this.props; - const plusSubscriber = user && user.subscriptionsPlus; - const showCondensed = is_expert && is_expanded; - const antiTrackUnsafe = enable_anti_tracking && antiTracking && antiTracking.totalUnsafeCount || 0; - const adBlockBlocked = enable_ad_block && adBlock && adBlock.totalCount || 0; + + return enable_anti_tracking && antiTracking && antiTracking.totalUnsafeCount || 0; + } + + _totalTrackersFound() { + const { trackerCounts } = this.props; + + return (trackerCounts.allowed + trackerCounts.blocked + this._requestsModifiedCount()) || 0; + } + + _requestsModifiedCount() { + return this._antiTrackUnsafe() + this._adBlockBlocked(); + } + + _sbBlocked() { + const { smartBlock, trackerCounts } = this.props; + let sbBlocked = smartBlock && smartBlock.blocked && Object.keys(smartBlock.blocked).length || 0; - const pageHost = this.props.pageHost || 'page_host'; - const hidePageHost = (pageHost.split('.').length < 2); if (sbBlocked === trackerCounts.sbBlocked) { sbBlocked = 0; } + + return sbBlocked; + } + + _sbAllowed() { + const { smartBlock, trackerCounts } = this.props; + let sbAllowed = smartBlock && smartBlock.unblocked && Object.keys(smartBlock.unblocked).length || 0; if (sbAllowed === trackerCounts.sbAllowed) { sbAllowed = 0; } - const sbAdjust = enable_smart_block && (sbBlocked - sbAllowed) || 0; - const summaryClassNames = ClassNames('', { - expert: is_expert, - condensed: showCondensed, - 'ab-pause': abPause, - }); + return sbAllowed; + } - const blockedTrackersClassNames = ClassNames('blocked-trackers', { - clickable: is_expert, - }); - const pageLoadClassNames = ClassNames('page-load', { - fast: this.state.trackerLatencyTotal < 5, - slow: this.state.trackerLatencyTotal > 10, - }); + _sbAdjust() { + const { enable_smart_block } = this.props; - const summaryViewStatsButton = ClassNames('stats-button', 'g-tooltip', { - hide: is_expert - }); + return enable_smart_block && (this._sbBlocked() - this._sbAllowed()) || 0; + } + + _totalTrackersBlockedCount() { + const { + paused_blocking, + sitePolicy, + trackerCounts + } = this.props; - let trackersBlockedCount; - if (paused_blocking || sitePolicy === 2) { - trackersBlockedCount = 0; - } else if (sitePolicy === 1) { - trackersBlockedCount = trackerCounts.blocked + trackerCounts.allowed || 0; + let totalTrackersBlockedCount; + if (paused_blocking || sitePolicy === WHITELISTED) { + totalTrackersBlockedCount = 0; + } else if (sitePolicy === BLACKLISTED) { + totalTrackersBlockedCount = trackerCounts.blocked + trackerCounts.allowed || 0; } else { - trackersBlockedCount = trackerCounts.blocked + sbAdjust || 0; + totalTrackersBlockedCount = trackerCounts.blocked + this._sbAdjust() || 0; } - const pageHostClassNames = ClassNames('page-host', { - invisible: hidePageHost + return totalTrackersBlockedCount; + } + + _isCondensed() { + const { is_expanded, is_expert } = this.props; + + return (is_expert && is_expanded); + } + + _isPageLoadFast() { + return this.state.trackerLatencyTotal < 5; + } + + _isPageLoadSlow() { + return this.state.trackerLatencyTotal > 10; + } + + _isPageLoadMedium() { + return !this._isPageLoadFast() && !this._isPageLoadSlow(); + } + + _isCliqzInactive() { + const { paused_blocking, sitePolicy } = this.props; + const { disableBlocking } = this.state; + + return paused_blocking || sitePolicy || disableBlocking || IS_CLIQZ; + } + + /** + * Render helper for the donut + * @return {JSX} JSX for rendering the donut + */ + _renderDonut() { + const { + categories, + is_expert, + paused_blocking, + sitePolicy, + } = this.props; + + return ( +
+ +
+ ); + } + + /** + * Render helper for the page host readout + * @return {JSX} JSX for rendering the page host readout + */ + _renderPageHostReadout() { + const pageHost = this._pageHost(); + const pageHostContainerClassNames = ClassNames('Summary__pageHostContainer', { + invisible: this._hidePageHost(pageHost), }); - const pauseButtonComponent = ( - ); - - const pauseButton = ( -
- pauseButtonComponent + return ( +
+ {pageHost}
); + } - const totalTrackersFound = ( -
- - {this.props.trackerCounts.allowed + this.props.trackerCounts.blocked + antiTrackUnsafe + adBlockBlocked || 0} + /** + * Render helper for the total trackers found readout shown in condensed view + * @return {JSX} JSX for rendering the condensed view total trackers found readout + */ + _renderTotalTrackersFound() { + return ( +
+ + {this._totalTrackersFound()}
); + } - const donut = ( -
- + /** + * Render helper for the total trackers blocked readout + * @return {JSX} JSX for rendering the total trackers blocked readout + */ + _renderTotalTrackersBlocked() { + const { is_expert } = this.props; + + const totalTrackersBlockedContainerClassNames = ClassNames('Summary__pageStatContainer', { + clickable: is_expert, + }); + const totalTrackersBlockedClassNames = ClassNames('SummaryPageStat', 'total-trackers-blocked', { + 'SummaryPageStat--condensed-view': this._isCondensed(), + }); + + return ( +
+
+ {t('trackers_blocked')} + + {this._totalTrackersBlockedCount()} + +
); + } - const totalTrackersBlocked = ( -
- {t('trackers_blocked')} - - {trackersBlockedCount} - + _renderTotalRequestsModified() { + const { is_expert } = this.props; + + const totalRequestsModifiedClassNames = ClassNames('SummaryPageStat', 'g-tooltip', 'total-requests-modified', { + 'SummaryPageStat--condensed-view': this._isCondensed(), + }); + + return ( +
+
+ {t('requests_modified')} + + {this._requestsModifiedCount()} + + +
); + } - const pageLoadTime = ( -
- {t('page_load')} - - {this.state.trackerLatencyTotal ? `${this.state.trackerLatencyTotal} ${t('settings_seconds')}` : '-'} - + _renderPageLoadTime() { + const { trackerLatencyTotal } = this.state; + + const pageLoadTimeClassNames = ClassNames('SummaryPageStat', { + 'page-load-time-slow': this._isPageLoadSlow(), + 'page-load-time-medium': this._isPageLoadMedium(), + 'page-load-time-fast': this._isPageLoadFast(), + 'SummaryPageStat--condensed-view': this._isCondensed(), + }); + + return ( +
+
+ {t('page_load')} + + {trackerLatencyTotal ? `${trackerLatencyTotal} ${t('settings_seconds')}` : '-'} + +
); + } + + _renderGhosteryFeature(type, ...modifiers) { + const { + is_expert, + paused_blocking, + sitePolicy, + } = this.props; + const { disableBlocking } = this.state; + const isCondensed = this._isCondensed(); + const containerClassNames = ClassNames('Summary__ghosteryFeatureContainer', modifiers); - // Trust, Restrict, Pause - const ghosteryFeatures = ( -
- + +
+ ); + } - {!abPause && pauseButtonComponent} + _renderPauseButton() { + const { + is_expert, + paused_blocking, + paused_blocking_timeout, + } = this.props; + + return ( +
+
); + } - // Enhanced Anti-Tracking, Enhanced Ad Blocking, Smart Blocking - const cliqzFeatures = ( -
- +
); + } + + _renderCliqzAdBlock() { + const { + enable_ad_block, + is_expert, + } = this.props; + const isCondensed = this._isCondensed(); - const statsNavButton = ( + return ( +
+ +
+ ); + } + + _renderCliqzSmartBlock() { + const { + enable_smart_block, + is_expert, + } = this.props; + const isCondensed = this._isCondensed(); + + return ( +
+ +
+ ); + } + + /** + * Render helper for the stats nav button + * @return {JSX} JSX for rendering the stats nav button + */ + _renderStatsNavButton() { + const summaryViewStatsButton = ClassNames( + 'Summary__statsButton', + 'Summary__statsButton--absolutely-positioned', + 'g-tooltip', + { + hide: this.props.is_expert, + } + ); + + return (
); + } + + /** + * Render helper for the plus upgrade banner or subscriber icon + * @return {JSX} JSX for rendering the plus upgrade banner or subscriber icon + */ + _renderPlusUpgradeBannerOrSubscriberIcon() { + const { is_expert } = this.props; - const plusUpgradeBannerOrSubscriberIcon = ( + const isPlusSubscriber = this._isPlusSubscriber(); + const upgradeBannerClassNames = ClassNames('UpgradeBanner', { + 'UpgradeBanner--normal': !is_expert, + 'UpgradeBanner--small': is_expert, + }); + + return (
- {plusSubscriber && - + {isPlusSubscriber && +
+
+ +
+
} - {!plusSubscriber && -
- {t('subscription_upgrade_to')} - + {!isPlusSubscriber && +
+
+ {t('subscription_upgrade_to')} +
+
}
); + } - return ( -
- {abPause && pauseButton} + /** + * React's required render function. Returns JSX + * @return {JSX} JSX for rendering the Summary View of the panel + */ + render() { + const { + is_expert, + is_expanded, + } = this.props; + const { disableBlocking } = this.state; + const isCondensed = this._isCondensed(); + const summaryClassNames = ClassNames('Summary', { + 'Summary--simple': !is_expert, + 'Summary--expert': is_expert && !is_expanded, + 'Summary--condensed': isCondensed, + }); - {!showCondensed && this.state.disableBlocking && ()} - {!showCondensed && abPause && !this.state.disableBlocking && is_expert && ( -
- {pageHost} -
- )} - {!showCondensed && !this.state.disableBlocking && donut} - {!showCondensed && !this.state.disableBlocking && (!abPause || !is_expert) && ( -
- {pageHost} -
- )} + return ( +
+ {!isCondensed && disableBlocking && ()} + {!isCondensed && !disableBlocking && this._renderDonut()} + {!isCondensed && !disableBlocking && this._renderPageHostReadout()} - {showCondensed && !this.state.disableBlocking && totalTrackersFound} + {isCondensed && !disableBlocking && this._renderTotalTrackersFound()} - {!this.state.disableBlocking && -
- {totalTrackersBlocked} - {pageLoadTime} -
- } +
+ {!disableBlocking && this._renderTotalTrackersBlocked()} + {!disableBlocking && this._renderTotalRequestsModified()} + {!disableBlocking && this._renderPageLoadTime()} +
- {showCondensed && this.state.disableBlocking && is_expert && ( -
+ {isCondensed && disableBlocking && is_expert && ( +
)} - {ghosteryFeatures} - {cliqzFeatures} - {statsNavButton} - - {!showCondensed && plusUpgradeBannerOrSubscriberIcon} +
+ {this._renderGhosteryFeature('trust')} + {this._renderGhosteryFeature('restrict', 'Summary__ghosteryFeatureContainer--middle')} + {this._renderPauseButton()} +
+
+ {this._renderCliqzAntiTracking()} + {this._renderCliqzAdBlock()} + {this._renderCliqzSmartBlock()} +
+ {this._renderStatsNavButton()} + + {!isCondensed && this._renderPlusUpgradeBannerOrSubscriberIcon()}
); } diff --git a/app/panel/components/__tests__/PauseButton.jsx b/app/panel/components/__tests__/PauseButton.jsx index 115c1624d..9f83869b8 100644 --- a/app/panel/components/__tests__/PauseButton.jsx +++ b/app/panel/components/__tests__/PauseButton.jsx @@ -28,7 +28,6 @@ describe('app/panel/components/BuildingBlocks/PauseButton.jsx', () => { describe('Snapshot tests with react-test-renderer', () => { test('unpaused state in simple view', () => { const initialState = { - isAbPause: false, isPaused: false, isPausedTimeout: null, clickPause: () => {}, @@ -46,7 +45,6 @@ describe('app/panel/components/BuildingBlocks/PauseButton.jsx', () => { test('paused state in detailed view', () => { const initialState = { - isAbPause: false, isPaused: true, isPausedTimeout: null, clickPause: () => {}, @@ -64,7 +62,6 @@ describe('app/panel/components/BuildingBlocks/PauseButton.jsx', () => { test('paused state in detailed condensed view', () => { const initialState = { - isAbPause: true, isPaused: true, isPausedTimeout: null, clickPause: () => {}, @@ -101,11 +98,12 @@ describe('app/panel/components/BuildingBlocks/PauseButton.jsx', () => { expect(component.find('.button.button-pause.active').length).toBe(0); expect(component.find('.button.button-pause.smaller').length).toBe(1); expect(component.find('.button.button-pause.smallest').length).toBe(0); - expect(component.find('.dropdown-container').length).toBe(1); + expect(component.find('.dropdown-container').length).toBe(0); expect(component.find('.dropdown-container .dropdown-item').length).toBe(0); expect(component.find('.button-caret').length).toBe(1); expect(component.find('.button-caret.active').length).toBe(0); component.setState({ showDropdown: true }); + expect(component.find('.dropdown-container').length).toBe(1); expect(component.find('.dropdown-container .dropdown-item').length).toBe(3); expect(component.find('.dropdown-container .dropdown-item.selected').length).toBe(0); expect(component.find('.button-caret.active').length).toBe(1); @@ -130,11 +128,12 @@ describe('app/panel/components/BuildingBlocks/PauseButton.jsx', () => { expect(component.find('.button.button-pause.active').length).toBe(1); expect(component.find('.button.button-pause.smaller').length).toBe(0); expect(component.find('.button.button-pause.smallest').length).toBe(0); - expect(component.find('.dropdown-container').length).toBe(1); + expect(component.find('.dropdown-container').length).toBe(0); expect(component.find('.dropdown-container .dropdown-item').length).toBe(0); expect(component.find('.button-caret').length).toBe(1); expect(component.find('.button-caret.active').length).toBe(0); component.setState({ showDropdown: true }); + expect(component.find('.dropdown-container').length).toBe(1); expect(component.find('.dropdown-container .dropdown-item').length).toBe(3); expect(component.find('.dropdown-container .dropdown-item.selected').length).toBe(1); expect(component.find('.button-caret.active').length).toBe(1); diff --git a/app/panel/components/__tests__/__snapshots__/PauseButton.jsx.snap b/app/panel/components/__tests__/__snapshots__/PauseButton.jsx.snap index 70261a31b..c6184528b 100644 --- a/app/panel/components/__tests__/__snapshots__/PauseButton.jsx.snap +++ b/app/panel/components/__tests__/__snapshots__/PauseButton.jsx.snap @@ -8,7 +8,7 @@ exports[`app/panel/components/BuildingBlocks/PauseButton.jsx Snapshot tests with className="button-group" >
-
`; @@ -49,7 +41,7 @@ exports[`app/panel/components/BuildingBlocks/PauseButton.jsx Snapshot tests with className="button-group" >
-
`; @@ -92,7 +76,7 @@ exports[`app/panel/components/BuildingBlocks/PauseButton.jsx Snapshot tests with className="button-group" >
-
`; diff --git a/app/scss/panel.scss b/app/scss/panel.scss index 2f168457f..c37affeec 100644 --- a/app/scss/panel.scss +++ b/app/scss/panel.scss @@ -14,12 +14,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -//Import Global Partials +// Import Global Partials @import "settings"; //includes _colors.scss @import './partials/_fonts'; @import './partials/_placeholders'; @import './partials/_mixins'; +// Import shared helpers +@import 'shared_helper_classes'; + html body { margin: 0px; font-size: 75%; @@ -51,6 +54,8 @@ html body { @import './partials/_header'; @import './partials/_callout'; @import './partials/_summary'; +@import './partials/_upgrade_banner'; +@import './partials/_subscriber_badge'; @import './partials/_detail'; @import './partials/_blocking'; @import './partials/_rewards'; @@ -61,8 +66,8 @@ html body { @import './partials/_toggle_slider'; @import './partials/_pause_button'; @import './partials/_donut_graph'; -@import './partials/_ghostery_features'; -@import './partials/_cliqz_features'; +@import './partials/_ghostery_feature'; +@import './partials/_cliqz_feature'; @import './partials/_tooltip'; @import './partials/_not_scanned'; @import './partials/_subscribe'; diff --git a/app/scss/partials/_cliqz_feature.scss b/app/scss/partials/_cliqz_feature.scss new file mode 100644 index 000000000..525312a59 --- /dev/null +++ b/app/scss/partials/_cliqz_feature.scss @@ -0,0 +1,129 @@ +/** + * Cliqz Features Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +$cliqz-feature--darker-blue: #0093bd; +$cliqz-feature--blue: #1dafed; +$cliqz-feature--pale-blue: #a4d4f2; +$cliqz-feature--gray: #c8c7c2; +$cliqz-feature--light-gray: #dedede; +$cliqz-feature--darker-gray: #a4a4a4; + +// Default styling for the elements of the CliqzFeature BEM block +.CliqzFeature__status { + text-align: center; + font-size: 14px; + font-weight: 600; + text-transform: uppercase; + transition: color 0.25s ease-out; + transition: background-image 0.25s ease-out; +} + +.CliqzFeature__icon { + margin: 0 auto; + background-repeat: no-repeat; + background-position: center center; + transition: background-image 0.25s ease-out; +} + +.CliqzFeature__feature-name { + text-align: center; + font-size: 11px; + line-height: 26px; + font-weight: 600; + transition: color 0.25s ease-out; + + white-space: nowrap; + overflow-x: hidden; + text-overflow: ellipsis; +} + +// Modifications to element styling based on size-related block-level modifiers +// The CliqzFeature block is always one of normal, smaller, or condensed +.CliqzFeature--normal, +.CliqzFeature--smaller { + .CliqzFeature__status { line-height: 28px; } + .CliqzFeature__icon { + height: 50px; + width: 50px; + background-size: 50px 50px; + } +} + +.CliqzFeature--smaller { + .CliqzFeature__feature-name { display: none; } +} + +.CliqzFeature--condensed { + .CliqzFeature__status { line-height: 14px; } + .CliqzFeature__icon { + height: 40px; + width: 40px; + background-size: 30px 30px; + } + .CliqzFeature__feature-name { display: none; } +} + +// Modifications to element styling based on state-related block-level modifiers +// The CliqzFeature block is always either active or inactive +// and always either clickable or not-clickable +.CliqzFeature--active.clickable { + .CliqzFeature__status { + color: $cliqz-feature--blue; + background: none; + } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--blue); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--blue); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--blue); } + .CliqzFeature__feature-name { color: $cliqz-feature--blue; } + + &:hover { + .CliqzFeature__status { color: $cliqz-feature--darker-blue; } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--darker-blue); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--darker-blue); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--darker-blue); } + .CliqzFeature__feature-name { color: $cliqz-feature--darker-blue; } + } +} + +.CliqzFeature--active.not-clickable { + .CliqzFeature__status { color: $cliqz-feature--pale-blue; } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--pale-blue); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--pale-blue); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--pale-blue); } + .CliqzFeature__feature-name { color: $cliqz-feature--pale-blue; } + +} + +.CliqzFeature--inactive.clickable { + .CliqzFeature__status { color: $cliqz-feature--gray; } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--gray); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--gray); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--gray); } + .CliqzFeature__feature-name { color: $cliqz-feature--gray; } + + &:hover { + .CliqzFeature__status { color: $cliqz-feature--darker-gray; } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--darker-gray); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--darker-gray); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--darker-gray); } + .CliqzFeature__feature-name { color: $cliqz-feature--darker-gray; } + } +} + +.CliqzFeature--inactive.not-clickable { + .CliqzFeature__status { color: $cliqz-feature--light-gray; } + .CliqzFeature__icon--anti-track { background-image: buildIconAntiTracking($cliqz-feature--light-gray); } + .CliqzFeature__icon--ad-block { background-image: buildIconAdBlocking($cliqz-feature--light-gray); } + .CliqzFeature__icon--smart-block { background-image: buildIconSmartBlocking($cliqz-feature--light-gray); } + .CliqzFeature__feature-name { color: $cliqz-feature--light-gray; } +} diff --git a/app/scss/partials/_cliqz_features.scss b/app/scss/partials/_cliqz_features.scss deleted file mode 100644 index 3e0815f28..000000000 --- a/app/scss/partials/_cliqz_features.scss +++ /dev/null @@ -1,122 +0,0 @@ -/** - * Cliqz Features Sass - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2019 Ghostery, Inc. All rights reserved. - * - * 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 - */ - -.sub-component.cliqz-features { - .cliqz-feature { - display: inline-block; - width: 150px; - margin: 0 10px; - } - &.smaller .cliqz-feature { - width: 55px; - margin: 0 10px; - } - &.smaller.condensed .cliqz-feature { - width: 40px; - margin: 0 0 5px; - .count { - line-height: 14px; - } - .icon { - width: 40px; - height: 40px; - background-size: 30px 30px; - } - } - - .count { - color: rgba(#c8c7c2, 0); - text-align: center; - font-size: 14px; - line-height: 28px; - font-weight: 600; - transition: color 0.25s ease-out; - - background-repeat: no-repeat; - background-position: center center; - background-size: 10px 10px; - transition: background-image 0.25s ease-out; - background-image: buildIconDash(#c8c7c2); - } - .active .count { - color: #1dafed; - background: none; - } - &.inactive .count { - color: rgba(#dedede, 0); - background-image: buildIconDash(#dedede); - } - &.inactive .active .count { - color: #a4d4f2; - background: none; - } - - .icon { - margin: 0 auto; - height: 50px; - width: 50px; - background-repeat: no-repeat; - background-position: center center; - background-size: 50px 50px; - transition: background-image 0.25s ease-out; - } - .anti-tracking .icon { background-image: buildIconAntiTracking(#c8c7c2); } - .active.anti-tracking .icon { background-image: buildIconAntiTracking(#1dafed); } - &.inactive .anti-tracking .icon { background-image: buildIconAntiTracking(#dedede); } - &.inactive .active.anti-tracking .icon { background-image: buildIconAntiTracking(#a4d4f2); } - - .ad-blocking .icon { background-image: buildIconAdBlocking(#c8c7c2); } - .active.ad-blocking .icon { background-image: buildIconAdBlocking(#1dafed); } - &.inactive .ad-blocking .icon { background-image: buildIconAdBlocking(#dedede); } - &.inactive .active.ad-blocking .icon { background-image: buildIconAdBlocking(#a4d4f2); } - - .smart-blocking .icon { background-image: buildIconSmartBlocking(#c8c7c2); } - .active.smart-blocking .icon { background-image: buildIconSmartBlocking(#1dafed); } - &.inactive .smart-blocking .icon { background-image: buildIconSmartBlocking(#dedede); } - &.inactive .active.smart-blocking .icon { background-image: buildIconSmartBlocking(#a4d4f2); } - - .feature-name { - color: #c8c7c2; - text-align: center; - font-size: 11px; - line-height: 26px; - font-weight: 600; - transition: color 0.25s ease-out; - - white-space: nowrap; - overflow-x: hidden; - text-overflow: ellipsis; - } - .active .feature-name { color: #1dafed; } - &.inactive .feature-name { color: #dedede; } - &.inactive .active .feature-name { color: #a4d4f2; } - &.smaller .feature-name { display: none; } - - .cliqz-feature.clickable:hover { - .count { background-image: buildIconDash(#a4a4a4); } - &.anti-tracking .icon { background-image: buildIconAntiTracking(#a4a4a4); } - &.ad-blocking .icon { background-image: buildIconAdBlocking(#a4a4a4); } - &.smart-blocking .icon { background-image: buildIconSmartBlocking(#a4a4a4); } - .feature-name { color: #a4a4a4; } - } - .cliqz-feature.active.clickable:hover { - .count { - color: #0093bd; - background: none; - } - &.anti-tracking .icon { background-image: buildIconAntiTracking(#0093bd); } - &.ad-blocking .icon { background-image: buildIconAdBlocking(#0093bd); } - &.smart-blocking .icon { background-image: buildIconSmartBlocking(#0093bd); } - .feature-name { color: #0093bd; } - } -} diff --git a/app/scss/partials/_donut_graph.scss b/app/scss/partials/_donut_graph.scss index a6d963a27..829bce2a4 100644 --- a/app/scss/partials/_donut_graph.scss +++ b/app/scss/partials/_donut_graph.scss @@ -11,54 +11,66 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -.sub-component.donut-graph { - .graph-text { - text-transform: capitalize; - text-align: center; - font-size: 12px; - line-height: 16px; - font-weight: 500; - padding: 13px 0; - color: #4a4a4a; - } - &.big .graph-text { +.DonutGraph--big { + .DonutGraph__textCountContainer { margin-top: -125px; height: 120px; } - &.small .graph-text { - margin-top: -99px; - height: 94px; - } - .graph-text-count { + + .DonutGraph__textCount { height: 94px; font-size: 42px; line-height: 90px; - font-weight: 700; } - &.small .graph-text-count { +} + +.DonutGraph--small { + .DonutGraph__textCountContainer { + margin-top: -99px; + height: 94px; + } + + .DonutGraph__textCount { height: 68px; font-size: 28px; line-height: 64px; } +} - .tooltip-container { - position: relative; - height: 0; - width: 0; - .tooltip { - white-space: nowrap; - pointer-events: none; - opacity: 0; - visibility: hidden; - transition: opacity .2s ease-in; - } - .tooltip.show { - visibility: visible; - opacity: 1; - } - .tooltip::before { - left: 50%; - margin-left: -8px; - } - } +.DonutGraph__tooltipContainer { + position: relative; + height: 0; + width: 0; +} + +.DonutGraph__tooltip { + white-space: nowrap; + pointer-events: none; + visibility: hidden; + opacity: 0; + transition: opacity .2s ease-in; +} + +.DonutGraph__tooltip--show { + visibility: visible; + opacity: 1; +} + +.DonutGraph__tooltip::before { + left: 50%; + margin-left: -8px; +} + +.DonutGraph__textCountContainer { + text-transform: capitalize; + text-align: center; + font-size: 12px; + line-height: 16px; + font-weight: 500; + padding: 13px 0; + color: $tundora; +} + +.DonutGraph__textCount { + font-weight: 700; } diff --git a/app/scss/partials/_ghostery_feature.scss b/app/scss/partials/_ghostery_feature.scss new file mode 100644 index 000000000..7d1d41a12 --- /dev/null +++ b/app/scss/partials/_ghostery_feature.scss @@ -0,0 +1,134 @@ +/** + * Ghostery Feature Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +.GhosteryFeatureButton__text { + background-repeat: no-repeat; + background-size: 14px 14px; +} + +.GhosteryFeatureButton { + transition: background-image 0.25s ease-out, + background-color 0.25s ease-out, + border-color 0.25s ease-out, + box-shadow 0.25s ease-out, + color 0.25s ease-out; + + // Foundation .button overrides + margin-bottom: 0; + line-height: 1.5; + font-size: 11px; +} + +.GhosteryFeatureButton--normal, +.GhosteryFeatureButton--short { + width: 150px; + + .GhosteryFeatureButton__text { + padding: 0 10px 0 30px; + background-position: 0 center; + } +} + +.GhosteryFeatureButton--normal { + height: 45px; +} + +.GhosteryFeatureButton--short { + height: 35px; +} + +.GhosteryFeatureButton--narrow { + width: 66px; + height: 41px; + + .GhosteryFeatureButton__text { + padding: 10px; + font-size: 9px; + background-position: center center; + } +} + +.GhosteryFeatureButton--inactive.clickable { + color: $tundora; + border-color: #cccccc; + background-color: $white; + box-shadow: inset 0 0 0 0 rgba($white, 0); + &:hover { color: $tundora; } + + &.trust .GhosteryFeatureButton__text { + background-image: buildIconTrust($tundora); + } + + &.restrict .GhosteryFeatureButton__text { + background-image: buildIconRestrict($tundora); + } +} + +.GhosteryFeatureButton--inactive.not-clickable { + color: #a4a4a4; + border-color: #e5e5e5; + background-color: #ffffff; + box-shadow: inset 0 0 0 0 rgba($white, 0); + + &.trust .GhosteryFeatureButton__text { + background-image: buildIconTrust(#a4a4a4); + } + + &.restrict .GhosteryFeatureButton__text { + background-image: buildIconRestrict(#a4a4a4); + } +} + +.GhosteryFeatureButton--active.clickable { + color: $white; + + &.trust { + border-color: #85b329; + background-color: $atlantis; + box-shadow: inset 0px 1px 7px 2px #85b329; + } + &.trust:hover { background-color: #85b329; } + &.trust .GhosteryFeatureButton__text { + background-image: buildIconTrust($white); + } + + &.restrict { + border-color: #ce273c; + background-color: $red; + box-shadow: inset 0px 1px 7px 2px #ce273c; + } + &.restrict:hover { background-color: #ce273c; } + &.restrict .GhosteryFeatureButton__text { + background-image: buildIconRestrict($white); + } +} + +.GhosteryFeatureButton--active.not-clickable { + &.trust { + color: $white; + border-color: #b8e65c; + background-color: #b8e65c; + } + &.trust .GhosteryFeatureButton__text { + background-image: buildIconTrust($white); + } + + &.restrict { + color: $white; + border-color: #ff8da2; + background-color: #ff8da2; + } + &.restrict .GhosteryFeatureButton__text { + background-image: buildIconRestrict($white); + } +} diff --git a/app/scss/partials/_ghostery_features.scss b/app/scss/partials/_ghostery_features.scss deleted file mode 100644 index b2d4393d0..000000000 --- a/app/scss/partials/_ghostery_features.scss +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Ghostery Features Sass - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2019 Ghostery, Inc. All rights reserved. - * - * 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 - */ - -.sub-component.ghostery-features { - .button { - width: 150px; - height: 45px; - font-size: 11px; - line-height: 1.5; - color: #4a4a4a; - border-color: #cccccc; - background-color: #ffffff; - margin-bottom: 0; - box-shadow: inset 0 0 0 0 rgba($white, 0); - - transition: background-image 0.25s ease-out, - background-color 0.25s ease-out, - border-color 0.25s ease-out, - box-shadow 0.25 ease-out, - color 0.25s ease-out; - &:hover { - background-color: #efefef; - } - } - .button.active.button-trust { - color: #ffffff; - border-color: #85b329; - background-color: #9ecc42; - box-shadow: inset 0px 1px 7px 2px #85b329; - &:hover { - background-color: #85b329; - } - } - .button.active.button-restrict { - color: #ffffff; - border-color: #ce273c; - background-color: #e74055; - box-shadow: inset 0px 1px 7px 2px #ce273c; - &:hover { - background-color: #ce273c; - } - } - .button.active.ab-pause { - color: #ffffff; - border-color: #2092bf; - background-color: #1dafed; - box-shadow: inset 0px 1px 7px 2px #2092bf; - &:hover { - background-color: #0093bd; - } - } - - .full-height { height: 100%; } - .button-trust .button-text, - .button-restrict .button-text { - padding: 0 10px 0 30px; - background-repeat: no-repeat; - background-position: 0 center; - background-size: 14px 14px; - } - .button-trust .button-text { - background-image: buildIconTrust(#4a4a4a); - } - .button-trust.active .button-text { - background-image: buildIconTrust(#ffffff); - } - .button-restrict .button-text { - background-image: buildIconRestrict(#4a4a4a); - } - .button-restrict.active .button-text { - background-image: buildIconRestrict(#ffffff); - } - - .button-group.inactive { - .button { - color: #a4a4a4; - border-color: #e5e5e5; - background-color: #ffffff; - box-shadow: inset 0 0 0 0 rgba($white, 0); - } - .button.active.button-trust { - color: #ffffff; - border-color: #b8e65c; - background-color: #b8e65c; - } - .button.active.button-restrict { - color: #ffffff; - border-color: #ff8da2; - background-color: #ff8da2; - } - .button.active.ab-pause { - color: #ffffff; - border-color: #a4d4f2; - background-color: #a4d4f2; - } - .button-trust .button-text { - background-image: buildIconTrust(#a4a4a4); - } - .button-trust.active .button-text { - background-image: buildIconTrust(#ffffff); - } - .button-restrict .button-text { - background-image: buildIconRestrict(#a4a4a4); - } - .button-restrict.active .button-text { - background-image: buildIconRestrict(#ffffff); - } - } - - .button-group.stacked .button { - height: 35px; - margin-bottom: 0; - } - .button-group.stacked .button.condensed { - width: 66px; - height: 41px; - .button-text { - padding: 10px; - font-size: 9px; - background-position: center center; - } - } - - .button-top { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border-bottom: 0; - } - .button-left { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; - } - .button-center { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - } - .button-bottom { - border-top-left-radius: 0; - border-top-right-radius: 0; - border-top: 0; - } - .button-right { - border-top-left-radius: 0; - border-bottom-left-radius: 0; - border-left: 0; - } -} diff --git a/app/scss/partials/_pause_button.scss b/app/scss/partials/_pause_button.scss index 96a9c4e02..c398075d9 100644 --- a/app/scss/partials/_pause_button.scss +++ b/app/scss/partials/_pause_button.scss @@ -25,20 +25,22 @@ } .button.active { color: #ffffff; - border-color: #1dafed; + border-color: #0093bd; background-color: #1dafed; - box-shadow: inset 0px 1px 7px 2px rgba(#1dafed, 0); + box-shadow: inset 0px 1px 7px 2px #0093bd; & + .button.active { border-left-color: #efefea; } } - .button:hover { background-color: #efefef; } + .button:hover { background-color: #0093bd; } .button.active:hover { border-color: #0093bd; background-color: #0093bd; } .button-pause { + height: 35px; + min-width: 125px; max-width: 125px; line-height: 16px; @@ -62,19 +64,29 @@ background-image: buildIconPlay(#ffffff); } &.smaller { - min-width: 100px; - max-width: 150px; + height: 45px; } - &.smallest { - min-width: 41px; - max-width: 41px; - padding-left: 17px; - .pause-button-icon { - padding: 0 0 0 15px; - } + } + + .button-pause.smallest { + height: 41px; + min-width: 41px; + max-width: 41px; + padding-left: 15px; + border-top: none; + border-bottom-left-radius: 3px; + line-height: 27px; + .pause-button-icon { + padding: 0 0 0 15px; } } + + .button-pause.smallest.dropdown-open { + border-bottom-left-radius: 0; + } + .button-caret { + height: 35px; width: 25px; padding-top: 21px; padding-right: 0; @@ -82,9 +94,24 @@ background-position: center center; background-size: 9px 5px; background-image: buildIconCaretDown(#4a4a4a); - &.active { - background-image: buildIconCaretDown(#ffffff); - } + } + + .button-caret.active { + background-image: buildIconCaretDown(#ffffff); + } + + .button-caret.smaller { + height: 45px; + } + + .button-caret.smallest { + height: 41px; + border-top: none; + border-bottom-right-radius: 3px; + } + + .button-caret.smallest.dropdown-open { + border-bottom-right-radius: 0; } .button-left { @@ -95,6 +122,7 @@ border-bottom-left-radius: 0; } } + .button-right { border-top-left-radius: 0; border-bottom-left-radius: 0; @@ -108,13 +136,13 @@ width: 0; height: 0; top: 0; + left: 0; .dropdown { - text-align: center; - background-color: #ffffff; + position: absolute; + z-index: 1; border: 1px solid #cccccc; border-top: 0; - margin: 0 auto; border-bottom-left-radius: 3px; border-bottom-right-radius: 3px; } @@ -141,6 +169,10 @@ } } + .dropdown-container.centered .dropdown-item { + padding: 6px 0; + } + .no-border-radius { border-bottom-right-radius: 0; border-bottom-left-radius: 0; @@ -148,54 +180,3 @@ border-top-left-radius: 0; } } - -.ghostery-features-container .sub-component.pause-button { - .button-pause { - height: 35px; - line-height: 16px; - } - .button-caret { - height: 35px; - } - .button-pause.smaller { - height: 45px; - min-width: 125px; - max-width: 125px; - } - .button-caret.smaller { - height: 45px; - } - .button.active { - border-color: #0093bd; - background-color: #1dafed; - box-shadow: inset 0px 1px 7px 2px #0093bd; - &:hover { - background-color: #0093bd; - } - } - .button-pause.smallest { - padding-left: 15px; - height: 41px; - line-height: 27px; - border-top: none; - border-bottom-left-radius: 3px; - &.dropdown-open { - border-bottom-left-radius: 0; - } - } - .button-caret.smallest { - height: 41px; - border-top: none; - border-bottom-right-radius: 3px; - &.dropdown-open { - border-bottom-right-radius: 0; - } - } - .dropdown { - position: absolute; - z-index: 1; - } - .dropdown-container.centered .dropdown-item { - padding: 9px 0; - } -} diff --git a/app/scss/partials/_rewards.scss b/app/scss/partials/_rewards.scss index a152d6b0b..dd42e5d89 100644 --- a/app/scss/partials/_rewards.scss +++ b/app/scss/partials/_rewards.scss @@ -11,23 +11,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -// Universal Classes -.full-height { - height: 100%; -} -.full-width { - width: 100%; -} -.display-inline-block { - display: inline-block; -} -.clickable { - @extend %pointer; -} -.not-clickable { - cursor: not-allowed; -} - // Rewards Panel Component Classes .RewardsPanel { background-color: #ffffff; diff --git a/app/scss/partials/_subscriber_badge.scss b/app/scss/partials/_subscriber_badge.scss new file mode 100644 index 000000000..9c486b0ff --- /dev/null +++ b/app/scss/partials/_subscriber_badge.scss @@ -0,0 +1,16 @@ +/** + * Subscriber Badge Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +.SubscriberBadge { + @extend %pointer; +} diff --git a/app/scss/partials/_summary.scss b/app/scss/partials/_summary.scss index 0b37a9f76..1fd7459f5 100644 --- a/app/scss/partials/_summary.scss +++ b/app/scss/partials/_summary.scss @@ -11,306 +11,205 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -#content-summary { +.Summary { position: absolute; height: 479px; - width: 100%; - - &.expert { - width: 235px; - padding-top: 15px; - } - - &.expert.condensed { - width: 66px; - padding-top: 0; - background-color: #f9f6f6; - } +} - .clickable { - cursor: pointer; - } +.Summary__donutContainer { + margin: 26px auto; +} - .not-clickable { - cursor: not-allowed; - } +.Summary__pageHostContainer { + text-align: center; +} - &.ab-pause .pause-button-container { - padding: 10px 0 0 10px; - text-align: left; - } +.SummaryPageHost { + font-size: 11px; + font-weight: 600; + color: #4a4a4a; +} - &.ab-pause .sub-component.pause-button { - .button-pause { - font-size: 11px; - } - } +.Summary__pageStatsContainer { + text-align: center; +} - &.expert.ab-pause .pause-button-container { - padding: 10px 0 0 0; - text-align: center; - } +.Summary__pageStatContainer { + text-align: center; +} - &.expert.condensed.ab-pause .pause-button-container { - padding: 0; - text-align: left; - } +.SummaryPageStat { + line-height: 21px; + font-size: 14px; + font-weight: 600; +} - .page-host { - color: #4a4a4a; - text-align: center; - font-size: 11px; - font-weight: 600; - margin-bottom: 36px; +.SummaryPageStat--condensed-view { + padding: 0; + margin: 5px 0; - &.invisible { - visibility: hidden; - } + .SummaryPageStat__label { + display: none; } +} - &.ab-pause .page-host { - margin-bottom: 30px; - } +.SummaryPageStat.total-trackers-blocked .SummaryPageStat__value { color: #e74055; } +.SummaryPageStat.total-requests-modified .SummaryPageStat__value { color: #00aef0; } +.SummaryPageStat.page-load-time-slow .SummaryPageStat__value { color: #e74055; } +.SummaryPageStat.page-load-time-medium .SummaryPageStat__value { color: #ffc063; } +.SummaryPageStat.page-load-time-fast .SummaryPageStat__value { color: #9ecc42; } - &.expert .page-host { - margin-top: 20px; - margin-bottom: 20px; - } +.Summary--simple { + width: 100%; - &.expert.ab-pause .page-host { - margin-top: 8px; - margin-bottom: 8px; + .Summary__pageHostContainer { + margin-bottom: 36px; } - .donut-graph-container { - margin: 26px auto; + .Summary__donutContainer { height: 120px; width: 120px; } - &.ab-pause .donut-graph-container { - margin-top: 0; - margin-bottom: 30px; - } - - &.expert .donut-graph-container { - height: 94px; - width: 94px; - margin-top: 21px; - margin-bottom: 20px; - } - - &.expert.ab-pause .donut-graph-container { - margin-top: 0; - margin-bottom: 16px; - } - - &.expert.condensed .total-tracker-count { - text-align: center; - padding: 0; - color: #4a4a4a; - font-size: 24px; - font-weight: 600; - margin: 18px 0; - } - - &.expert.condensed.ab-pause .total-tracker-count { - margin: 13px 0; - } - - .page-stats { - color: #4a4a4a; - text-align: center; - font-size: 14px; - line-height: 21px; - font-weight: 600; + .Summary__pageStatsContainer { margin-bottom: 40px; - - .blocked-trackers .value { - color: #e74055; - } - - .page-load .value { - color: #ffc063; - } - - .page-load.fast .value { - color: #9ecc42; - } - - .page-load.slow .value { - color: #e74055; - } - - .blocked-trackers, - .page-load { - display: inline-block; - padding: 0 20px; - } } - &.expert .page-stats { - margin-bottom: 21px; - - .blocked-trackers, - .page-load { - display: block; - text-overflow: ellipsis; - white-space: nowrap; - overflow-x: hidden; - } - } - - &.expert.ab-pause .page-stats { - margin-bottom: 16px; + .Summary__pageStatContainer { + display: inline-block; + padding: 0 20px; } - &.expert.condensed .page-stats { - div { - text-align: center; - padding: 0; - margin: 21px 0; - } - - .text { - display: none; - } + .Summary__ghosteryFeatureContainer--middle { + margin: 12px 28px; } - &.expert.condensed.ab-pause .page-stats { - margin-bottom: 0; - - div { - margin: 13px 0; - } + .Summary__cliqzFeatureContainer { + width: 150px; } +} - .not-scanned-expert-condensed-space-taker { - height: 162px; - } +.Summary--expert { + width: 235px; + padding-top: 10px; - &.ab-pause .not-scanned-expert-condensed-space-taker { - height: 130px; + .Summary__pageHostContainer { + margin-top: 20px; + margin-bottom: 10px; } - .ghostery-features-container { - text-align: center; - - .ghostery-features, - .pause-button { - display: inline-block; - } + .Summary__donutContainer { + height: 94px; + width: 94px; + margin-top: 21px; + margin-bottom: 20px; + padding-top: 5px; } - &.ab-pause .ghostery-features-container { - margin-bottom: 22px; - - .ghostery-features { - display: block; - } + .Summary__pageStatsContainer { + margin-bottom: 21px; } - &.expert.ab-pause .ghostery-features-container { - margin-bottom: 16px; + .Summary__pageStatContainer { + display: block; + text-overflow: ellipsis; + white-space: nowrap; } - &.expert.condensed.ab-pause .ghostery-features-container { - margin-bottom: -8px; + // .total-requests-modified needs to show overflow for tooltip + .Summary__pageStatContainer .total-trackers-blocked, + .Summary__pageStatContainer .page_load_time { + overflow-x: hidden; } - .ghostery-features-container .button-restrict { + .Summary__ghosteryFeatureContainer--middle { margin: 12px 28px; } - &.expert.condensed .ghostery-features-container .button-restrict { - margin: 0; + .Summary__cliqzFeaturesContainer { + margin-top: 6px; + margin-bottom: 6px; } - &.ab-pause .ghostery-features-container .button-restrict { - margin: 0; + .Summary__cliqzFeatureContainer { + width: 55px; } +} - .cliqz-features-container { - text-align: center; - } +.Summary--condensed { + width: 66px; + background-color: #f9f6f6; - &.expert .cliqz-features-container { - margin-top: 10px; - margin-bottom: 6px; + .Summary__totalTrackerCountContainer { + margin: 10px 0; + padding: 0; + text-align: center; + font-size: 24px; + font-weight: 600; + color: $tundora; } - &.expert.ab-pause .cliqz-features-container { - margin-top: 0; - margin-bottom: 16px; + .Summary__pageStatsContainer { + margin-bottom: 12px; } - &.expert.condensed.ab-pause .cliqz-features-container { - margin-top: 14px; + .Summary__cliqzFeaturesContainer { + margin-top: 15px; + margin-bottom: 0; } - &.expert.condensed .cliqz-features-container { + .Summary__cliqzFeatureContainer:last-of-type { margin-bottom: 0; - - .cliqz-feature:last-of-type { - margin-bottom: 0; - } } - .stats-button { - position: absolute; - right: 0; - top: 40px; - padding: 6px 3px 3px 9px; - border: 1px lightgray solid; - border-radius: 5px 0 0 5px; + .Summary__cliqzFeatureContainer { + width: 40px; + margin: 0 0 5px; } +} - .upgrade-banner-container { - @extend %pointer; - position: absolute; - top: 10px; - background: url("../../app/images/panel/green-upgrade-banner.svg"); - background-size: 100% 23px; - height: 23px; - } +// Additional specificity needed to overwrite the position value of g-tooltip +.Summary__statsButton.Summary__statsButton--absolutely-positioned { + position: absolute; + right: 0; + top: 40px; + padding: 6px 3px 3px 9px; + border: 1px lightgray solid; + border-radius: 5px 0 0 5px; +} - &.expert .upgrade-banner-container { - background-size: 100% 20px; - height: 20px; - } +.Summary__spaceTaker { + height: 162px; +} - .upgrade-banner-text { - display: inline-block; - font-family: "Open Sans", "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; - font-weight: bold; - color: white; +.Summary__ghosteryFeaturesContainer { + text-align: center; +} - font-size: 12px; - vertical-align: sub; - padding: 0 4px 0 10px; - } +.Summary__ghosteryFeatureContainer { + display: inline-block; +} - &.expert .upgrade-banner-text { - font-size: 10px; - vertical-align: baseline; - padding-left: 8px; - } +.Summary__pauseButtonContainer { + display: inline-block; +} - .upgrade-banner-plus { - display: inline-block; - padding-right: 18px; +.Summary__cliqzFeaturesContainer { + text-align: center; +} - vertical-align: sub; - } +.Summary__cliqzFeatureContainer { + display: inline-block; + margin: 0 10px; +} - &.expert .upgrade-banner-plus { - vertical-align: middle; - } +.Summary__upgradeBannerContainer { + position: absolute; + top: 10px; +} - .gold-plus-icon { - @extend %pointer; - position: absolute; - left: 10px; - top: 11px; - } +.Summary__subscriberBadgeContainer { + position: absolute; + left: 10px; + top: 11px; } diff --git a/app/scss/partials/_svgs.scss b/app/scss/partials/_svgs.scss index 3d2f8b98b..80029dd58 100644 --- a/app/scss/partials/_svgs.scss +++ b/app/scss/partials/_svgs.scss @@ -32,11 +32,6 @@ @return url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2250%22%20height%3D%2250%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Ccircle%20stroke%3D%22#{url-friendly-colour($stroke-color)}%22%20stroke-width%3D%222%22%20fill%3D%22none%22%20cx%3D%2225%22%20cy%3D%2225%22%20r%3D%2223%22/%3E%3Cpath%20fill%3D%22#{url-friendly-colour($stroke-color)}%22%20d%3D%22M31.977%2020.24c-.097%201.677-.697%203.156-1.654%204.514-.43.61-.867%201.217-1.285%201.84-.597.887-1.074%201.832-1.258%202.898-.03.175-.141.162-.263.162l-2.525-.001c-.832%200-1.663-.005-2.497.003-.181.002-.246-.05-.283-.238-.197-1.031-.657-1.954-1.241-2.818-.497-.733-1.015-1.454-1.514-2.187A8.257%208.257%200%200%201%2018.011%2020c-.112-2.82%201.486-5.279%204.185-6.42%203.458-1.462%207.547.004%209.166%203.293.521%201.062.682%202.19.615%203.365zM22.352%2032.3v-.63h5.305v.63h-5.305zm4.76%202.681h-4.216c-.508%200-.602-.108-.536-.653h5.28c.075.537-.022.653-.529.653zm6.238-18.576c-1.449-3.169-3.966-4.928-7.385-5.335-2.913-.348-5.446.61-7.511%202.673-2.305%202.306-2.858%205.124-2.19%208.241.351%201.63%201.149%203.046%202.104%204.39.438.617.869%201.243%201.271%201.883.372.593.635%201.241.661%201.946.03.814.008%201.627.008%202.441h.032c0%20.676-.001%201.351.002%202.027.006%201.204.952%202.22%202.15%202.3.158.01.21.056.25.214a2.322%202.322%200%200%200%204.524-.007c.034-.14.072-.194.225-.206a2.329%202.329%200%200%200%202.174-2.337c0-1.257.01-2.515-.003-3.774-.011-.941.208-1.816.706-2.61.402-.64.832-1.268%201.274-1.88%201.263-1.757%202.155-3.653%202.323-5.844.109-1.423-.018-2.816-.615-4.122z%22/%3E%3Cpath%20stroke%3D%22#{url-friendly-colour($stroke-color)}%22%20stroke-width%3D%221.5%22%20fill%3D%22none%22%20d%3D%22M25.096%2018.214a.324.324%200%200%200-.192%200l-4.117%201.092a.37.37%200%200%200-.287.364c.02%202.932%201.59%205.652%204.29%207.472a.387.387%200%200%200%20.21.058c.077%200%20.153-.02.21-.058%202.7-1.82%204.27-4.54%204.29-7.472a.37.37%200%200%200-.287-.364l-4.117-1.092z%22/%3E%3C/svg%3E'); } -// Used in Cliqz Features -@function buildIconDash($stroke-color) { - @return url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2210%22%20height%3D%2210%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%3Cpath%20stroke%3D%22#{url-friendly-colour($stroke-color)}%22%20stroke-width%3D%223%22%20d%3D%22M1%205h8%22/%3E%3C/svg%3E'); -} - // Used in Ghostery Features @function buildIconTrust($stroke-color) { @return url('data:image/svg+xml;charset%3DUS-ASCII,%3Csvg%20width%3D%2214%22%20height%3D%2214%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22>%3Ccircle%20cx%3D%227%22%20cy%3D%227%22%20r%3D%226%22%20stroke-width%3D%222%22%20stroke%3D%22#{url-friendly-colour($stroke-color)}%22%20fill%3D%22none%22/%3E%3C/svg%3E'); diff --git a/app/scss/partials/_tooltip.scss b/app/scss/partials/_tooltip.scss index 2a203bb9d..ef37da0b4 100644 --- a/app/scss/partials/_tooltip.scss +++ b/app/scss/partials/_tooltip.scss @@ -117,44 +117,78 @@ } } -.summary-total-tracker-count.g-tooltip .tooltip-content.right { - margin-top: -20px; - margin-left: 24px; -} -.sub-component.donut-graph.small .g-tooltip .tooltip-content.right { - margin-top: -8px; - margin-left: 15px; -} -.sub-component.donut-graph.big .g-tooltip .tooltip-content.right { - margin-top: 5px; - margin-left: 10px; -} -.expert .sub-component.cliqz-features .g-tooltip .tooltip-content.right { - margin-left: 16px; -} -.expert .sub-component.ghostery-features .g-tooltip .tooltip-content.right { - margin-top: -18px; -} -.expert .sub-component.pause-button .g-tooltip .tooltip-content.right { - margin-top: -12px; - margin-left: 28px; -} -.sub-component.pause-button .g-tooltip .tooltip-content.top { - left: 75px; +.Summary { + .DonutGraph .g-tooltip .tooltip-content.right { + margin-top: 5px; + margin-left: 10px; + } + + .sub-component.pause-button .g-tooltip .tooltip-content.top { + left: 75px; + } } -.expert .g-tooltip .tooltip-content.top { - &.top-right { - margin-left: -40px; - &:after { - left: 40px; - } +.Summary--expert { + .DonutGraph .g-tooltip .tooltip-content.right { + margin-top: -8px; + margin-left: 15px; } - &.top-left { - margin-left: -110px; - &:after { - left: 110px; + + .SummaryPageStat.total-requests-modified.g-tooltip .tooltip-content.right { + margin-top: -43px; + + // Overwrite the expert view Summary__pageStatContainer + // white-space: nowrap value + white-space: normal; + } + + .GhosteryFeatureButton.g-tooltip .tooltip-content.right { + margin-top: -18px; + } + + .sub-component.pause-button .g-tooltip .tooltip-content.right { + margin-top: -12px; + margin-left: 28px; + } + + .CliqzFeature .g-tooltip .tooltip-content.top { + &.top-right { + margin-left: -40px; + &:after { + left: 40px; + } } + &.top-left { + margin-left: -110px; + &:after { + left: 110px; + } + } + } +} + +.Summary--condensed { + .Summary__totalTrackerCount.g-tooltip .tooltip-content.right { + margin-top: -20px; + margin-left: 24px; + } + + .SummaryPageStat.total-requests-modified.g-tooltip .tooltip-content.right { + margin-top: -42px; + margin-left: 31px; + } + + .sub-component.pause-button .g-tooltip .tooltip-content.right { + margin-top: -12px; + margin-left: 28px; + } + + .GhosteryFeatureButton.g-tooltip .tooltip-content.right { + margin-top: -18px; + } + + .CliqzFeature .g-tooltip .tooltip-content.right { + margin-left: 16px; } } diff --git a/app/scss/partials/_upgrade_banner.scss b/app/scss/partials/_upgrade_banner.scss new file mode 100644 index 000000000..4fe139ad9 --- /dev/null +++ b/app/scss/partials/_upgrade_banner.scss @@ -0,0 +1,58 @@ +/** + * Upgrade Banner Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +.UpgradeBanner { + @extend %pointer; + background: url("../../app/images/panel/green-upgrade-banner.svg"); + background-size: contain; +} + +.UpgradeBanner--normal { + height: 23px; + + .UpgradeBanner__text { + font-size: 12px; + vertical-align: sub; + padding: 0 4px 0 10px; + } + + .UpgradeBanner__plus { + vertical-align: sub; + } +} + +.UpgradeBanner--small { + height: 20px; + + .UpgradeBanner__text { + font-size: 10px; + vertical-align: baseline; + padding: 0 4px 0 8px; + } + + .UpgradeBanner__plus { + vertical-align: middle; + } +} + +.UpgradeBanner__text { + display: inline-block; + font-family: "Open Sans", "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; + font-weight: bold; + color: white; +} + +.UpgradeBanner__plus { + display: inline-block; + padding-right: 18px; +} diff --git a/app/scss/shared_helper_classes.scss b/app/scss/shared_helper_classes.scss new file mode 100644 index 000000000..393b71ee0 --- /dev/null +++ b/app/scss/shared_helper_classes.scss @@ -0,0 +1,20 @@ +/** + * Shared Helper Classes Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2019 Ghostery, Inc. All rights reserved. + * + * 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 + */ + +.clickable { cursor: pointer; } +.display-inline-block { display: inline-block; } +.full-height { height: 100%; } +.full-width { width: 100%; } +.invisible { visibility: hidden; } +.not-clickable { cursor: not-allowed; } + diff --git a/src/classes/Globals.js b/src/classes/Globals.js index a59967ea2..023d7069c 100644 --- a/src/classes/Globals.js +++ b/src/classes/Globals.js @@ -66,6 +66,10 @@ class Globals { this.GHOSTERY_TAB_FIREFOX_PRODUCTION_ID = 'firefoxtab@ghostery.com'; this.GHOSTERY_TAB_FIREFOX_TEST_ID = '{0ea88bc4-03bd-4baa-8153-acc861589c1c}'; + // Site Policy named constants + this.BLACKLISTED = 1; + this.WHITELISTED = 2; + // data stores this.REDIRECT_MAP = new Map(); this.BLOCKED_REDIRECT_DATA = {}; diff --git a/src/classes/Policy.js b/src/classes/Policy.js index 0989243bc..0ea28e797 100644 --- a/src/classes/Policy.js +++ b/src/classes/Policy.js @@ -47,10 +47,10 @@ class Policy { */ getSitePolicy(url) { if (this.blacklisted(url)) { - return 1; + return globals.BLACKLISTED; } if (this.whitelisted(url)) { - return 2; + return globals.WHITELISTED; } return false; }