diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index 05499c4d1..8a02576ff 100644
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -1817,8 +1817,17 @@
"subscribe_pitch_sign_in": {
"message": "Already subscribed? Sign in"
},
- "subscription_midnight_theme": {
- "message": "Midnight Theme"
+ "subscription_default_theme": {
+ "message": "Default"
+ },
+ "subscription_dark_blue_theme": {
+ "message": "Dark Blue Theme"
+ },
+ "subscription_palm_theme": {
+ "message": "Palm Theme"
+ },
+ "subscription_leaf_theme": {
+ "message": "Leaf Theme"
},
"subscription_status": {
"message": "Status"
diff --git a/app/images/panel/icon-information-tooltip-blue.svg b/app/images/panel/icon-information-tooltip-blue.svg
new file mode 100644
index 000000000..2b277cf22
--- /dev/null
+++ b/app/images/panel/icon-information-tooltip-blue.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/app/panel/components/BuildingBlocks/RadioButton.jsx b/app/panel/components/BuildingBlocks/RadioButton.jsx
new file mode 100644
index 000000000..d8205a983
--- /dev/null
+++ b/app/panel/components/BuildingBlocks/RadioButton.jsx
@@ -0,0 +1,46 @@
+/**
+ * Radio Button 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
+ */
+
+/* eslint jsx-a11y/label-has-associated-control: 0 */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import ClassNames from 'classnames';
+
+/**
+ * @class Implements a single radio button to be used inside the RadioButtonGroup component
+ * @memberof PanelBuildingBlocks
+ */
+
+const RadioButton = (props) => {
+ const OuterCircleClassNames = ClassNames('RadioButton__outerCircle', {
+ checked: props.checked,
+ });
+ const InnerCircleClassNames = ClassNames('RadioButton__innerCircle', {
+ checked: props.checked,
+ });
+ return (
+
+
+
+
+
+ );
+};
+
+// PropTypes ensure we pass required props of the correct type
+RadioButton.propTypes = {
+ handleClick: PropTypes.func.isRequired,
+};
+
+export default RadioButton;
diff --git a/app/panel/components/BuildingBlocks/RadioButtonGroup.jsx b/app/panel/components/BuildingBlocks/RadioButtonGroup.jsx
new file mode 100644
index 000000000..883fa60a1
--- /dev/null
+++ b/app/panel/components/BuildingBlocks/RadioButtonGroup.jsx
@@ -0,0 +1,51 @@
+/**
+ * Radio Button Group 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
+ */
+
+/* eslint jsx-a11y/label-has-associated-control: 0 */
+
+import React from 'react';
+import PropTypes from 'prop-types';
+import RadioButton from './RadioButton';
+
+/**
+ * @class Implements a radio button group
+ * @memberof PanelBuildingBlocks
+ */
+const RadioButtonGroup = (props) => {
+ const { indexClicked, handleItemClick } = props;
+ return (
+ props.items.map((item, index) => (
+
+
+ {t(item.text)}
+
+
+ handleItemClick(index)}
+ />
+
+
+ ))
+ );
+};
+
+// PropTypes ensure we pass required props of the correct type
+RadioButtonGroup.propTypes = {
+ items: PropTypes.arrayOf(PropTypes.object).isRequired, // Number of objects in array is the number of radio buttons
+ handleItemClick: PropTypes.func.isRequired,
+ indexClicked: PropTypes.number.isRequired
+};
+
+
+export default RadioButtonGroup;
diff --git a/app/panel/components/BuildingBlocks/index.js b/app/panel/components/BuildingBlocks/index.js
index edc925cbc..8f73d6052 100644
--- a/app/panel/components/BuildingBlocks/index.js
+++ b/app/panel/components/BuildingBlocks/index.js
@@ -21,6 +21,8 @@ import GhosteryFeature from './GhosteryFeature';
import NotScanned from './NotScanned';
import PauseButton from './PauseButton';
import ToggleSlider from './ToggleSlider';
+import RadioButtonGroup from './RadioButtonGroup';
+import RadioButton from './RadioButton';
import ModalExitButton from './ModalExitButton';
export {
@@ -31,5 +33,7 @@ export {
NotScanned,
PauseButton,
ToggleSlider,
+ RadioButtonGroup,
+ RadioButton,
ModalExitButton
};
diff --git a/app/panel/components/Subscription.jsx b/app/panel/components/Subscription.jsx
index 004e5d9ab..d39afad65 100644
--- a/app/panel/components/Subscription.jsx
+++ b/app/panel/components/Subscription.jsx
@@ -28,7 +28,9 @@ import PrioritySupport from './Subscription/PrioritySupport';
class Subscription extends React.Component {
constructor(props) {
super(props);
- this.state = { isChecked: (props.current_theme !== 'default') };
+ this.state = {
+ theme: this.props.current_theme
+ };
}
/**
@@ -75,10 +77,8 @@ class Subscription extends React.Component {
return { loading: true };
}
- toggleThemes = () => {
- const newChecked = !this.state.isChecked;
- this.setState({ isChecked: newChecked });
- const updated_theme = newChecked ? 'midnight-theme' : 'default';
+ changeTheme = (updated_theme) => {
+ this.setState({ theme: updated_theme });
this.props.actions.getTheme(updated_theme).then(() => {
sendMessage('ping', 'theme_change');
});
@@ -86,7 +86,7 @@ class Subscription extends React.Component {
SubscriptionInfoComponent = () => ( );
- SubscriptionThemesComponent = () => ( );
+ SubscriptionThemesComponent = () => ( );
PrioritySupportComponent = () => ( );
diff --git a/app/panel/components/Subscription/SubscriptionInfo.jsx b/app/panel/components/Subscription/SubscriptionInfo.jsx
index 93c1161a4..8d115b17b 100644
--- a/app/panel/components/Subscription/SubscriptionInfo.jsx
+++ b/app/panel/components/Subscription/SubscriptionInfo.jsx
@@ -74,7 +74,7 @@ const SubscriptionInfo = (props) => {
- {t('subscription_midnight_theme')}
+ {t('subscription_dark_blue_theme')}
{t('historical_stats')}
{t('priority_support')}
diff --git a/app/panel/components/Subscription/SubscriptionThemes.jsx b/app/panel/components/Subscription/SubscriptionThemes.jsx
index 3a00f0282..dc1574375 100644
--- a/app/panel/components/Subscription/SubscriptionThemes.jsx
+++ b/app/panel/components/Subscription/SubscriptionThemes.jsx
@@ -12,36 +12,68 @@
*/
import React from 'react';
-import { ToggleSlider } from '../BuildingBlocks';
+import PropTypes from 'prop-types';
+import { RadioButtonGroup } from '../BuildingBlocks';
/**
* @class Implement Themes subview as a React component.
* The view opens from the left-side menu of the main Subscription view.
- * It allows to switch between available Ghostery themes. Right now it handles just one theme. Hence - slider.
+ * It allows to switch between available Ghostery themes.
* @memberOf SettingsComponents
- */
-const SubscriptionThemes = props => (
-
-
-
-
{ t('subscription_themes_title') }
-
-
-
- {t('subscription_midnight_theme')}
-
-
-
-
-
+*/
+const SubscriptionThemes = (props) => {
+ const themes = [
+ {
+ name: 'default',
+ text: 'subscription_default_theme',
+ },
+ {
+ name: 'midnight-theme',
+ text: 'subscription_dark_blue_theme',
+ },
+ {
+ name: 'palm',
+ text: 'subscription_palm_theme',
+ },
+ {
+ name: 'leaf',
+ text: 'subscription_leaf_theme',
+ }
+ ];
+
+ const getIndexClicked = () => {
+ const index = themes.findIndex(theme => theme.name === props.theme);
+ return index;
+ };
+
+ const handleThemeClick = (index) => {
+ const theme = themes[index];
+ props.changeTheme(theme.name);
+ };
+
+ return (
+
+
+
+
{t('subscription_themes_title')}
+
+
+
-
-);
+ );
+};
+
+// PropTypes ensure we pass required props of the correct type
+SubscriptionThemes.propTypes = {
+ changeTheme: PropTypes.func.isRequired,
+ theme: PropTypes.string.isRequired,
+};
+
export default SubscriptionThemes;
diff --git a/app/scss/panel.scss b/app/scss/panel.scss
index eaef66ef7..cb9ea1ca0 100644
--- a/app/scss/panel.scss
+++ b/app/scss/panel.scss
@@ -65,6 +65,7 @@ html body {
@import './partials/_account';
@import './partials/_drawer';
@import './partials/_toggle_slider';
+@import './partials/_radio_button';
@import './partials/_pause_button';
@import './partials/_donut_graph';
@import './partials/_ghostery_feature';
diff --git a/app/scss/partials/_radio_button.scss b/app/scss/partials/_radio_button.scss
new file mode 100644
index 000000000..51ddeb4bb
--- /dev/null
+++ b/app/scss/partials/_radio_button.scss
@@ -0,0 +1,42 @@
+/**
+ * Radio Button 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
+ */
+
+.RadioButtonGroup__label {
+ margin-right: 10px;
+ font-weight: bolder;
+}
+.RadioButtonGroup__container {
+ margin: 16px 0;
+ width: 138px;
+}
+.RadioButton__outerCircle {
+ border: 1px solid #4a4a4a;
+ height: 16px;
+ width: 16px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ box-sizing: border-box;
+ &.checked {
+ border: 2px solid #2092bf;
+ }
+}
+.RadioButton__innerCircle {
+ &.checked {
+ height: 8px;
+ width: 8px;
+ background-color: #2092bf;
+ border-radius: 50%;
+ }
+}
diff --git a/app/scss/partials/_settings.scss b/app/scss/partials/_settings.scss
index dccf04282..96981e5aa 100644
--- a/app/scss/partials/_settings.scss
+++ b/app/scss/partials/_settings.scss
@@ -5,7 +5,7 @@
* 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
@@ -58,7 +58,6 @@
text-align: left;
}
}
-
.s-tab-title {
font-weight: 400;
font-size: 18px;
@@ -195,12 +194,11 @@
line-height: 1.4;
}
img.s-question {
- top: -5px;
- width: 14px;
+ width: 16px;
height: auto;
cursor: default;
- vertical-align: top;
opacity: 1.0;
+ margin: -6px 0 0 10px;
}
.s-option-group {
margin-bottom: 12px;
@@ -279,7 +277,7 @@
border-color: #CCCCCC;
background-size: 8px 5px;
-moz-appearance: none;
- -webkit-appearance:none;
+ -webkit-appearance: none;
}
}
#select-file {
@@ -458,4 +456,4 @@
.blocking-trackers {
margin-left: 25px;
}
-}
\ No newline at end of file
+}
diff --git a/app/scss/partials/_subscribe.scss b/app/scss/partials/_subscribe.scss
index 11e7375e4..c771b102d 100644
--- a/app/scss/partials/_subscribe.scss
+++ b/app/scss/partials/_subscribe.scss
@@ -83,17 +83,16 @@
-webkit-font-smoothing: antialiased;
text-align: left;
}
- .themes-slider-label {
- @extend .field-label;
- padding-right: 20px !important;
- }
- .themes-slider-container {
- padding-top: 10px !important;
- }
.column-subscription {
padding-left: 30px !important;
padding-right: 30px !important;
}
+ .subscription-title {
+ display: inline;
+ }
+ .tooltip-icon {
+ margin-left: 5px !important;
+ }
.status-label {
@extend .field-label;
padding-right: 7px !important;