Unify Spinner / Refresh Styles (#1032)

* Unify spinner styles, enforce more SuitCSS style names

* Unify spinner styles, enforce more SuitCSS style names

* Hide refresh offline, adjust colors correctly.
This commit is contained in:
William O'Beirne 2018-02-08 18:44:30 -05:00 committed by Daniel Ternyak
parent 42afff3ef2
commit eaa9ac392c
13 changed files with 112 additions and 86 deletions

View File

@ -1,5 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 36 36">
<g class="nc-icon-wrapper" fill="#000000">
<path d="M26.47 9.53C24.3 7.35 21.32 6 18 6 11.37 6 6 11.37 6 18s5.37 12 12 12c5.94 0 10.85-4.33 11.81-10h-3.04c-.91 4.01-4.49 7-8.77 7-4.97 0-9-4.03-9-9s4.03-9 9-9c2.49 0 4.71 1.03 6.34 2.66L20 16h10V6l-3.53 3.53z"></path>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 378 B

View File

@ -17,7 +17,6 @@
&-refresh {
background: transparent;
border: none;
margin: 0px 0.5rem;
padding: 0;
height: 1.4rem;
width: 1.2rem;
@ -77,9 +76,14 @@
}
}
&-balance-wrapper {
&-balance {
display: flex;
align-items: flex-end;
justify-content: flex-start;
align-items: center;
&-amount {
margin-right: $space-sm;
}
}
&-list {

View File

@ -5,10 +5,9 @@ import React from 'react';
import translate from 'translations';
import './AccountInfo.scss';
import Spinner from 'components/ui/Spinner';
import { getNetworkConfig } from 'selectors/config';
import { getNetworkConfig, getOffline } from 'selectors/config';
import { AppState } from 'reducers';
import { connect } from 'react-redux';
import refreshIcon from 'assets/images/refresh.svg';
import { TSetAccountBalance, setAccountBalance } from 'actions/wallet';
interface OwnProps {
@ -18,6 +17,7 @@ interface OwnProps {
interface StateProps {
balance: Balance;
network: NetworkConfig;
isOffline: boolean;
}
interface State {
@ -70,7 +70,7 @@ class AccountInfo extends React.Component<Props, State> {
};
public render() {
const { network, balance } = this.props;
const { network, balance, isOffline } = this.props;
const { address, showLongBalance, confirmAddr } = this.state;
const { blockExplorer, tokenExplorer } = network;
const wallet = this.props.wallet as LedgerWallet | TrezorWallet;
@ -114,30 +114,30 @@ class AccountInfo extends React.Component<Props, State> {
<div className="AccountInfo-section">
<h5 className="AccountInfo-section-header">{translate('sidebar_AccountBal')}</h5>
<ul className="AccountInfo-list">
<li className="AccountInfo-list-item AccountInfo-balance-wrapper">
<li className="AccountInfo-list-item AccountInfo-balance">
<span
className="AccountInfo-list-item-clickable AccountInfo-balance-amount mono wrap"
onClick={this.toggleShowLongBalance}
>
<UnitDisplay
value={balance.wei}
unit={'ether'}
displayShortBalance={!showLongBalance}
checkOffline={true}
symbol={balance.wei ? network.name : null}
/>
</span>
{balance.isPending ? (
<Spinner />
) : (
<React.Fragment>
<span
className="AccountInfo-list-item-clickable mono wrap"
onClick={this.toggleShowLongBalance}
>
<UnitDisplay
value={balance.wei}
unit={'ether'}
displayShortBalance={!showLongBalance}
checkOffline={true}
symbol={balance.wei ? network.name : null}
/>
</span>
!isOffline && (
<button
className="AccountInfo-section-refresh"
onClick={this.props.setAccountBalance}
>
<img src={refreshIcon} />
<i className="fa fa-refresh" />
</button>
</React.Fragment>
)
)}
</li>
</ul>
@ -179,7 +179,8 @@ class AccountInfo extends React.Component<Props, State> {
function mapStateToProps(state: AppState): StateProps {
return {
balance: state.wallet.balance,
network: getNetworkConfig(state)
network: getNetworkConfig(state),
isOffline: getOffline(state)
};
}
const mapDispatchToProps: DispatchProps = { setAccountBalance };

View File

@ -12,9 +12,9 @@
}
}
.Spinner {
display: block;
margin: auto;
&-spinner {
text-align: center;
padding: 1.6rem;
}
&-title {

View File

@ -158,7 +158,9 @@ class EquivalentValues extends React.Component<Props, State> {
) : ratesError ? (
<h5>{ratesError}</h5>
) : isFetching ? (
<Spinner size="x2" />
<div className="EquivalentValues-spinner">
<Spinner size="x3" />
</div>
) : (
<div className="EquivalentValues-values">
{pairRates.length ? (

View File

@ -1,27 +1,24 @@
@import 'common/sass/variables';
@import 'common/sass/mixins';
.nonce {
&-label-wrapper {
.Nonce {
&-label {
align-items: center;
margin-bottom: $space-xs;
> label {
&-text {
margin-bottom: 0;
}
}
&-input-wrapper {
&-field {
position: relative;
}
&-refresh {
position: absolute;
right: 0;
top: 0;
border: none;
background: transparent;
padding: 0;
margin: 0 1rem;
height: 2.55rem;
@include reset-button;
height: $input-height-base;
opacity: 0.3;
transition: opacity 300ms;
> img {
height: 1.4rem;
}
@ -33,4 +30,17 @@
opacity: 1;
}
}
&-spinner {
height: 1rem;
}
&-spinner,
&-refresh {
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%) translateZ(0);
margin: 0 1rem;
}
}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { NonceFieldFactory } from 'components/NonceFieldFactory';
import Help from 'components/ui/Help';
import RefreshIcon from 'assets/images/refresh.svg';
import './NonceField.scss';
import { InlineSpinner } from 'components/ui/InlineSpinner';
import { Spinner } from 'components/ui';
import { connect } from 'react-redux';
import { getNonceRequested, TGetNonceRequested } from 'actions/transaction';
import { nonceRequestPending } from 'selectors/transaction';
import { getOffline } from 'selectors/config';
import { AppState } from 'reducers';
interface OwnProps {
@ -14,7 +14,8 @@ interface OwnProps {
}
interface StateProps {
nonePending: boolean;
isOffline: boolean;
noncePending: boolean;
}
interface DispatchProps {
@ -25,35 +26,44 @@ type Props = OwnProps & DispatchProps & StateProps;
class NonceField extends React.Component<Props> {
public render() {
const { alwaysDisplay, requestNonce, nonePending } = this.props;
const { alwaysDisplay, requestNonce, noncePending, isOffline } = this.props;
return (
<NonceFieldFactory
withProps={({ nonce: { raw, value }, onChange, readOnly, shouldDisplay }) => {
return alwaysDisplay || shouldDisplay ? (
<React.Fragment>
<div className="nonce-label-wrapper flex-wrapper">
<label className="nonce-label">Nonce</label>
<div className="Nonce-label flex-wrapper">
<label className="Nonce-label-text">Nonce</label>
<Help
size={'x1'}
link={
'https://myetherwallet.github.io/knowledge-base/transactions/what-is-nonce.html'
}
/>
<div className="flex-spacer" />
<InlineSpinner active={nonePending} text="Calculating" />
</div>
<div className="nonce-input-wrapper">
<div className="Nonce-field">
<input
className={`form-control nonce-input ${!!value ? 'is-valid' : 'is-invalid'}`}
className={`Nonce-field-input form-control ${
!!value ? 'is-valid' : 'is-invalid'
}`}
type="number"
placeholder="e.g. 7"
value={raw}
readOnly={readOnly}
onChange={onChange}
disabled={noncePending}
/>
<button className="nonce-refresh" onClick={requestNonce}>
<img src={RefreshIcon} alt="refresh" />
</button>
{noncePending ? (
<div className="Nonce-spinner">
<Spinner />
</div>
) : (
!isOffline && (
<button className="Nonce-refresh" onClick={requestNonce}>
<i className="fa fa-refresh" />
</button>
)
)}
</div>
</React.Fragment>
) : null;
@ -63,9 +73,10 @@ class NonceField extends React.Component<Props> {
}
}
const mapStateToProps = (state: AppState) => {
const mapStateToProps = (state: AppState): StateProps => {
return {
nonePending: nonceRequestPending(state)
isOffline: getOffline(state),
noncePending: nonceRequestPending(state)
};
};

View File

@ -8,19 +8,3 @@
left: -8px;
}
}
.Calculating-limit {
color: rgba(51, 51, 51, 0.7);
display: flex;
align-items: center;
font-weight: 400;
opacity: 0;
pointer-events: none;
&.active {
opacity: 1;
}
.Spinner {
margin-left: 8px;
}
}

View File

@ -1,8 +1,21 @@
.inline-spinner {
@import 'common/sass/variables';
.InlineSpinner {
color: $gray-light;
display: flex;
align-items: center;
font-weight: 400;
opacity: 0;
pointer-events: none;
.Spinner {
margin-left: 8px;
}
&--fade {
&-enter,
&-exit {
transition: opacity 300ms;
transition: opacity $transition-speed;
}
&-enter {

View File

@ -3,13 +3,15 @@ import { CSSTransition } from 'react-transition-group';
import { Spinner } from 'components/ui';
import './InlineSpinner.scss';
export const InlineSpinner: React.SFC<{
interface Props {
active: boolean;
text?: string;
}> = ({ active, text }) => (
<CSSTransition in={active} timeout={300} classNames="inline-spinner--fade">
}
export const InlineSpinner: React.SFC<Props> = ({ active, text }) => (
<CSSTransition in={active} timeout={300} classNames="InlineSpinner--fade">
{/* TODO: when react-transition-group v2.3 releases, use '-done' classes instead of conditional 'active' class https://github.com/reactjs/react-transition-group/issues/274 */}
<div className={`Calculating-limit small ${active ? 'active' : ''}`}>
<div className="InlineSpinner small">
{text}
<Spinner />
</div>

View File

@ -1,3 +1,5 @@
@import 'common/sass/variables';
.Spinner {
animation: rotate 2s linear infinite;
@ -39,7 +41,7 @@
&-dark {
& .path {
stroke: #163151;
stroke: $ether-navy;
}
}
}

View File

@ -14,3 +14,4 @@ export { default as TitleBar } from './TitleBar';
export { default as HelpLink } from './HelpLink';
export * from './ConditionalInput';
export * from './Expandable';
export * from './InlineSpinner';

View File

@ -1,4 +1,5 @@
$transition: 120ms opacity ease,
120ms color ease,
120ms background-color ease,
120ms border-color ease;
$transition-speed: 120ms;
$transition: $transition-speed opacity ease,
$transition-speed color ease,
$transition-speed background-color ease,
$transition-speed border-color ease;