style(connection status): replace icons

Replace previous icon with a flexible version to fit inside other
nodes (e.g: buttons).
This commit is contained in:
Pedro Beschorner Marin 2021-04-22 22:07:48 -03:00
parent 3c0c4f0b42
commit 3672a909f1
7 changed files with 160 additions and 74 deletions

View File

@ -1,9 +1,11 @@
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import { withModalMounter } from '/imports/ui/components/modal/service';
import { defineMessages, injectIntl } from 'react-intl';
import Button from '/imports/ui/components/button/component';
import ConnectionStatusModalContainer from '/imports/ui/components/connection-status/modal/container';
import ConnectionStatusService from '/imports/ui/components/connection-status/service';
import Icon from '/imports/ui/components/connection-status/icon/component';
import { styles } from './styles';
const intlMessages = defineMessages({
label: {
@ -16,74 +18,81 @@ const intlMessages = defineMessages({
},
});
class ConnectionStatusButton extends Component {
shouldComponentUpdate(nextProps) {
const {
connected,
stats,
} = this.props;
const {
connected: nextConnected,
stats: nextStats,
} = nextProps;
// Always re-render when the connection state change
if (connected !== nextConnected) return true;
// Avoid simple re-render case
if (stats === nextStats) return false;
// Avoid updating when component drifts between danger and critical
// since it's the same feedback
if (stats === 'danger' && nextStats === 'critical') return false;
if (stats === 'critical' && nextStats === 'danger') return false;
return true;
class ConnectionStatusButton extends PureComponent {
renderIcon(level = 'normal') {
return(
<div className={styles.iconWrapper}>
<Icon
level={level}
grayscale
/>
</div>
);
}
render() {
const {
intl,
connected,
} = this.props;
if (!connected) {
return (
<div className={styles.buttonWrapper}>
<Button
customIcon={this.renderIcon()}
label={intl.formatMessage(intlMessages.label)}
hideLabel
aria-label={intl.formatMessage(intlMessages.description)}
size="sm"
disabled
ghost
circle
onClick={() => {}}
data-test="connectionStatusButton"
/>
</div>
);
}
const {
stats,
mountModal,
} = this.props;
let color;
if (!connected) {
color = 'offline';
} else {
switch (stats) {
case 'warning':
case 'danger':
// We map warning and danger stats into the warning palette color and
// the error notification
color = 'warning';
ConnectionStatusService.notification('warning', intl);
break;
case 'critical':
color = 'danger';
ConnectionStatusService.notification('error', intl);
break;
default:
color = 'success';
}
switch (stats) {
case 'warning':
color = 'success';
break;
case 'danger':
color = 'warning';
ConnectionStatusService.notification('warning', intl);
break;
case 'critical':
color = 'danger';
ConnectionStatusService.notification('error', intl);
break;
default:
color = 'success';
}
const level = stats ? stats : 'normal';
return (
<Button
icon="network"
label={intl.formatMessage(intlMessages.label)}
hideLabel
aria-label={intl.formatMessage(intlMessages.description)}
size="sm"
color={color}
disabled={!connected}
circle
onClick={() => mountModal(<ConnectionStatusModalContainer />)}
data-test="connectionStatusButton"
/>
<div className={styles.buttonWrapper}>
<Button
customIcon={this.renderIcon(level)}
label={intl.formatMessage(intlMessages.label)}
hideLabel
aria-label={intl.formatMessage(intlMessages.description)}
size="sm"
color={color}
circle
onClick={() => mountModal(<ConnectionStatusModalContainer />)}
data-test="connectionStatusButton"
/>
</div>
);
}
}

View File

@ -1,17 +1,8 @@
.btn {
margin: 0;
span {
border: none;
box-shadow: none;
}
&:hover,
&:focus {
span {
background-color: transparent !important;
color: var(--color-white) !important;
opacity: .75;
}
}
.buttonWrapper {
margin: 0 .5rem;
}
.iconWrapper {
width: 1.025rem;
height: 1.025rem;
}

View File

@ -0,0 +1,39 @@
import React, { Fragment } from 'react';
import cx from 'classnames';
import { styles } from './styles';
const STATS = {
critical: {
color: styles.critical,
bars: styles.oneBar,
},
danger: {
color: styles.danger,
bars: styles.twoBars,
},
warning: {
color: styles.warning,
bars: styles.threeBars,
},
normal: {
color: styles.normal,
bars: styles.fourBars,
},
};
const Icon = ({ level, grayscale }) => {
const color = grayscale ? styles.normal : STATS[level].color;
return (
<Fragment>
<div className={cx(styles.signalBars, color, STATS[level].bars)}>
<div className={cx(styles.firstBar, styles.bar)} />
<div className={cx(styles.secondBar, styles.bar)} />
<div className={cx(styles.thirdBar, styles.bar)} />
<div className={cx(styles.fourthBar, styles.bar)} />
</div>
</Fragment>
);
};
export default Icon;

View File

@ -0,0 +1,40 @@
.signalBars {
align-items: flex-end;
display: flex;
justify-content: space-between;
width: 100%;
height: 100%;
}
.signalBars .bar {
width: 20%;
}
.signalBars .bar.firstBar { height: 25%; }
.signalBars .bar.secondBar { height: 50%; }
.signalBars .bar.thirdBar { height: 75%; }
.signalBars .bar.fourthBar { height: 100%; }
.critical .bar {
background-color: var(--color-danger);
}
.danger .bar {
background-color: var(--color-warning);
}
.warning .bar {
background-color: var(--color-success);
}
.normal .bar {
background-color: var(--color-white);
}
.fourBars .bar.fifthBar,
.threeBars .bar.fifthBar,
.threeBars .bar.fourthBar,
.oneBar .bar:not(.firstBar),
.twoBars .bar:not(.firstBar):not(.secondBar) {
opacity: .5;
}

View File

@ -3,7 +3,7 @@ import { FormattedTime, defineMessages, injectIntl } from 'react-intl';
import PropTypes from 'prop-types';
import cx from 'classnames';
import UserAvatar from '/imports/ui/components/user-avatar/component';
import SlowConnection from '/imports/ui/components/slow-connection/component';
import Icon from '/imports/ui/components/connection-status/icon/component';
import Switch from '/imports/ui/components/switch/component';
import Service from '../service';
import Modal from '/imports/ui/components/modal/simple/component';
@ -145,7 +145,9 @@ class ConnectionStatusComponent extends PureComponent {
</div>
</div>
<div className={styles.status}>
<SlowConnection effectiveConnectionType={conn.level} />
<div className={styles.icon}>
<Icon level={conn.level} />
</div>
</div>
</div>
<div className={styles.right}>

View File

@ -121,6 +121,11 @@
height: 100%;
justify-content: center;
align-items: center;
.icon {
width: 2.05rem;
height: 2.05rem;
}
}
}

View File

@ -319,7 +319,7 @@ const notification = (level, intl) => {
Session.set('connectionStatusNotified', true);
if (intl) notify(intl.formatMessage(intlMessages.notification), level, 'network');
if (intl) notify(intl.formatMessage(intlMessages.notification), level, 'warning');
};
export default {