diff --git a/packages/page-accounts/src/Accounts/index.tsx b/packages/page-accounts/src/Accounts/index.tsx index 90056abfa4..d137737fa2 100644 --- a/packages/page-accounts/src/Accounts/index.tsx +++ b/packages/page-accounts/src/Accounts/index.tsx @@ -116,8 +116,9 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement )} - - - }> - - - - - - - - - {sortedAccounts.map(({ address, isFavorite }): React.ReactNode => ( - - ))} - + } + header={[ + [t('accounts'), 'start', 3], + [t('type')], + [t('tags'), 'start'], + [t('transactions')], + [t('balances')], + [undefined, undefined, 2] + ]} + > + {sortedAccounts.map(({ address, isFavorite }): React.ReactNode => ( + + ))}
-

{t('accounts')}

-
{t('type')}{t('tags')}{t('transactions')}{t('balances')} 
); diff --git a/packages/page-accounts/src/Contacts/index.tsx b/packages/page-accounts/src/Contacts/index.tsx index c0ea74cbc7..914b8a463e 100644 --- a/packages/page-accounts/src/Contacts/index.tsx +++ b/packages/page-accounts/src/Contacts/index.tsx @@ -54,8 +54,9 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement )} - - - }> - - - - - - - - {sortedAddresses.map(({ address, isFavorite }): React.ReactNode => ( -
- ))} - + } + header={[ + [t('contacts'), 'start', 2], + [t('tags'), 'start'], + [t('transactions')], + [t('balances')], + [undefined, undefined, 2] + ]} + > + {sortedAddresses.map(({ address, isFavorite }): React.ReactNode => ( +
+ ))}
-

{t('contacts')}

-
{t('tags')}{t('transactions')}{t('balances')} 
); diff --git a/packages/page-council/src/Motions/index.tsx b/packages/page-council/src/Motions/index.tsx index 250fe63bdf..37905c4151 100644 --- a/packages/page-council/src/Motions/index.tsx +++ b/packages/page-council/src/Motions/index.tsx @@ -44,26 +44,26 @@ function Proposals ({ className, motions, prime }: Props): React.ReactElement - - - - - - - - - - - {motions?.map((motion: DeriveCollectiveProposal): React.ReactNode => ( - - ))} - +
 {t('threshold')}{t('voting end')}{t('aye')}{t('nay')} 
