Create app namespace for all absolute requires of app modules. Move all packages under packages yarn workspace

This commit is contained in:
SleepWalker
2019-12-07 21:02:00 +02:00
parent d8d2df0702
commit f9d3bb4e20
404 changed files with 758 additions and 742 deletions

View File

@@ -0,0 +1,3 @@
{
"logout": "Logout"
}

View File

@@ -0,0 +1,127 @@
import React from 'react';
import classNames from 'classnames';
import { AccountSwitcher } from 'app/components/accounts';
import styles from './loggedInPanel.scss';
export default class LoggedInPanel extends React.Component<
{
username: string;
},
{
isAccountSwitcherActive: boolean;
}
> {
state = {
isAccountSwitcherActive: false,
};
_isMounted: boolean = false;
el: HTMLElement | null;
componentDidMount() {
if (window.document) {
window.document.addEventListener('click', this.onBodyClick);
}
this._isMounted = true;
}
componentWillUnmount() {
if (window.document) {
window.document.removeEventListener('click', this.onBodyClick);
}
this._isMounted = false;
}
render() {
const { username } = this.props;
const { isAccountSwitcherActive } = this.state;
return (
<div
ref={el => (this.el = el)}
className={classNames(styles.loggedInPanel)}
>
<div
className={classNames(styles.activeAccount, {
[styles.activeAccountExpanded]: isAccountSwitcherActive,
})}
>
<button
className={styles.activeAccountButton}
onClick={this.onExpandAccountSwitcher}
>
<span className={styles.userIcon} />
<span className={styles.userName}>{username}</span>
<span className={styles.expandIcon} />
</button>
<div className={classNames(styles.accountSwitcherContainer)}>
<AccountSwitcher
skin="light"
onAfterAction={this.onToggleAccountSwitcher}
/>
</div>
</div>
</div>
);
}
toggleAccountSwitcher = () =>
this._isMounted &&
this.setState({
isAccountSwitcherActive: !this.state.isAccountSwitcherActive,
});
onToggleAccountSwitcher = () => {
this.toggleAccountSwitcher();
};
onExpandAccountSwitcher = (event: React.MouseEvent<HTMLButtonElement>) => {
event.preventDefault();
this.toggleAccountSwitcher();
};
onBodyClick = createOnOutsideComponentClickHandler(
() => this.el,
() => this.state.isAccountSwitcherActive && this._isMounted,
() => 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
*
* @returns {Function}
*/
function createOnOutsideComponentClickHandler(
getEl: () => HTMLElement | null,
isActive: () => boolean,
callback: () => void,
) {
// 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: { target: HTMLElement } & MouseEvent) => {
const el = getEl();
if (isActive() && el) {
if (!el.contains(event.target) && el !== event.target) {
event.preventDefault();
// add a small delay for the case someone have alredy called toggle
setTimeout(() => isActive() && callback(), 0);
}
}
};
}

View File

@@ -0,0 +1,4 @@
{
"register": "Join",
"login": "Sign in"
}

View File

@@ -0,0 +1,50 @@
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { FormattedMessage as Message } from 'react-intl';
import { Account } from 'app/components/accounts/reducer';
import buttons from 'app/components/ui/buttons.scss';
import messages from './Userbar.intl.json';
import styles from './userbar.scss';
import LoggedInPanel from './LoggedInPanel';
export default class Userbar extends Component<{
account: Account | null;
guestAction: 'register' | 'login';
}> {
static displayName = 'Userbar';
static defaultProps = {
guestAction: 'register',
};
render() {
const { account, guestAction: actionType } = this.props;
let guestAction: React.ReactElement;
switch (actionType) {
case 'login':
guestAction = (
<Link to="/login" className={buttons.blue}>
<Message {...messages.login} />
</Link>
);
break;
case 'register':
default:
guestAction = (
<Link to="/register" className={buttons.blue}>
<Message {...messages.register} />
</Link>
);
break;
}
return (
<div className={styles.userbar}>
{account ? <LoggedInPanel username={account.username} /> : guestAction}
</div>
);
}
}

View File

@@ -0,0 +1,61 @@
@import '~app/components/ui/colors.scss';
.loggedInPanel {
}
.activeAccount {
position: relative;
display: inline-block;
$border: 1px solid rgba(#fff, 0.15);
border-left: $border;
border-right: $border;
}
.activeAccountButton {
composes: green from '~app/components/ui/buttons.scss';
}
.activeAccountExpanded {
.activeAccountButton {
background-color: darker($green);
}
.accountSwitcherContainer {
display: block;
}
.expandIcon {
transform: rotate(-180deg);
}
}
.userIcon {
composes: user from '~app/components/ui/icons.scss';
position: relative;
bottom: 2px;
padding-right: 5px;
}
.expandIcon {
composes: caret from '~app/components/ui/icons.scss';
margin-left: 4px;
font-size: 6px;
color: #ccc;
transition: 0.2s;
}
.userName {
}
.accountSwitcherContainer {
position: absolute;
top: 100%;
right: -2px;
cursor: auto;
display: none;
}

View File

@@ -0,0 +1,3 @@
.userbar {
text-align: right;
}