diff --git a/src/AppV2.js b/src/AppV2.js index 231989d4..50ac8b39 100644 --- a/src/AppV2.js +++ b/src/AppV2.js @@ -18,6 +18,7 @@ const Dashboard = lazy(() => import('v2/components/Dashboard')); const Validators = lazy(() => import('v2/components/Validators')); const ValidatorsAll = lazy(() => import('v2/components/Validators/All')); const ValidatorDetail = lazy(() => import('v2/components/Validators/Detail')); +const TourDeSol = lazy(() => import('v2/components/TourDeSol')); const useStyles = makeStyles(theme => ({ root: { @@ -69,6 +70,7 @@ const App = () => { path="/rc/validators/:id" component={ValidatorDetail} /> + diff --git a/src/v2/assets/icons/arrow-right-dark.png b/src/v2/assets/icons/arrow-right-dark.png new file mode 100644 index 00000000..6fb3710b Binary files /dev/null and b/src/v2/assets/icons/arrow-right-dark.png differ diff --git a/src/v2/assets/icons/bicycle.svg b/src/v2/assets/icons/bicycle.svg new file mode 100644 index 00000000..772afbea --- /dev/null +++ b/src/v2/assets/icons/bicycle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/v2/components/Dashboard/NetworkOverview/index.jsx b/src/v2/components/Dashboard/NetworkOverview/index.jsx index 6aeb8acd..625c555f 100644 --- a/src/v2/components/Dashboard/NetworkOverview/index.jsx +++ b/src/v2/components/Dashboard/NetworkOverview/index.jsx @@ -37,7 +37,7 @@ const NetworkOverview = () => { return ( - Network Overview + diff --git a/src/v2/components/Dashboard/ViewAll/index.jsx b/src/v2/components/Dashboard/ViewAll/index.jsx index 35159e5a..bf425efe 100644 --- a/src/v2/components/Dashboard/ViewAll/index.jsx +++ b/src/v2/components/Dashboard/ViewAll/index.jsx @@ -11,7 +11,7 @@ const ViewAll = () => { return ( - View All + diff --git a/src/v2/components/HelpLink/styles.js b/src/v2/components/HelpLink/styles.js index b8e9348d..ab07fe58 100644 --- a/src/v2/components/HelpLink/styles.js +++ b/src/v2/components/HelpLink/styles.js @@ -13,6 +13,7 @@ export default makeStyles(theme => ({ padding: '0 5px', color: getColor('greenDark')(theme), transition: '.15s ease-in-out', + marginLeft: 15, '&:hover': { color: getColor('main')(theme), borderColor: getColor('main')(theme), diff --git a/src/v2/components/TourDeSol/Cards/index.jsx b/src/v2/components/TourDeSol/Cards/index.jsx new file mode 100644 index 00000000..72461d6f --- /dev/null +++ b/src/v2/components/TourDeSol/Cards/index.jsx @@ -0,0 +1,78 @@ +// @flow +import {map} from 'lodash/fp'; +import React from 'react'; +import {observer} from 'mobx-react-lite'; +import NodesStore from 'v2/stores/nodes'; +import Card from 'v2/components/UI/StatCard'; + +import useStyles from './styles'; + +const Cards = () => { + const classes = useStyles(); + const {cluster} = NodesStore; + const {nodes} = cluster; + const cards = [ + { + title: 'Stage Duration Blocks', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + { + title: 'Days Left In Stage', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + { + title: 'Total SOL In Circulation', + value: cluster.supply / Math.pow(2, 34).toFixed(2), + changes: '', + period: 'since yesterday', + }, + { + title: 'Total Bonded Tokens', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + { + title: 'Current Network Inflation Rate', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + { + title: '# of Active Validators', + value: nodes.length, + changes: '', + period: 'since yesterday', + }, + { + title: '# of Inactive Validators', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + { + title: 'Circulating Supply Staked', + value: 'TODO', + changes: '', + period: 'since yesterday', + }, + ]; + + const renderStats = ({ + title, + value, + changes = null, + }: { + title: string, + value: string | (() => React$Node), + changes?: string, + }) => ; + + return {map(renderStats)(cards)}; +}; + +export default observer(Cards); diff --git a/src/v2/components/TourDeSol/Cards/styles.js b/src/v2/components/TourDeSol/Cards/styles.js new file mode 100644 index 00000000..3b85acad --- /dev/null +++ b/src/v2/components/TourDeSol/Cards/styles.js @@ -0,0 +1,9 @@ +import {makeStyles} from '@material-ui/core'; + +export default makeStyles(() => ({ + cards: { + '& div:not(:last-child)': { + marginBottom: 20, + }, + }, +})); diff --git a/src/v2/components/TourDeSol/Ranking/index.jsx b/src/v2/components/TourDeSol/Ranking/index.jsx new file mode 100644 index 00000000..64db870f --- /dev/null +++ b/src/v2/components/TourDeSol/Ranking/index.jsx @@ -0,0 +1,40 @@ +import React from 'react'; +import {observer} from 'mobx-react-lite'; +import {map} from 'lodash/fp'; +import HelpLink from 'v2/components/HelpLink'; +import NodesStore from 'v2/stores/nodes'; +import {ReactComponent as BicycleIcon} from 'v2/assets/icons/bicycle.svg'; + +import useStyles from './styles'; + +const Ranking = () => { + const classes = useStyles(); + const { + cluster: {nodes}, + } = NodesStore; + + const renderNode = node => ( + + {node.pubkey} + + + + + + + ); + + return ( + + + Top Validator Ranking + + + {map(renderNode)(nodes)} + + ); +}; + +Ranking.propTypes = {}; + +export default observer(Ranking); diff --git a/src/v2/components/TourDeSol/Ranking/styles.js b/src/v2/components/TourDeSol/Ranking/styles.js new file mode 100644 index 00000000..bbdace86 --- /dev/null +++ b/src/v2/components/TourDeSol/Ranking/styles.js @@ -0,0 +1,50 @@ +import {makeStyles} from '@material-ui/core'; +import getColor from 'v2/utils/getColor'; + +export default makeStyles(theme => ({ + root: { + background: getColor('grey2')(theme), + padding: '17px 24px', + }, + list: { + padding: 0, + }, + item: { + display: 'flex', + alignItems: 'center', + '&:not(:last-child)': { + marginBottom: 17, + }, + }, + name: { + maxWidth: 130, + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', + color: getColor('main')(theme), + marginRight: 20, + flexShrink: 0, + '&::before': { + content: '""', + display: 'inline-block', + verticalAlign: 'middle', + width: 33, + height: 33, + background: getColor('main')(theme), + borderRadius: '50%', + marginRight: 22, + }, + }, + bar: { + flex: 1, + height: 8, + borderRadius: 10, + background: getColor('greyW1')(theme), + position: 'relative', + }, + icon: { + position: 'absolute', + top: '50%', + transform: 'translateY(-50%)', + }, +})); diff --git a/src/v2/components/TourDeSol/Table/index.jsx b/src/v2/components/TourDeSol/Table/index.jsx new file mode 100644 index 00000000..12aba84d --- /dev/null +++ b/src/v2/components/TourDeSol/Table/index.jsx @@ -0,0 +1,114 @@ +// @flow + +import React from 'react'; +import { + Typography, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Grid, +} from '@material-ui/core'; +import cn from 'classnames'; +import useMediaQuery from '@material-ui/core/useMediaQuery'; +import {useTheme} from '@material-ui/core/styles'; +import {observer} from 'mobx-react-lite'; +import {Link} from 'react-router-dom'; +import {map} from 'lodash/fp'; +import NodesStore from 'v2/stores/nodes'; +import HelpLink from '../../HelpLink'; + +import useStyles from './styles'; + +const ValidatorsTable = ({separate}: {separate: boolean}) => { + const classes = useStyles(); + const theme = useTheme(); + const showTable = useMediaQuery(theme.breakpoints.up('md')); + const { + cluster: {voting = []}, + } = NodesStore; + + const renderRow = row => { + return ( + + 1 + + + + {row.nodePubkey} + + + {row.stake} + TODO + + ); + }; + const renderCard = card => { + return ( + + + + {card.nodePubkey} + + + + Stake + {card.stake} + + + Uptime + TODO + + + + ); + }; + return ( + + + + Active Validators + + + {voting.length} + {!separate && ( + + See all > + + )} + + {showTable ? ( + + + + Ranking + Name + Stake + Uptime + + + + {map(renderRow)(voting)} + + + ) : ( + + {map(renderCard)(voting)} + + )} + + ); +}; + +export default observer(ValidatorsTable); diff --git a/src/v2/components/TourDeSol/Table/styles.js b/src/v2/components/TourDeSol/Table/styles.js new file mode 100644 index 00000000..ea75a43e --- /dev/null +++ b/src/v2/components/TourDeSol/Table/styles.js @@ -0,0 +1,110 @@ +import {makeStyles} from '@material-ui/core'; +import getColor from 'v2/utils/getColor'; + +export default makeStyles(theme => ({ + root: { + marginTop: 19, + background: getColor('grey2')(theme), + padding: '25px 44px', + [theme.breakpoints.down('sm')]: { + padding: 0, + paddingBottom: 27, + marginBottom: 50, + }, + }, + head: { + border: '1px solid #979797', + '& th': { + textTransform: 'uppercase', + fontSize: 15, + letterSpacing: 2, + paddingRight: 5, + fontWeight: 'bold', + borderBottom: 'none', + }, + }, + body: { + '& td': { + fontSize: 15, + paddingTop: 18, + paddingBottom: 18, + paddingRight: 5, + maxWidth: 0, + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', + }, + }, + header: { + display: 'flex', + alignItems: 'baseline', + flexWrap: 'wrap', + '& *:first-child': { + marginRight: 35, + }, + marginBottom: 23, + [theme.breakpoints.down('sm')]: { + padding: '10px 27px 0', + marginBottom: 10, + }, + }, + link: { + marginLeft: 'auto', + textTransform: 'uppercase', + color: getColor('main')(theme), + fontSize: 15, + textDecoration: 'none', + }, + name: { + display: 'flex', + alignItems: 'center', + color: getColor('main')(theme), + textDecoration: 'none', + '& span': { + width: 33, + height: 33, + flexShrink: 0, + background: getColor('main')(theme), + borderRadius: '50%', + marginRight: 22, + }, + '& div': { + whiteSpace: 'nowrap', + textOverflow: 'ellipsis', + overflow: 'hidden', + }, + [theme.breakpoints.down('sm')]: { + marginBottom: 22, + }, + }, + list: { + display: 'flex', + width: '100%', + overflowX: 'auto', + }, + vertical: { + [theme.breakpoints.down('sm')]: { + flexDirection: 'column', + }, + }, + card: { + padding: 17, + background: '#505050', + marginRight: 12, + maxWidth: 326, + }, + cardVertical: { + [theme.breakpoints.down('sm')]: { + marginBottom: 2, + marginRight: 0, + maxWidth: '100%', + }, + }, + cardTitle: { + fontSize: 12, + textTransform: 'uppercase', + color: '#C4C4C4', + letterSpacing: 2, + fontWight: 'bold', + }, +})); diff --git a/src/v2/components/TourDeSol/index.jsx b/src/v2/components/TourDeSol/index.jsx new file mode 100644 index 00000000..b3f2f3b0 --- /dev/null +++ b/src/v2/components/TourDeSol/index.jsx @@ -0,0 +1,50 @@ +// @flow +import {Container, Grid} from '@material-ui/core'; +import React from 'react'; +import cn from 'classnames'; +import {observer} from 'mobx-react-lite'; +import SectionHeader from 'v2/components/UI/SectionHeader'; +import iconRight from 'v2/assets/icons/arrow-right-dark.png'; + +import Ranking from './Ranking'; +import Table from './Table'; +import Cards from './Cards'; +import useStyles from './styles'; + +const TourDeSol = () => { + const classes = useStyles(); + + return ( + + + + + + + Stage 1 (live!) + + + + + Stage 1(coming 09/01/19) + + + Stage 3(coming 10/01/19) + + + + + + + + + + + + + + + ); +}; + +export default observer(TourDeSol); diff --git a/src/v2/components/TourDeSol/styles.js b/src/v2/components/TourDeSol/styles.js new file mode 100644 index 00000000..4d2a3b1b --- /dev/null +++ b/src/v2/components/TourDeSol/styles.js @@ -0,0 +1,48 @@ +import {makeStyles} from '@material-ui/core'; +import getColor from 'v2/utils/getColor'; + +export default makeStyles(theme => ({ + root: { + padding: '40px 0', + }, + stages: { + display: 'flex', + width: '100%', + padding: 0, + marginLeft: 50, + maxWidth: 675, + [theme.breakpoints.down('sm')]: { + maxWidth: '100%', + marginLeft: 0, + }, + }, + stage: { + height: 55, + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + color: getColor('white')(theme), + padding: '0 15px', + fontSize: 15, + lineHeight: 1, + textTransform: 'uppercase', + lettersSpacing: 2.5, + border: `1px solid ${getColor('grey3')(theme)}`, + flex: 1, + fontWeight: 'bold', + '&:not(:first-child)': { + borderLeft: 'none', + }, + '& span': { + fontSize: 10, + marginTop: 3, + fontWeight: 'normal', + }, + }, + stageActive: { + background: getColor('main')(theme), + color: getColor('dark')(theme), + borderColor: getColor('main')(theme), + }, +})); diff --git a/src/v2/components/UI/SectionHeader/index.jsx b/src/v2/components/UI/SectionHeader/index.jsx index fabfd6f6..dd57529d 100644 --- a/src/v2/components/UI/SectionHeader/index.jsx +++ b/src/v2/components/UI/SectionHeader/index.jsx @@ -5,14 +5,21 @@ import React from 'react'; import decor from './assets/decorate.png'; import useStyles from './styles'; -const SectionHeader = ({children}: {children: React$Node}) => { +const SectionHeader = ({ + title, + children, +}: { + title: string, + children?: React$Node, +}) => { const classes = useStyles(); return ( - {children} + {title} + {children} ); }; diff --git a/src/v2/components/UI/SectionHeader/styles.js b/src/v2/components/UI/SectionHeader/styles.js index a3ca6c3a..1010590a 100644 --- a/src/v2/components/UI/SectionHeader/styles.js +++ b/src/v2/components/UI/SectionHeader/styles.js @@ -4,15 +4,23 @@ export default makeStyles(theme => ({ root: { position: 'relative', marginBottom: 47, + display: 'flex', + alignItems: 'center', + justifyContent: 'space-between', + [theme.breakpoints.down('sm')]: { + flexWrap: 'wrap', + }, }, title: { display: 'flex', alignItems: 'center', + whiteSpace: 'nowrap', }, decor: { position: 'absolute', left: -120, - top: -7, + top: '50%', + transform: 'translateY(-50%)', [theme.breakpoints.down('sm')]: { display: 'none', }, diff --git a/src/v2/components/UI/StatCard/index.jsx b/src/v2/components/UI/StatCard/index.jsx index c74fe8f6..1f407905 100644 --- a/src/v2/components/UI/StatCard/index.jsx +++ b/src/v2/components/UI/StatCard/index.jsx @@ -1,6 +1,7 @@ // @flow import React from 'react'; import {Paper, Typography} from '@material-ui/core'; +import HelpLink from 'v2/components/HelpLink'; import useStyles from './styles'; @@ -35,6 +36,7 @@ const StatCard = (props: StatCardProps) => { {title} + {renderValue()} diff --git a/src/v2/components/Validators/Detail/index.jsx b/src/v2/components/Validators/Detail/index.jsx index 319bb44f..baeea87d 100644 --- a/src/v2/components/Validators/Detail/index.jsx +++ b/src/v2/components/Validators/Detail/index.jsx @@ -135,8 +135,7 @@ const ValidatorsDetail = ({match}: {match: Match}) => { return ( - - Validator Detail + {!isMobile && ( diff --git a/src/v2/components/Validators/index.jsx b/src/v2/components/Validators/index.jsx index fa3fbaa6..9ff89faf 100644 --- a/src/v2/components/Validators/index.jsx +++ b/src/v2/components/Validators/index.jsx @@ -70,8 +70,7 @@ const Validators = () => { return ( - - Validators Overview + Become a validator diff --git a/src/v2/theme.js b/src/v2/theme.js index b61245ad..8bcc7f99 100644 --- a/src/v2/theme.js +++ b/src/v2/theme.js @@ -6,6 +6,7 @@ export default createMuiTheme({ primary: { dark: '#000', grey: '#242424', + greyW1: '#424242', grey2: '#202020', grey3: '#979797', grey4: '#c4c4c4',