Vote component (#30)

* gh-pages setup

* Minor change

* Change router

* Change font paths

* v1 to GH pages while waiting for domain

* Removes bad DApps, adds Nuo

* vote component + some styles

* styles for upvote and downvote

* fix: downvotes

* Adds routes to vote component
This commit is contained in:
Andy Tudhope 2019-04-16 09:34:45 +02:00 committed by GitHub
parent 4c94c909f6
commit f5e8da9d5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 18614 additions and 13 deletions

2
.gitignore vendored
View File

@ -38,4 +38,4 @@ yarn-debug.log*
yarn-error.log*
# Slither
crytic-export/
crytic-export/

18262
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

BIN
public/images/dapps/nuo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -42,11 +42,11 @@ const DappListItem = props => {
<img src={sntIcon} alt="SNT" width="16" height="16" />
12,345
</span>
<a className={styles.vote} href="#abc">
<a className={styles.vote} href="/vote">
<img src={upvoteArrowIcon} alt="" />
Upvote
</a>
<a className={styles.vote} href="#abc">
<a className={styles.vote} href="/vote">
<img src={downvoteArrowIcon} alt="" />
Downvote
</a>

View File

@ -401,4 +401,4 @@ const Dapps = [
},
]
export default Dapps
export default Dapps

View File

@ -2,15 +2,15 @@
font-family: 'Inter';
font-style: normal;
font-weight: 400;
src: url('/fonts/Inter-Regular.woff2') format('woff2'),
url('/fonts/Inter-Regular.woff') format('woff');
src: url('/discover-dapps/fonts/Inter-Regular.woff2') format('woff2'),
url('/discover-dapps/fonts/Inter-Regular.woff') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: italic;
font-weight: 400;
src: url('/fonts/Inter-Italic.woff2') format('woff2'),
url('/fonts/Inter-Italic.woff') format('woff');
src: url('/discover-dapps/fonts/Inter-Italic.woff2') format('woff2'),
url('/discover-dapps/fonts/Inter-Italic.woff') format('woff');
}
@font-face {
@ -25,13 +25,13 @@
font-family: 'Inter';
font-style: normal;
font-weight: 700;
src: url('/fonts/Inter-Bold.woff2') format('woff2'),
url('/fonts/Inter-Bold.woff') format('woff');
src: url('/discover-dapps/fonts/Inter-Bold.woff2') format('woff2'),
url('/discover-dapps/fonts/Inter-Bold.woff') format('woff');
}
@font-face {
font-family: 'Inter';
font-style: italic;
font-weight: 700;
src: url('/fonts/Inter-BoldItalic.woff2') format('woff2'),
url('/fonts/Inter-BoldItalic.woff') format('woff');
src: url('/discover-dapps/fonts/Inter-BoldItalic.woff2') format('woff2'),
url('/discover-dapps/fonts/Inter-BoldItalic.woff') format('woff');
}

View File

@ -3,13 +3,15 @@ import { Route, Switch } from 'react-router-dom'
import Home from '../Home'
import Filtered from '../Filtered'
import RecentlyAdded from '../RecentlyAdded'
import Vote from '../Vote'
import Dapps from '../Dapps'
export default () => (
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/discover-dapps/" component={Home} />
<Route path="/categories" component={Filtered} />
<Route path="/all" component={Dapps} />
<Route path="/recently-added" component={RecentlyAdded} />
<Route path="/vote" component={Vote} />
</Switch>
)

View File

@ -0,0 +1,9 @@
import { connect } from 'react-redux'
import Vote from './Vote'
const mapDispatchToProps = dispatch => ({})
export default connect(
null,
mapDispatchToProps,
)(Vote)

155
src/modules/Vote/Vote.jsx Normal file
View File

