Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-1975 Theme Framework & GH-1972 Palm Theme #517

Closed
wants to merge 22 commits into from
Closed
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter
Filter file types
Jump to
Jump to file
Failed to load files.

Always

Just for now

Next
Replace themes toggle with radio buttons
  • Loading branch information
benstrumeyer committed Mar 11, 2020
commit 317ab64e96641f6c44f6eb85fd3c16e1a86d6b0a
@@ -1822,8 +1822,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"
@@ -0,0 +1,6 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(1)" fill="none" fill-rule="evenodd">
<circle stroke="#2092bf" cx="7" cy="8" r="7"/>
<path d="M5.86 4.756c0-.582.326-.873.974-.873.648 0 .973.29.973.873 0 .277-.08.493-.244.647-.162.155-.405.232-.73.232-.647 0-.972-.293-.972-.88zM7.726 13H5.938V6.45h1.787V13z" fill="#2092bf"/>
</g>
</svg>
@@ -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 */

This comment has been minimized.

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

Definitely will try to resolve those before resorting to eslint, I think I mistakenly put that here since there are no labels


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) => {

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

Destructure to clean up a lil
const { checked, handleClick } = props;, etc

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

Destructured!

const OuterCircleClassNames = ClassNames('RadioButton__outerCircle', {
checked: props.checked,
});
const InnerCircleClassNames = ClassNames('RadioButton__innerCircle', {
checked: props.checked,
});
return (
<span>
<span className={OuterCircleClassNames} onClick={props.handleClick}>
<span className={InnerCircleClassNames} />
</span>
</span>
);
};

// PropTypes ensure we pass required props of the correct type
RadioButton.propTypes = {
handleClick: PropTypes.func.isRequired,

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

add checked

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

Added checked!

};

export default RadioButton;
@@ -0,0 +1,74 @@
/**
* 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
*/
class RadioButtonGroup extends React.Component {
constructor(props) {
super(props);
this.state = {
buttons: []

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

buttons suggests that the items are button objects/components. Use a name that better reflects the nature of the (on/off bool) elements.

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

Changed to buttonState! Actually, removed altogether per Ethan's comment:

It looks like this is the only place that you're using the local state in this component. You can instead just pass the props to the <RadioButton /> component like this:

const { indexClicked, handleItemClick } = this.props
// ...code in between...
	<RadioButton
		checked={index === indexClicked}
		handleClick={() => handleItemClick(index)}
	/>

Then, you can remove all of the code from componentDidMount and RadioButtonGroup.handleClick and not have to worry about local state.

};
}

componentDidMount() {
const buttons = new Array(this.props.items.length).fill(false);
buttons[this.props.selectedIndex] = true;
this.setState({ buttons });
}

handleClick(indexClicked) {
const { buttons } = this.state;
const updatedButtons = buttons.map((button, index) => (index === indexClicked));
this.setState({ buttons: updatedButtons });
this.props.handleItemClick(indexClicked);
}

/**
* React's required render function. Returns JSX
* @return {JSX} JSX for rendering the Toggle Slider used throughout the extension
*/
render() {
const { buttons } = this.state;
return (
this.props.items.map((item, index) => (
<div className="flex-container align-middle align-justify RadioButtonGroup__container">
<span className="RadioButtonGroup__label">
{t(item.text)}
</span>
<div>
<RadioButton key={buttons[index]} checked={buttons[index]} handleClick={() => this.handleClick(index)} />
</div>
</div>
))
);
}
}

// 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

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

Since we only use the text property of these objects for the individual button labels, let's pass in the labels only, as an array of strings. Not only do we avoid passing unused data that way but we also make the component more flexible, since it will no longer be expeting an object prop with a Themes-view-specific shape.

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

So reusable. Passed in labels for flexibility

handleItemClick: PropTypes.func.isRequired,
selectedIndex: PropTypes.number.isRequired
};


export default RadioButtonGroup;
@@ -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
};
@@ -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,18 +77,16 @@ 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');
});
}

SubscriptionInfoComponent = () => (<SubscriptionInfo subscriptionData={this.parseSubscriptionData()} />);

