DRY Card display (CardBar component, consistency) (#235)
* DRY Card display (CardBar component, consistency) * Use SummaryCard on staking * Simplify summaries (no duplication from explorer) * Display lateness percentage value
This commit is contained in:
parent
090f4d4cc8
commit
4ff1392459
@ -6,7 +6,7 @@ import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import CardBar from '@polkadot/ui-app/CardBar';
|
||||
import CardSummary from '@polkadot/ui-app/CardSummary';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
@ -27,11 +27,11 @@ class Summary extends React.PureComponent<Props> {
|
||||
const { className, democracyLaunchPeriod, democracyNextTally = new BN(0), democracyProposalCount, democracyReferendumCount = new BN(0), democracyVotingPeriod, style, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('democracy--Summary', className)}
|
||||
<CardBar
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<div className='democracy--Summary-column'>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.proposalCount', {
|
||||
defaultValue: 'proposals'
|
||||
})}>
|
||||
@ -51,7 +51,7 @@ class Summary extends React.PureComponent<Props> {
|
||||
}
|
||||
</CardSummary>
|
||||
</div>
|
||||
<div className='democracy--Summary-column'>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.votingPeriod', {
|
||||
defaultValue: 'voting period'
|
||||
})}>
|
||||
@ -63,7 +63,7 @@ class Summary extends React.PureComponent<Props> {
|
||||
{numberFormat(democracyLaunchPeriod)}
|
||||
</CardSummary>
|
||||
</div>
|
||||
</div>
|
||||
</CardBar>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,28 +6,6 @@
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
/* FIXME These are just copied as-is from staking/Summary - once happy and proven to be
|
||||
shareable, it needs to be moved into ui-app for consistency.
|
||||
*/
|
||||
.democracy--Summary {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.democracy--Summary-column {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.democracy--Summary-card {
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.democracy--Proposals,
|
||||
.democracy--Referendums {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
@ -6,7 +6,6 @@ import { BareProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import Query from './Query';
|
||||
import Summary from './Summary';
|
||||
import BlockHeaders from './BlockHeaders';
|
||||
|
||||
@ -18,7 +17,6 @@ export default class Main extends React.PureComponent<Props> {
|
||||
render () {
|
||||
return [
|
||||
<Summary key='summary' />,
|
||||
<Query key='query' />,
|
||||
<BlockHeaders key='headers' />
|
||||
];
|
||||
}
|
||||
|
||||
@ -4,37 +4,32 @@
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import CardBar from '@polkadot/ui-app/CardBar';
|
||||
import CardSummary from '@polkadot/ui-app/CardSummary';
|
||||
import BestNumber from '@polkadot/ui-react-rx/BestNumber';
|
||||
import TimePeriod from '@polkadot/ui-react-rx/TimePeriod';
|
||||
import TimeNow from '@polkadot/ui-react-rx/TimeNow';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
|
||||
import Query from './Query';
|
||||
import SummarySession from './SummarySession';
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
eraBlockLength?: BN,
|
||||
eraBlockProgress?: BN,
|
||||
sessionBlockProgress?: BN,
|
||||
sessionBrokenValue?: BN,
|
||||
sessionBrokenPercentLate?: BN,
|
||||
sessionLength?: BN
|
||||
};
|
||||
type Props = I18nProps & {};
|
||||
|
||||
class Summary extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { className, eraBlockLength, eraBlockProgress, sessionBlockProgress, sessionBrokenValue, sessionBrokenPercentLate, sessionLength, style, t } = this.props;
|
||||
const { className, style, t } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('explorer--Summary', className)}
|
||||
<CardBar
|
||||
className={className}
|
||||
expanded={
|
||||
<Query />
|
||||
}
|
||||
style={style}
|
||||
>
|
||||
<div className='explorer--Summary-column'>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.period', {
|
||||
defaultValue: 'target time'
|
||||
})}>
|
||||
@ -46,55 +41,19 @@ class Summary extends React.PureComponent<Props> {
|
||||
<TimeNow />
|
||||
</CardSummary>
|
||||
</div>
|
||||
<div className='explorer--Summary-column'>
|
||||
<CardSummary
|
||||
label={t('summary.sessionProgress', {
|
||||
defaultValue: 'session'
|
||||
})}
|
||||
progress={{
|
||||
total: sessionLength,
|
||||
value: sessionBlockProgress
|
||||
}}
|
||||
/>
|
||||
<CardSummary
|
||||
label={t('summary.eraProgress', {
|
||||
defaultValue: 'era'
|
||||
})}
|
||||
progress={{
|
||||
total: eraBlockLength,
|
||||
value: eraBlockProgress
|
||||
}}
|
||||
/>
|
||||
<CardSummary
|
||||
label={t('summary.brokenCount', {
|
||||
defaultValue: 'lateness'
|
||||
})}
|
||||
progress={{
|
||||
color: 'autoReverse',
|
||||
total: sessionBrokenPercentLate,
|
||||
value: sessionBrokenValue
|
||||
}}
|
||||
/>
|
||||
<div className='column'>
|
||||
<SummarySession />
|
||||
</div>
|
||||
<div className='explorer--Summary-column'>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.best', {
|
||||
defaultValue: 'best'
|
||||
})}>
|
||||
<BestNumber />
|
||||
</CardSummary>
|
||||
</div>
|
||||
</div>
|
||||
</CardBar>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Summary,
|
||||
translate,
|
||||
withObservable('eraBlockLength'),
|
||||
withObservable('eraBlockProgress'),
|
||||
withObservable('sessionBlockProgress'),
|
||||
withObservable('sessionBrokenValue'),
|
||||
withObservable('sessionLength'),
|
||||
withObservable('sessionBrokenPercentLate')
|
||||
);
|
||||
export default translate(Summary);
|
||||
|
||||
74
packages/app-explorer/src/SummarySession.tsx
Normal file
74
packages/app-explorer/src/SummarySession.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
// Copyright 2017-2018 @polkadot/app-explorer authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import CardSummary from '@polkadot/ui-app/CardSummary';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = I18nProps & {
|
||||
eraBlockLength?: BN,
|
||||
eraBlockProgress?: BN,
|
||||
sessionBlockProgress?: BN,
|
||||
sessionBrokenValue?: BN,
|
||||
sessionBrokenPercentLate?: BN,
|
||||
sessionLength?: BN
|
||||
};
|
||||
|
||||
class SummarySession extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { eraBlockLength, eraBlockProgress, sessionBlockProgress, sessionBrokenValue, sessionBrokenPercentLate, sessionLength, t } = this.props;
|
||||
|
||||
return [
|
||||
<CardSummary
|
||||
key='sessionProgress'
|
||||
label={t('summary.sessionProgress', {
|
||||
defaultValue: 'session'
|
||||
})}
|
||||
progress={{
|
||||
total: sessionLength,
|
||||
value: sessionBlockProgress
|
||||
}}
|
||||
/>,
|
||||
<CardSummary
|
||||
key='eraProgress'
|
||||
label={t('summary.eraProgress', {
|
||||
defaultValue: 'era'
|
||||
})}
|
||||
progress={{
|
||||
total: eraBlockLength,
|
||||
value: eraBlockProgress
|
||||
}}
|
||||
/>,
|
||||
<CardSummary
|
||||
key='brokenCount'
|
||||
label={t('summary.brokenCount', {
|
||||
defaultValue: 'lateness'
|
||||
})}
|
||||
progress={{
|
||||
color: 'autoReverse',
|
||||
isPercent: true,
|
||||
total: sessionBrokenPercentLate,
|
||||
value: sessionBrokenValue
|
||||
}}
|
||||
/>
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
SummarySession,
|
||||
translate,
|
||||
withObservable('eraBlockLength'),
|
||||
withObservable('eraBlockProgress'),
|
||||
withObservable('sessionBlockProgress'),
|
||||
withObservable('sessionBrokenValue'),
|
||||
withObservable('sessionLength'),
|
||||
withObservable('sessionBrokenPercentLate')
|
||||
);
|
||||
@ -79,24 +79,6 @@
|
||||
right: 0rem;
|
||||
}
|
||||
|
||||
.explorer--Summary {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.explorer--Summary-column {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.explorer--Summary-card {
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.explorer--Query {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
@ -4,51 +4,63 @@
|
||||
|
||||
import { I18nProps } from '@polkadot/ui-app/types';
|
||||
import { RxBalance, RxBalanceMap } from '@polkadot/ui-react-rx/ApiObservable/types';
|
||||
import { ApiProps } from '@polkadot/ui-react-rx/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React from 'react';
|
||||
import classes from '@polkadot/ui-app/util/classes';
|
||||
import withObservable from '@polkadot/ui-react-rx/with/observable';
|
||||
import withMulti from '@polkadot/ui-react-rx/with/multi';
|
||||
import CardBar from '@polkadot/ui-app/CardBar';
|
||||
import CardSummary from '@polkadot/ui-app/CardSummary';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
import translate from './translate';
|
||||
|
||||
type Props = ApiProps & I18nProps & {
|
||||
type Props = I18nProps & {
|
||||
balances: RxBalanceMap,
|
||||
bestNumber?: BN,
|
||||
intentions: Array<string>,
|
||||
lastLengthChange?: BN,
|
||||
sessionBlockProgress?: BN,
|
||||
sessionLength?: BN,
|
||||
validators: Array<string>
|
||||
};
|
||||
|
||||
const DEFAULT_BLOCKNUMBER = new BN(0);
|
||||
const DEFAULT_SESSION_PROGRESS = new BN(0);
|
||||
const DEFAULT_SESSION_LENGTH = new BN(60);
|
||||
|
||||
class Summary extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { bestNumber = DEFAULT_BLOCKNUMBER, className, intentions, style, sessionLength = DEFAULT_SESSION_LENGTH, sessionBlockProgress = DEFAULT_SESSION_PROGRESS, t, validators } = this.props;
|
||||
const { className, intentions, style, t, validators } = this.props;
|
||||
|
||||
return (
|
||||
<CardBar
|
||||
className={className}
|
||||
style={style}
|
||||
>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.validators', {
|
||||
defaultValue: 'validators'
|
||||
})}>
|
||||
{validators.length}
|
||||
</CardSummary>
|
||||
<CardSummary label={t('summary.intentions', {
|
||||
defaultValue: 'intentions'
|
||||
})}>
|
||||
{intentions.length}
|
||||
</CardSummary>
|
||||
</div>
|
||||
<div className='column'>
|
||||
<CardSummary label={t('summary.balances', {
|
||||
defaultValue: 'balances'
|
||||
})}>
|
||||
{this.renderBalances()}
|
||||
</CardSummary>
|
||||
</div>
|
||||
</CardBar>
|
||||
);
|
||||
}
|
||||
|
||||
private renderBalances () {
|
||||
const { t } = this.props;
|
||||
const intentionHigh = this.calcIntentionsHigh();
|
||||
const validatorLow = this.calcValidatorLow();
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('staking--Summary', className)}
|
||||
style={style}
|
||||
>
|
||||
<div>{t('summary.headline', {
|
||||
defaultValue: '{{validatorCount}} validators, {{intentionCount}} accounts with intentions',
|
||||
replace: {
|
||||
intentionCount: intentions.length,
|
||||
validatorCount: validators.length
|
||||
}
|
||||
})}</div>
|
||||
<div className='staking--Summary-text'>
|
||||
<div>{t('summary.balance.validator', {
|
||||
defaultValue: 'lowest validator balance is {{validatorLow}}',
|
||||
defaultValue: 'lowest validator {{validatorLow}}',
|
||||
replace: {
|
||||
validatorLow: validatorLow && validatorLow.stakingBalance
|
||||
? `${numberFormat(validatorLow.stakingBalance)} (+${numberFormat(validatorLow.nominatedBalance)})`
|
||||
@ -56,21 +68,13 @@ class Summary extends React.PureComponent<Props> {
|
||||
}
|
||||
})}</div>
|
||||
<div>{t('summary.balance.stake', {
|
||||
defaultValue: ' highest balance intending to stake is {{intentionHigh}}',
|
||||
defaultValue: 'highest intention {{intentionHigh}}',
|
||||
replace: {
|
||||
intentionHigh: intentionHigh
|
||||
? `${numberFormat(intentionHigh.stakingBalance)} (+${numberFormat(intentionHigh.nominatedBalance)})`
|
||||
: 'unknown'
|
||||
}
|
||||
})}</div>
|
||||
<div>{t('summary.countdown', {
|
||||
defaultValue: 'session block {{remainder}} / {{length}} at #{{blockNumber}}',
|
||||
replace: {
|
||||
blockNumber: numberFormat(bestNumber),
|
||||
remainder: sessionBlockProgress.toString(),
|
||||
length: sessionLength.toString()
|
||||
}
|
||||
})}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -106,10 +110,4 @@ class Summary extends React.PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
export default withMulti(
|
||||
Summary,
|
||||
translate,
|
||||
withObservable('bestNumber'),
|
||||
withObservable('sessionBlockProgress'),
|
||||
withObservable('sessionLength')
|
||||
);
|
||||
export default translate(Summary);
|
||||
|
||||
@ -85,3 +85,10 @@
|
||||
opacity: 0.45;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.staking--Summary-text {
|
||||
text-align: right;
|
||||
font-size: 1rem;
|
||||
font-weight: normal;
|
||||
line-height: 1.2rem;
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import RxBalance from '@polkadot/ui-react-rx/Balance';
|
||||
import numberFormat from '@polkadot/ui-react-rx/util/numberFormat';
|
||||
|
||||
import classes from './util/classes';
|
||||
import translate from './translate';
|
||||
|
||||
export type Props = BareProps & {
|
||||
balance?: BN | Array<BN>,
|
||||
@ -19,7 +18,7 @@ export type Props = BareProps & {
|
||||
withLabel?: boolean
|
||||
};
|
||||
|
||||
class Balance extends React.PureComponent<Props> {
|
||||
export default class Balance extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { balance, className, label, value, style } = this.props;
|
||||
|
||||
@ -62,5 +61,3 @@ class Balance extends React.PureComponent<Props> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate(Balance);
|
||||
|
||||
46
packages/ui-app/src/CardBar.tsx
Normal file
46
packages/ui-app/src/CardBar.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
// Copyright 2017-2018 @polkadot/ui-app authors & contributors
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the ISC license. See the LICENSE file for details.
|
||||
|
||||
import { BareProps } from '@polkadot/ui-app/types';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import classes from './util/classes';
|
||||
|
||||
export type Props = BareProps & {
|
||||
children: React.ReactNode,
|
||||
expanded?: React.ReactNode
|
||||
};
|
||||
|
||||
export default class CardBar extends React.PureComponent<Props> {
|
||||
render () {
|
||||
const { children, className, style } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classes('ui--CardBar', className)}
|
||||
style={style}
|
||||
>
|
||||
<div className='ui--CardBar-cards'>
|
||||
{children}
|
||||
</div>
|
||||
{this.renderExtra()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private renderExtra () {
|
||||
const { expanded } = this.props;
|
||||
|
||||
if (!expanded) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='ui--CardBar-expanded'>
|
||||
{expanded}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ import classes from './util/classes';
|
||||
|
||||
type ProgressProps = {
|
||||
color?: ProgressColors,
|
||||
isPercent?: boolean,
|
||||
total?: BN,
|
||||
value?: BN
|
||||
};
|
||||
@ -31,8 +32,16 @@ export default class CardSummary extends React.PureComponent<Props> {
|
||||
const left = progress && !isUndefined(progress.value) && !isUndefined(progress.total) && progress.value.gten(0) && progress.total.gtn(0)
|
||||
? (
|
||||
progress.value.gt(progress.total)
|
||||
? `>${progress.total.toString()}`
|
||||
: progress.value.toString()
|
||||
? `>${
|
||||
progress.isPercent
|
||||
? '100'
|
||||
: progress.total.toString()
|
||||
}`
|
||||
: (
|
||||
progress.isPercent
|
||||
? progress.value.muln(100).div(progress.total).toString()
|
||||
: progress.value.toString()
|
||||
)
|
||||
)
|
||||
: undefined;
|
||||
|
||||
@ -47,7 +56,11 @@ export default class CardSummary extends React.PureComponent<Props> {
|
||||
progress && (
|
||||
!left || isUndefined(progress.total)
|
||||
? '-'
|
||||
: `${left}/${progress.total.toString()}`
|
||||
: `${left}${progress.isPercent ? '' : '/'}${
|
||||
progress.isPercent
|
||||
? '%'
|
||||
: progress.total.toString()
|
||||
}`
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
@ -140,6 +140,28 @@
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.ui--CardBar {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
.ui--CardBar-cards {
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ui--CardBar-cards .column {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ui--CardBar-cards .ui--Card {
|
||||
flex: 0 1 auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.ui--CardSummary .ui.label {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user