@ -0,0 +1,155 @@
import React, { Component } from 'react'
// import PropTypes from 'prop-types'
import ReactImageFallback from 'react-image-fallback'
import styles from './Vote.module.scss'
import sntIcon from '../../common/assets/images/SNT.svg'
import CategoriesUtils from '../Categories/Categories.utils'
import Categories from '../../common/utils/categories'
import icon from '../../common/assets/images/icon.svg'
const getCategoryName = category =>
Categories.find(x => x.key === category).value
class Vote extends Component {
constructor(props) {
super(props)
this.state = {
isUpvote: true,
sntValue: 0,
}
this.onClickTab = this.onClickTab.bind(this)
this.handleChange = this.handleChange.bind(this)
}
onClickTab(showUpvote) {
return () => {
this.setState({ isUpvote: showUpvote })
}
}
handleChange(e) {
this.setState({ sntValue: e.target.value })
}
render() {
const { isUpvote, sntValue } = this.state
// TODO: extract these to props
const dapp = {
name: 'Kyber',
url: 'https://web3.kyber.network',
description:
'On-chain, instant and liquid platform for exchange and payment service',
image: '/images/dapps/kyber.png',
category: 'EXCHANGES',
dateAdded: null,
}
const currentSNTamount = 23456
const categoryPosition = 2
const upvoteSNTcost = 12422
const downvoteSNTcost = 3244
return (
<div>
<div className={styles.tabs}>
<button
className={isUpvote ? styles.active : ''}
type="button"
onClick={this.onClickTab(true)}
>
UPVOTE
</button>
<button
className={!isUpvote ? styles.active : ''}
type="button"
onClick={this.onClickTab(false)}
>
DOWNVOTE
</button>
</div>
<div className={styles.dapp}>
<ReactImageFallback
className={styles.image}
src={dapp.image}
fallbackImage={icon}
alt="App icon"
width={24}
height={24}
/>
{dapp.name}
</div>
<div className={styles.items}>
{isUpvote && upvoteSNTcost > 0 && (
<span className={styles.greenBadge}>
{`${upvoteSNTcost.toLocaleString()}`}
</span>
)}
{!isUpvote && downvoteSNTcost > 0 && (
<span className={styles.redBadge}>
{`${downvoteSNTcost.toLocaleString()}`}
</span>
)}
<span className={styles.item}>
<img src={sntIcon} alt="SNT" width="24" height="24" />
{currentSNTamount.toLocaleString()}
</span>
{isUpvote && upvoteSNTcost > 0 && (
<span className={styles.greenBadge}>
{`${categoryPosition - 1}`}
</span>
)}
<span className={styles.item}>
<img
src={CategoriesUtils(dapp.category)}
alt={getCategoryName(dapp.category)}
width="24"
height="24"
/>
{`${getCategoryName(dapp.category)}${categoryPosition}`}
</span>
</div>
{!isUpvote && (
<div className={styles.inputArea}>
<span>{downvoteSNTcost}</span>
</div>
)}
{isUpvote && (
<div className={styles.inputArea}>
<input type="text" value={sntValue} onChange={this.handleChange} />
</div>
)}
<div className={styles.footer}>
{isUpvote && (
<p className={styles.disclaimer}>
SNT you spend to upvote is locked in the contract and contributes
directly to {dapp.name}'s ranking.{' '}
<a href="#" target="_blank">
Learn more
</a>
</p>
)}
{!isUpvote && (
<p className={styles.disclaimer}>
SNT you spend to downvote goes directly back to {dapp.name}.
Downvoting moves their DApp down by 1% of the current ranking. The
cost is fixed by our unique bonded curve.{' '}
<a href="#" target="_blank">
Learn more
</a>
</p>
)}
<button type="submit" disabled={!sntValue}>
{isUpvote ? 'Upvote' : 'Downvote'}
</button>
</div>
</div>
)
}
}
Vote.propTypes = {}
export default Vote

View File

@ -0,0 +1,170 @@
@import '../../common/styles/variables';
.tabs {
width: 100%;
border-bottom: 1px solid #eef2f5;
text-align: center;
}
.tabs button {
color: #939ba1;
background: transparent;
border: none;
text-transform: uppercase;
font-family: $font;
height: calculateRem(40);
letter-spacing: calculateRem(0.2);
display: inline-block;
width: 130px;
cursor: pointer;
}
.tabs button.active:after {
display: block;
clear: both;
content: '';
position: relative;
left: 0;
bottom: -9px;
height: 1px;
width: 24px;
border-bottom: 2px solid $link-color;
margin: 0 auto;
}
.tabs button.active {
color: $link-color;
}
.footer {
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
}
.footer button {
background: $link-color;
border-radius: 8px;
color: #fff;
margin: calculateRem(10) auto;
border: none;
font-family: $font;
padding: calculateRem(11) calculateRem(38);
font-size: calculateRem(15);
}
.footer button:disabled,
.footer button[disabled] {
background: $text-color;
}
.footer .disclaimer {
font-size: calculateRem(15);
color: $text-color;
line-height: 22px;
font-family: $font;
padding: calculateRem(16);
border-bottom: 1px solid #eef2f5;
margin: 0;
}
.footer .disclaimer a {
text-decoration: none;
color: $link-color;
}
.item,
.dapp {
line-height: 22px;
font-family: $font;
font-size: calculateRem(15);
display: block;
height: calculateRem(32);
padding: 0 calculateRem(12);
}
.item img,
.dapp img {
margin-right: calculateRem(12);
vertical-align: middle;
}
.dapp {
margin-bottom: calculateRem(12);
font-size: calculateRem(17);
font-weight: 500;
}
.dapp img {
vertical-align: bottom;
}
.badge {
float: right;
border-radius: 24px;
color: #ffffff;
font-family: $font;
font-size: calculateRem(15);
margin-right: calculateRem(16);
padding: calculateRem(3) calculateRem(10);
}
.greenBadge {
@extend .badge;
background: #44d058;
}
.redBadge {
@extend .badge;
background: #f00;
}
.inputArea {
text-align: center;
width: 300px;
position: fixed;
top: 40%;
}
.inputArea input {
margin: auto;
width: 50%;
border: none;
border-bottom: 1px solid #eef2f5;
text-align: center;
font-size: calculateRem(32);
line-height: calculateRem(28);
font-family: $font;
}
.inputArea input:focus {
outline: none;
}
.inputArea::after {
position: absolute;
top: 5px;
right: 0;
transition: all 0.05s ease-in-out;
content: 'SNT';
color: #939ba1;
font-size: calculateRem(32);
line-height: calculateRem(28);
font-family: $font;
}
.inputArea span {
font-size: calculateRem(32);
line-height: calculateRem(28);
font-family: $font;
position: relative;
top: 5px;
}
.image {
max-width: calculateRem(40);
max-height: calculateRem(40);
margin-top: calculateRem(15);
margin-right: calculateRem(16);
}

View File

@ -0,0 +1,3 @@
import Vote from './Vote.container'
export default Vote