SubscriptionThemesComponent = () => (<SubscriptionThemes isChecked={this.state.isChecked} toggleThemes={this.toggleThemes} />);
SubscriptionThemesComponent = () => (<SubscriptionThemes theme={this.state.theme} changeTheme={this.changeTheme} />);

PrioritySupportComponent = () => (<PrioritySupport />);

@@ -74,7 +74,7 @@ const SubscriptionInfo = (props) => {
</div>
<div className="list-row">
<ul>
<li className="list-item">{t('subscription_midnight_theme')}</li>
<li className="list-item">{t('subscription_dark_blue_theme')}</li>
<li className="list-item">{t('historical_stats')}</li>
<li className="list-item">{t('priority_support')}</li>
</ul>
@@ -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 => (
<div className="content-subscription s-tabs-panel">
<div className="row">
<div className="columns column-subscription">
<h1>{ t('subscription_themes_title') }</h1>
<div>
<span className="flex-container align-middle themes-slider-container">
<span className="themes-slider-label">
{t('subscription_midnight_theme')}
</span>
<ToggleSlider
className="themes-slider"
isChecked={props.isChecked}
onChange={props.toggleThemes}
/>
<div className="s-tooltip-down" data-g-tooltip={t('subscription_themes_tooltip')}>
<img src="../../app/images/panel/icon-information-tooltip.svg" className="s-question" />
</div>
*/
const SubscriptionThemes = (props) => {
const themes = [
{
name: 'default',
text: 'subscription_default_theme',
},
{
name: 'midnight-theme',

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

Update to dark-blue-theme here too

This comment has been minimized.

@wlycdgr

wlycdgr Mar 27, 2020
Member

And let's be consistent with the naming -default-theme, palm-theme, leaf-theme, etc

This comment has been minimized.

@benstrumeyer

benstrumeyer Mar 31, 2020
Author Contributor

Ah I wanted to do that. It's my understanding that these theme names rely on the account project for API calls and we don't want to update these for now, however we have a ticket in the backlog for it https://cliqztix.atlassian.net/browse/GH-1974

text: 'subscription_dark_blue_theme',
},
{
name: 'palm',
text: 'subscription_palm_theme',
},
{
name: 'leaf',
text: 'subscription_leaf_theme',
}
];

const getSelectedIndex = () => {
const index = themes.findIndex(theme => theme.name === props.theme);
return index;
};

const handleThemeClick = (index) => {
const theme = themes[index];
props.changeTheme(theme.name);
};

return (
<div className="content-subscription s-tabs-panel">
<div className="row">
<div className="columns column-subscription">
<h1 className="subscription-title">{t('subscription_themes_title')}</h1>
<span className="tooltip-icon s-tooltip-down-right" data-g-tooltip={t('subscription_themes_tooltip')}>
<img src="../../app/images/panel/icon-information-tooltip-blue.svg" className="s-question" />
</span>
<RadioButtonGroup
items={themes}
handleItemClick={handleThemeClick}
selectedIndex={getSelectedIndex(props.theme)}
/>
</div>
</div>
</div>
</div>
);
);
};

// PropTypes ensure we pass required props of the correct type
SubscriptionThemes.propTypes = {
changeTheme: PropTypes.func.isRequired,
theme: PropTypes.string.isRequired,
};

export default SubscriptionThemes;
@@ -8,7 +8,6 @@
* 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
@@ -65,6 +64,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';
@@ -0,0 +1,43 @@
/**
* 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 !important;
font-weight: bolder;
}
.RadioButtonGroup__container {
margin: 16px 0;
width: 138px;
}
.RadioButton__innerCircle {
&.checked {
height: 8px;
width: 8px;
background-color: #2092bf;
border-radius: 50%;
border: 1px solid #2092bf;
}
}
.RadioButton__outerCircle {
position: relative;
border: 1px solid #4a4a4a;
height: 14px;
width: 14px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
&.checked {
border: 2px solid #2092bf;
}
}
ProTip! Use n and p to navigate between commits in a pull request.