#48: toggle AccountSwitcher in header by click, instead of hover. Render AccountSwitcher outside of active account button

This commit is contained in:
SleepWalker 2016-11-11 09:39:01 +02:00
parent a2afac867a
commit 81c2b48cd1
4 changed files with 83 additions and 18 deletions

View File

@ -1,6 +1,7 @@
import React, { Component, PropTypes } from 'react'; import React, { Component, PropTypes } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Link } from 'react-router';
import { FormattedMessage as Message } from 'react-intl'; import { FormattedMessage as Message } from 'react-intl';
import { skins, SKIN_DARK, COLOR_WHITE } from 'components/ui'; import { skins, SKIN_DARK, COLOR_WHITE } from 'components/ui';
@ -112,7 +113,7 @@ export default class AccountSwitcher extends Component {
</div> </div>
))} ))}
{allowAdd ? ( {allowAdd ? (
<div> <Link to="/login">
<Button <Button
color={COLOR_WHITE} color={COLOR_WHITE}
block block
@ -129,7 +130,7 @@ export default class AccountSwitcher extends Component {
</Message> </Message>
} }
/> />
</div> </Link>
) : null} ) : null}
</div> </div>
); );

View File

@ -5,7 +5,7 @@
//@import '~components/ui/panel.scss'; //@import '~components/ui/panel.scss';
$bodyLeftRightPadding: 20px; $bodyLeftRightPadding: 20px;
$lightBorderColor: #EEE; $lightBorderColor: #eee;
.accountSwitcher { .accountSwitcher {
text-align: left; text-align: left;
@ -16,12 +16,9 @@ $lightBorderColor: #EEE;
} }
.accountUsername { .accountUsername {
line-height: normal; // button style override
} }
.accountEmail { .accountEmail {
line-height: normal; // button style override
font-family: $font-family-base; // button style override
} }
.lightAccountSwitcher { .lightAccountSwitcher {
@ -68,7 +65,6 @@ $lightBorderColor: #EEE;
.activeAccountUsername { .activeAccountUsername {
font-size: 20px; font-size: 20px;
line-height: normal; // button style override
color: $green; color: $green;
} }
@ -80,8 +76,7 @@ $lightBorderColor: #EEE;
} }
.link { .link {
line-height: normal; // button style override font-size: 12px;
font-size: 12px; // button style override
margin-bottom: 3px; margin-bottom: 3px;
&:last-of-type { &:last-of-type {

View File

@ -1,4 +1,5 @@
import React, { Component } from 'react'; import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classNames from 'classnames'; import classNames from 'classnames';
@ -15,16 +16,32 @@ export default class LoggedInPanel extends Component {
user: userShape user: userShape
}; };
state = {
isAccountSwitcherActive: false
};
componentDidMount() {
document.addEventListener('click', this.onBodyClick);
}
componentWillUnmount() {
document.removeEventListener('click', this.onBodyClick);
}
render() { render() {
const { user } = this.props; const { user } = this.props;
const { isAccountSwitcherActive } = this.state;
return ( return (
<div className={classNames(styles.loggedInPanel)}> <div className={classNames(styles.loggedInPanel)}>
{/* this button must be a div, because some browsers force overflow hidden on button elements */} <div className={classNames(styles.activeAccount, {
<div className={classNames(buttons.green, styles.activeAccount)}> [styles.activeAccountExpanded]: isAccountSwitcherActive
<span className={styles.userIcon} /> })}>
<span className={styles.userName}>{user.username}</span> <button className={buttons.green} onClick={this.onExpandAccountSwitcher}>
<span className={styles.expandIcon} /> <span className={styles.userIcon} />
<span className={styles.userName}>{user.username}</span>
<span className={styles.expandIcon} />
</button>
<div className={classNames(styles.accountSwitcherContainer)}> <div className={classNames(styles.accountSwitcherContainer)}>
<AccountSwitcher skin="light" /> <AccountSwitcher skin="light" />
@ -33,4 +50,51 @@ export default class LoggedInPanel extends Component {
</div> </div>
); );
} }
toggleAccountSwitcher() {
this.setState({
isAccountSwitcherActive: !this.state.isAccountSwitcherActive
});
}
onExpandAccountSwitcher = (event) => {
event.preventDefault();
this.toggleAccountSwitcher();
};
onBodyClick = createOnOutsideComponentClickHandler(
() => ReactDOM.findDOMNode(this),
() => this.state.isAccountSwitcherActive,
() => this.toggleAccountSwitcher()
);
}
/**
* Creates an event handling function to handle clicks outside the component
*
* The handler will check if current click was outside container el and if so
* and component isActive, it will call the callback
*
* @param {function} getEl - the function, that returns reference to container el
* @param {function} isActive - whether the component is active and callback may be called
* @param {function} callback - the callback to call, when there was a click outside el
* @return {function}
*/
function createOnOutsideComponentClickHandler(getEl, isActive, callback) {
// TODO: we have the same logic in LangMenu
// Probably we should decouple this into some helper function
// TODO: the name of function may be better...
return (event) => {
if (isActive()) {
const el = getEl();
if (!el.contains(event.target) && el !== event.taget) {
event.preventDefault();
// add a small delay for the case someone have alredy called toggle
setTimeout(() => isActive() && callback(), 0);
}
}
};
} }

View File

@ -5,15 +5,20 @@
.activeAccount { .activeAccount {
position: relative; position: relative;
display: inline-block;
$border: 1px solid rgba(#fff, .15); $border: 1px solid rgba(#fff, .15);
border-left: $border; border-left: $border;
border-right: $border; border-right: $border;
}
&:hover { .activeAccountExpanded {
.accountSwitcherContainer { .accountSwitcherContainer {
display: block; display: block;
} }
.expandIcon {
transform: rotate(180deg);
} }
} }