+ {motions?.map((motion: DeriveCollectiveProposal): React.ReactNode => ( + + ))}
); diff --git a/packages/page-council/src/Overview/Candidates.tsx b/packages/page-council/src/Overview/Candidates.tsx index fdbd11d535..8de432d52e 100644 --- a/packages/page-council/src/Overview/Candidates.tsx +++ b/packages/page-council/src/Overview/Candidates.tsx @@ -21,46 +21,36 @@ function Candidates ({ allVotes = {}, electionsInfo }: Props): React.ReactElemen return ( <> - - - - - - - {electionsInfo?.runnersUp.map(([accountId, balance]): React.ReactNode => ( - - ))} - +
-

{t('runners up')}

-
{t('backing')}
+ {electionsInfo?.runnersUp.map(([accountId, balance]): React.ReactNode => ( + + ))}
- - - - - - - {electionsInfo?.candidates.map((accountId): React.ReactNode => ( - - ))} - +
-

{t('candidates')}

-
{t('backing')}
+ {electionsInfo?.candidates.map((accountId): React.ReactNode => ( + + ))}
); diff --git a/packages/page-council/src/Overview/Members.tsx b/packages/page-council/src/Overview/Members.tsx index bf61e7a7e6..f749d81d78 100644 --- a/packages/page-council/src/Overview/Members.tsx +++ b/packages/page-council/src/Overview/Members.tsx @@ -21,27 +21,23 @@ function Members ({ allVotes = {}, className, electionsInfo, prime }: Props): Re const { t } = useTranslation(); return ( - - - - - - - {electionsInfo?.members.map(([accountId, balance]): React.ReactNode => ( - - ))} - +
-

{t('members')}

-
{t('backing')}
+ {electionsInfo?.members.map(([accountId, balance]): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-democracy/src/Overview/DispatchQueue.tsx b/packages/page-democracy/src/Overview/DispatchQueue.tsx index d48fabd9b5..aed936209d 100644 --- a/packages/page-democracy/src/Overview/DispatchQueue.tsx +++ b/packages/page-democracy/src/Overview/DispatchQueue.tsx @@ -21,25 +21,21 @@ function DispatchQueue ({ className }: Props): React.ReactElement | null const queued = useCall(api.derive.democracy.dispatchQueue as any, []); return ( - - - - - - - - {queued?.map((entry): React.ReactNode => ( - - ))} - +
-

{t('dispatch queue')}

-
{t('enact')} 
+ {queued?.map((entry): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-democracy/src/Overview/Externals.tsx b/packages/page-democracy/src/Overview/Externals.tsx index 3e3702dc96..5d418e007b 100644 --- a/packages/page-democracy/src/Overview/Externals.tsx +++ b/packages/page-democracy/src/Overview/Externals.tsx @@ -21,19 +21,18 @@ function Externals ({ className }: Props): React.ReactElement | null { const external = useCall(api.derive.democracy.nextExternal, []); return ( -
- - - - - - - - - {external && } - -

{t('external')}

{t('proposer')}{t('locked')} 
-
+ + {external && } +
); } diff --git a/packages/page-democracy/src/Overview/Proposals.tsx b/packages/page-democracy/src/Overview/Proposals.tsx index 21206b2900..ac63d178b2 100644 --- a/packages/page-democracy/src/Overview/Proposals.tsx +++ b/packages/page-democracy/src/Overview/Proposals.tsx @@ -21,26 +21,22 @@ function Proposals ({ className }: Props): React.ReactElement { const proposals = useCall(api.derive.democracy.proposals, []); return ( - - - - - - - - - {proposals?.map((proposal): React.ReactNode => ( - - ))} - +
-

{t('proposals')}

-
{t('proposer')}{t('locked')} 
+ {proposals?.map((proposal): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-democracy/src/Overview/Referendums.tsx b/packages/page-democracy/src/Overview/Referendums.tsx index f9717fc9ae..490c8ea564 100644 --- a/packages/page-democracy/src/Overview/Referendums.tsx +++ b/packages/page-democracy/src/Overview/Referendums.tsx @@ -21,28 +21,24 @@ function Referendums ({ className }: Props): React.ReactElement { const referendums = useCall(api.derive.democracy.referendums, []); return ( - - - - - - - - - - - {referendums?.map((referendum): React.ReactNode => ( - - ))} - +
-

{t('referenda')}

-
{t('remaining')}{t('activate')}{t('aye')}{t('nay')} 
+ {referendums?.map((referendum): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-explorer/src/BlockHeaders.tsx b/packages/page-explorer/src/BlockHeaders.tsx index acf36865b0..4d160483e2 100644 --- a/packages/page-explorer/src/BlockHeaders.tsx +++ b/packages/page-explorer/src/BlockHeaders.tsx @@ -17,25 +17,20 @@ function BlockHeaders ({ headers }: Props): React.ReactElement { const { t } = useTranslation(); return ( - - - - - - {headers - .filter((header) => !!header) - .map((header): React.ReactNode => ( - - ))} - +
-

{t('recent blocks')}

-
+ {headers + .filter((header) => !!header) + .map((header): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-explorer/src/BlockInfo/ByHash.tsx b/packages/page-explorer/src/BlockInfo/ByHash.tsx index 9e9d03f0b2..bb5c5acdd5 100644 --- a/packages/page-explorer/src/BlockInfo/ByHash.tsx +++ b/packages/page-explorer/src/BlockInfo/ByHash.tsx @@ -33,41 +33,36 @@ function BlockByHash ({ className, value }: Props): React.ReactElement { return (
- - - - {getHeader && ( - <> - - - - - - - )} - - - {getBlock && !getBlock.isEmpty && getHeader && !getHeader.isEmpty && ( - - - - - - - - - )} - +
-

{blockNumber ? formatNumber(blockNumber) : '...'}

-
{t('hash')}{t('parent')}{t('extrinsics')}{t('state')} 
{getHeader.author && }{getHeader.hash.toHex()}{parentHash}{getHeader.extrinsicsRoot.toHex()}{getHeader.stateRoot.toHex()} - -
+ {getBlock && !getBlock.isEmpty && getHeader && !getHeader.isEmpty && ( + + + + + + + + + )}
{getHeader.author && }{getHeader.hash.toHex()}{parentHash}{getHeader.extrinsicsRoot.toHex()}{getHeader.stateRoot.toHex()} + +
{getBlock && getHeader && ( <> diff --git a/packages/page-explorer/src/BlockInfo/Extrinsics.tsx b/packages/page-explorer/src/BlockInfo/Extrinsics.tsx index 324df8f9a6..10a665679d 100644 --- a/packages/page-explorer/src/BlockInfo/Extrinsics.tsx +++ b/packages/page-explorer/src/BlockInfo/Extrinsics.tsx @@ -24,34 +24,23 @@ function Extrinsics ({ blockNumber, className, events, label, value }: Props): R return ( - - - - - - - {value?.map((extrinsic, index): React.ReactNode => - - )} - + {value?.map((extrinsic, index): React.ReactNode => + + )}
-

{label || t('extrinsics')}

-
- {t('events')} - {t('signer')}
); } diff --git a/packages/page-explorer/src/BlockInfo/Logs.tsx b/packages/page-explorer/src/BlockInfo/Logs.tsx index 4792d13640..3370904b67 100644 --- a/packages/page-explorer/src/BlockInfo/Logs.tsx +++ b/packages/page-explorer/src/BlockInfo/Logs.tsx @@ -104,21 +104,19 @@ function Logs (props: Props): React.ReactElement | null { const { t } = useTranslation(); return ( - - - - - - {value?.map((log, index) => ( - - - - ))} - +

{t('logs')}

- - {formatItem(log)} - -
+ {value?.map((log, index) => ( + + + + ))}
+ + {formatItem(log)} + +
); } diff --git a/packages/page-explorer/src/Events.tsx b/packages/page-explorer/src/Events.tsx index 526bfe6149..109eb84325 100644 --- a/packages/page-explorer/src/Events.tsx +++ b/packages/page-explorer/src/Events.tsx @@ -21,25 +21,25 @@ function Events ({ emptyLabel, eventClassName, events, label }: Props): React.Re const { t } = useTranslation(); return ( - - - - - - {events - .filter(({ event: { method, section } }): boolean => !!method && !!section) - .map((event: EventRecord, index): React.ReactNode => ( - - - - )) - } - +

{label || t('recent events')}

- -
+ {events + .filter(({ event: { method, section } }): boolean => !!method && !!section) + .map((event: EventRecord, index): React.ReactNode => ( + + + + )) + }
+ +
); } diff --git a/packages/page-explorer/src/NodeInfo/Peers.tsx b/packages/page-explorer/src/NodeInfo/Peers.tsx index 89e5362232..572b811b4d 100644 --- a/packages/page-explorer/src/NodeInfo/Peers.tsx +++ b/packages/page-explorer/src/NodeInfo/Peers.tsx @@ -19,23 +19,24 @@ function Peers ({ className, peers }: Props): React.ReactElement { const { t } = useTranslation(); return ( - - - - - - - - - {peers?.sort((a, b): number => b.bestNumber.cmp(a.bestNumber)).map((peer) => ( - - - - - - - ))} - +

{t('connected peers')}

{t('role')}{t('best #')}{t('best hash')}
{peer.peerId.toString()}{peer.roles.toString().toLowerCase()}{formatNumber(peer.bestNumber)}{peer.bestHash.toHex()}
+ {peers?.sort((a, b): number => b.bestNumber.cmp(a.bestNumber)).map((peer) => ( + + + + + + + ))}
{peer.peerId.toString()}{peer.roles.toString().toLowerCase()}{formatNumber(peer.bestNumber)}{peer.bestHash.toHex()}
); } diff --git a/packages/page-parachains/src/Overview/Parachains.tsx b/packages/page-parachains/src/Overview/Parachains.tsx index ddf6cdb72c..aad471873f 100644 --- a/packages/page-parachains/src/Overview/Parachains.tsx +++ b/packages/page-parachains/src/Overview/Parachains.tsx @@ -19,28 +19,25 @@ function Parachains ({ parachains }: Props): React.ReactElement { const { t } = useTranslation(); return ( - - - - - - - - {parachains.map((parachain): React.ReactNode => ( - - ))} - +
 {t('swap to id')}{t('scheduling')}
+ {parachains.map((parachain): React.ReactNode => ( + + ))}
); } export default React.memo(styled(Parachains)` - tbody { - tr { - cursor: pointer; - } + tbody tr { + cursor: pointer; } `); diff --git a/packages/page-society/src/Overview/Bids.tsx b/packages/page-society/src/Overview/Bids.tsx index bc756645e4..fcfd3a14a2 100644 --- a/packages/page-society/src/Overview/Bids.tsx +++ b/packages/page-society/src/Overview/Bids.tsx @@ -21,20 +21,21 @@ function Bids ({ className }: Props): React.ReactElement { const bids = useCall(api.query.society.bids, []); return ( - - - - - - - - {bids?.map((bid): React.ReactNode => ( - - ))} - +

{t('bids')}

{t('kind')}{t('value')}
+ {bids?.map((bid): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-society/src/Overview/Candidates.tsx b/packages/page-society/src/Overview/Candidates.tsx index cdc84928f5..4bdca8b4a5 100644 --- a/packages/page-society/src/Overview/Candidates.tsx +++ b/packages/page-society/src/Overview/Candidates.tsx @@ -22,25 +22,25 @@ function Candidates ({ allMembers, className, isMember, ownMembers }: Props): Re const candidates = useCall(api.derive.society.candidates, []); return ( - - - - - - - - - - {candidates?.map((candidate): React.ReactNode => ( - - ))} - +

{t('candidates')}

{t('kind')}{t('value')}{t('votes')} 
+ {candidates?.map((candidate): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-society/src/Overview/Defender.tsx b/packages/page-society/src/Overview/Defender.tsx index eb6e8b0bac..310c975be8 100644 --- a/packages/page-society/src/Overview/Defender.tsx +++ b/packages/page-society/src/Overview/Defender.tsx @@ -34,26 +34,26 @@ function Defender ({ className, info, isMember, ownMembers }: Props): React.Reac } return ( - - - - - - - - - - - - - +

{t('defender')}

{t('votes')} 
- - - -
+ + + + +
+ + + +
); } diff --git a/packages/page-society/src/Overview/Members.tsx b/packages/page-society/src/Overview/Members.tsx index 042f3f58cb..13a15e0e7a 100644 --- a/packages/page-society/src/Overview/Members.tsx +++ b/packages/page-society/src/Overview/Members.tsx @@ -29,25 +29,21 @@ function Members ({ className, info }: Props): React.ReactElement { }, [info, members]); return ( - - - - - - - {filtered.map((member): React.ReactNode => ( - - ))} - +
-

{t('members')}

-
{t('strikes')}
+ {filtered.map((member): React.ReactNode => ( + + ))}
); } diff --git a/packages/page-staking/src/Actions/index.tsx b/packages/page-staking/src/Actions/index.tsx index 9b34cdeebc..26028791f1 100644 --- a/packages/page-staking/src/Actions/index.tsx +++ b/packages/page-staking/src/Actions/index.tsx @@ -77,35 +77,30 @@ function Actions ({ allRewards, allStashes, className, isVisible, next, stakingO {isNewStakeOpen && ( )} - - - - - - - - - - {foundStashes?.map(([stashId, isOwnStash]): React.ReactNode => ( - - ))} - +
-

{t('stashes')}

-
{t('controller')}{t('rewards')}{t('bonded')} 
+ {foundStashes?.map(([stashId, isOwnStash]): React.ReactNode => ( + + ))}
); diff --git a/packages/page-staking/src/Overview/CurrentList.tsx b/packages/page-staking/src/Overview/CurrentList.tsx index a4a42b23d1..02168d323d 100644 --- a/packages/page-staking/src/Overview/CurrentList.tsx +++ b/packages/page-staking/src/Overview/CurrentList.tsx @@ -136,24 +136,19 @@ function CurrentList ({ authorsMap, hasQueries, isIntentions, lastAuthors, next, return isIntentions ? ( - - - - - - {_renderRows(elected, false).concat(..._renderRows(waiting, false))} - {} - +
-

{t('intentions')}

-
+ {_renderRows(elected, false).concat(..._renderRows(waiting, false))}
) : ( - - - }> - - - - - - - - - - {_renderRows(validators, true)} - + } + header={[ + [t('validators'), 'start', 3], + [t('other stake')], + [t('own stake')], + [t('commission')], + [t('points')], + [t('last #')], + [] + ]} + > + {_renderRows(validators, true)}
-

{t('validators')}

-
{t('other stake')}{t('own stake')}{t('commission')}{t('points')}{t('last #')} 
); } diff --git a/packages/page-staking/src/Targets/index.tsx b/packages/page-staking/src/Targets/index.tsx index 645bb96973..f4ad2a0992 100644 --- a/packages/page-staking/src/Targets/index.tsx +++ b/packages/page-staking/src/Targets/index.tsx @@ -219,8 +219,9 @@ function Targets ({ className }: Props): React.ReactElement { numValidators={validators.length} totalStaked={totalStaked} /> - - { onChange={setAmount} value={_amount} /> - }> - - {['rankComm', 'rankBondTotal', 'rankBondOwn', 'rankBondOther', 'rankOverall'].map((header): React.ReactNode => ( - - ))} - - - - {sorted?.map((info): React.ReactNode => - - )} - + } + header={[ + [t('validators'), 'start', 3], + ...['rankComm', 'rankBondTotal', 'rankBondOwn', 'rankBondOther', 'rankOverall'].map((header) => [ + <>{labels[header]}, + `isClickable ${sortBy === header && 'ui--highlight--border'} number`, + 1, + (): void => _sort(header as 'rankComm') + ]), + [] + ]} + > + {sorted?.map((info): React.ReactNode => + + )}
-

{t('validators')}

-
_sort(header as 'rankComm')} - >{labels[header]} 
); diff --git a/packages/page-tech-comm/src/Overview/Members.tsx b/packages/page-tech-comm/src/Overview/Members.tsx index 393fff00b7..248f51beef 100644 --- a/packages/page-tech-comm/src/Overview/Members.tsx +++ b/packages/page-tech-comm/src/Overview/Members.tsx @@ -19,34 +19,30 @@ function Members ({ className, members, prime }: Props): React.ReactElement - - -

{t('members')}

- -
- - {members?.map((accountId): React.ReactNode => ( - - - - - - {prime?.eq(accountId) && ( - - )} - -   - - ))} - + + {members?.map((accountId): React.ReactNode => ( + + + + + + ))}
+ + + {prime?.eq(accountId) && ( + + )} +  
); } diff --git a/packages/page-tech-comm/src/Proposals/index.tsx b/packages/page-tech-comm/src/Proposals/index.tsx index 5c68a3838f..9c67a58ffa 100644 --- a/packages/page-tech-comm/src/Proposals/index.tsx +++ b/packages/page-tech-comm/src/Proposals/index.tsx @@ -23,28 +23,23 @@ function Proposals ({ className, isMember, members, prime, proposals }: Props): members={members} /> - - - - - - - - - - {proposals?.map((hash: Hash): React.ReactNode => ( - - ))} - +
-

{t('proposals')}

-
{t('threshold')}{t('aye')}{t('nay')} 
+ {proposals?.map((hash: Hash): React.ReactNode => ( + + ))}
); diff --git a/packages/page-treasury/src/Overview/Proposals.tsx b/packages/page-treasury/src/Overview/Proposals.tsx index 5c0558a2f9..0035a3a769 100644 --- a/packages/page-treasury/src/Overview/Proposals.tsx +++ b/packages/page-treasury/src/Overview/Proposals.tsx @@ -40,30 +40,26 @@ function ProposalsBase ({ className, isApprovals, proposals }: Props): React.Rea }; return ( - - - - - - - - - - {proposals?.map((proposal): React.ReactNode => ( - - ))} - +
-

{isApprovals ? t('Approved') : t('Proposals')}

-
{t('beneficiary')}{t('payment')}{t('bond')} 
+ {proposals?.map((proposal): React.ReactNode => ( + + ))}
); } diff --git a/packages/react-components/src/Table/Body.tsx b/packages/react-components/src/Table/Body.tsx new file mode 100644 index 0000000000..6ddb6abe06 --- /dev/null +++ b/packages/react-components/src/Table/Body.tsx @@ -0,0 +1,34 @@ +// Copyright 2017-2020 @polkadot/react-components authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import React from 'react'; +import { isString } from '@polkadot/util'; + +import Spinner from '../Spinner'; + +interface Props { + children?: React.ReactNode; + className?: string; + empty?: React.ReactNode; + isEmpty?: boolean; +} + +function Body ({ children, className, empty, isEmpty }: Props): React.ReactElement { + return ( + + {isEmpty + ? ( + { + isString(empty) + ?
{empty}
+ : empty || + } + ) + : children + } + + ); +} + +export default React.memo(Body); diff --git a/packages/react-components/src/Table/Head.tsx b/packages/react-components/src/Table/Head.tsx new file mode 100644 index 0000000000..bcb6f22af5 --- /dev/null +++ b/packages/react-components/src/Table/Head.tsx @@ -0,0 +1,44 @@ +// Copyright 2017-2020 @polkadot/react-components authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import React from 'react'; + +interface Props { + className?: string; + filter?: React.ReactNode; + header: [React.ReactNode?, string?, number?, (() => void)?][]; + isEmpty: boolean; +} + +function Head ({ className, filter, header, isEmpty }: Props): React.ReactElement { + return ( + + {filter && ( + + {filter} + + )} + + {header.map(([label, className = 'default', colSpan = 1, onClick], index) => + + { + index === 0 + ?

{label}

+ : isEmpty + ? '' + : label + } + + )} + + + ); +} + +export default React.memo(Head); diff --git a/packages/react-components/src/Table.tsx b/packages/react-components/src/Table/index.tsx similarity index 77% rename from packages/react-components/src/Table.tsx rename to packages/react-components/src/Table/index.tsx index 3af57db5ae..0d6eb28714 100644 --- a/packages/react-components/src/Table.tsx +++ b/packages/react-components/src/Table/index.tsx @@ -4,77 +4,42 @@ import React from 'react'; import styled from 'styled-components'; -import { isString } from '@polkadot/util'; -import Spinner from './Spinner'; +import Body from './Body'; +import Head from './Head'; -interface BaseProps { +interface TableProps { children: React.ReactNode; className?: string; -} - -interface BodyProps extends BaseProps { empty?: React.ReactNode; -} - -interface HeadProps extends BaseProps { filter?: React.ReactNode; -} - -interface TableProps extends BaseProps { + header: [React.ReactNode?, string?, number?, (() => void)?][]; isFixed?: boolean; } -type TableImpl = React.FC & { - Body: React.FC; - Head: React.FC; -} - -function Head ({ children, className, filter }: HeadProps): React.ReactElement { - return ( - - {filter && ( - - {filter} - - )} - - {children} - - - ); -} - -function Body ({ children, className, empty }: BodyProps): React.ReactElement { +function Table ({ children, className, empty, filter, header, isFixed }: TableProps): React.ReactElement { const isEmpty = !children || (Array.isArray(children) && children.length === 0); - return ( - - {isEmpty - ? ( - { - isString(empty) - ?
{empty}
- : empty || - } - ) - : children - } - - ); -} - -function Table ({ children, className, isFixed }: TableProps): React.ReactElement { return (
- {children} + + + {children} +
); } -const Memo = React.memo(styled(Table)` +export default React.memo(styled(Table)` margin-bottom: 1.5rem; max-width: 100%; width: 100%; @@ -293,9 +258,4 @@ const Memo = React.memo(styled(Table)` } } } -`) as unknown as TableImpl; - -Memo.Body = React.memo(Body); -Memo.Head = React.memo(Head); - -export default Memo; +`);