1
0
mirror of https://github.com/kremalicious/blog.git synced 2025-02-14 21:10:25 +01:00
This commit is contained in:
Matthias Kretschmann 2018-10-28 11:16:57 +01:00
parent ef78d92f74
commit 86948a5340
Signed by: m
GPG Key ID: 606EEEF3C479A91F
11 changed files with 133 additions and 83 deletions

View File

@ -1,4 +1,4 @@
import React, { Fragment, PureComponent } from 'react' import React, { PureComponent } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import styles from './Alerts.module.scss' import styles from './Alerts.module.scss'
@ -42,7 +42,7 @@ export default class Alerts extends PureComponent {
{!web3Connected ? ( {!web3Connected ? (
<Message message={this.alertMessages().noWeb3} /> <Message message={this.alertMessages().noWeb3} />
) : ( ) : (
<Fragment> <>
{!hasAccount && ( {!hasAccount && (
<Message message={this.alertMessages().noAccount} /> <Message message={this.alertMessages().noAccount} />
)} )}
@ -58,7 +58,7 @@ export default class Alerts extends PureComponent {
message={this.alertMessages(null, transactionHash).transaction} message={this.alertMessages(null, transactionHash).transaction}
/> />
)} )}
</Fragment> </>
)} )}
</div> </div>
) )

View File

@ -7,36 +7,30 @@ import styles from './InputGroup.module.scss'
export default class InputGroup extends PureComponent { export default class InputGroup extends PureComponent {
static propTypes = { static propTypes = {
hasCorrectNetwork: PropTypes.bool.isRequired, isCorrectNetwork: PropTypes.bool.isRequired,
hasAccount: PropTypes.bool.isRequired, hasAccount: PropTypes.bool.isRequired,
amount: PropTypes.string.isRequired, amount: PropTypes.string.isRequired,
onAmountChange: PropTypes.func.isRequired, onAmountChange: PropTypes.func.isRequired,
handleButton: PropTypes.func.isRequired, handleButton: PropTypes.func.isRequired,
selectedAccount: PropTypes.string, selectedAccount: PropTypes.string
inTransaction: PropTypes.bool,
message: PropTypes.string
} }
render() { render() {
const { const {
hasCorrectNetwork, isCorrectNetwork,
hasAccount, hasAccount,
amount, amount,
onAmountChange, onAmountChange,
handleButton, handleButton,
selectedAccount, selectedAccount
inTransaction,
message
} = this.props } = this.props
return inTransaction ? ( return (
<div className={styles.message}>{message}</div>
) : (
<div className={styles.inputGroup}> <div className={styles.inputGroup}>
<div className={styles.input}> <div className={styles.input}>
<Input <Input
type="number" type="number"
disabled={!hasCorrectNetwork || !hasAccount} disabled={!isCorrectNetwork || !hasAccount}
value={amount} value={amount}
onChange={onAmountChange} onChange={onAmountChange}
min="0" min="0"
@ -49,11 +43,11 @@ export default class InputGroup extends PureComponent {
<button <button
className="btn btn-primary" className="btn btn-primary"
onClick={handleButton} onClick={handleButton}
disabled={!hasCorrectNetwork || !hasAccount} disabled={!isCorrectNetwork || !hasAccount}
> >
Make it rain Make it rain
</button> </button>
{hasCorrectNetwork && {isCorrectNetwork &&
hasAccount && ( hasAccount && (
<div className={styles.infoline}> <div className={styles.infoline}>
<Conversion amount={amount} /> <Conversion amount={amount} />

View File

@ -5,7 +5,7 @@
max-width: 18rem; max-width: 18rem;
margin: auto; margin: auto;
position: relative; position: relative;
animation: fadeIn .5s ease-out backwards; animation: fadeIn .8s ease-out backwards;
@media (min-width: $screen-sm) { @media (min-width: $screen-sm) {
display: flex; display: flex;
@ -84,7 +84,7 @@
} }
.message { .message {
font-size: $font-size-small; composes: message from './index.module.scss';
} }
@keyframes fadeIn { @keyframes fadeIn {

View File

@ -22,7 +22,8 @@ export default class Web3Donation extends PureComponent {
receipt: null, receipt: null,
inTransaction: false, inTransaction: false,
error: null, error: null,
message: 'Hang on...' message: 'Hang on',
success: false
} }
static propTypes = { static propTypes = {
@ -126,19 +127,22 @@ export default class Web3Donation extends PureComponent {
.once('transactionHash', transactionHash => { .once('transactionHash', transactionHash => {
this.setState({ this.setState({
transactionHash, transactionHash,
message: 'Waiting for network confirmation, hang on...' message: 'Waiting for network confirmation, hang on'
}) })
}) })
.on('error', error => this.setState({ error, inTransaction: false })) .on('error', error => this.setState({ error, inTransaction: false }))
.then(() => { .then(() => {
this.setState({ message: 'Confirmed. You are awesome, thanks!' }) this.setState({
message: 'Confirmed. You are awesome, thanks!',
success: true
})
}) })
} }
handleButton = () => { handleButton = () => {
this.setState({ this.setState({
inTransaction: true, inTransaction: true,
message: 'Waiting for your confirmation...' message: 'Waiting for your confirmation'
}) })
this.sendTransaction() this.sendTransaction()
@ -161,7 +165,8 @@ export default class Web3Donation extends PureComponent {
error, error,
transactionHash, transactionHash,
confirmationNumber, confirmationNumber,
message message,
success
} = this.state } = this.state
const hasAccount = accounts.length !== 0 const hasAccount = accounts.length !== 0
@ -175,17 +180,20 @@ export default class Web3Donation extends PureComponent {
<div className={styles.web3Row}> <div className={styles.web3Row}>
{loading ? ( {loading ? (
<div className={styles.message}>Checking...</div> <div className={styles.message}>Checking</div>
) : inTransaction ? (
<div className={success ? styles.success : styles.message}>
{message}
</div>
) : ( ) : (
web3Connected && ( web3Connected && (
<InputGroup <InputGroup
hasCorrectNetwork={isCorrectNetwork} isCorrectNetwork={isCorrectNetwork}
hasAccount={hasAccount} hasAccount={hasAccount}
selectedAccount={selectedAccount} selectedAccount={selectedAccount}
amount={amount} amount={amount}
onAmountChange={this.onAmountChange} onAmountChange={this.onAmountChange}
handleButton={this.handleButton} handleButton={this.handleButton}
inTransaction={inTransaction}
message={message} message={message}
/> />
) )

View File

@ -30,4 +30,32 @@
.message { .message {
font-size: $font-size-small; font-size: $font-size-small;
position: relative;
&::after {
overflow: hidden;
display: inline-block;
vertical-align: bottom;
animation: ellipsis steps(4, end) 1s infinite;
content: '\2026'; // ascii code for the ellipsis character
width: 0;
position: absolute;
left: 100%;
bottom: 0;
}
}
.success {
composes: message;
color: green;
&::after {
display: none;
}
}
@keyframes ellipsis {
to {
width: .75rem;
}
} }

View File

@ -74,9 +74,7 @@ export const getFiat = async amount => {
try { try {
const response = await fetch(url) const response = await fetch(url)
if (!response.ok) { if (!response.ok) Logger.error(response.statusText)
throw Error(response.statusText)
}
const data = await response.json() const data = await response.json()
const { price_usd, price_eur } = data[0] const { price_usd, price_eur } = data[0]
const dollar = (amount * price_usd).toFixed(2) const dollar = (amount * price_usd).toFixed(2)

View File

@ -33,9 +33,8 @@ export default class CoinHiveClient extends PureComponent {
return new Promise(resolve => { return new Promise(resolve => {
loadScript(config.script, error => { loadScript(config.script, error => {
if (error) { if (error) return
return
}
resolve( resolve(
window.CoinHive.Anonymous(config.siteKey, { window.CoinHive.Anonymous(config.siteKey, {
throttle: config.throttle, throttle: config.throttle,

View File

@ -8,7 +8,7 @@
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
z-index: 10; z-index: 9;
background: rgba($body-background-color, .9); background: rgba($body-background-color, .9);
// backdrop-filter: blur(5px); // backdrop-filter: blur(5px);
animation: fadein .3s; animation: fadein .3s;

View File

@ -1,11 +1,17 @@
import React, { Fragment } from 'react' import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { QRCode } from 'react-qr-svg' import { QRCode } from 'react-qr-svg'
import Clipboard from 'react-clipboard.js' import Clipboard from 'react-clipboard.js'
import { ReactComponent as IconClipboard } from '../../images/clipboard.svg' import { ReactComponent as IconClipboard } from '../../images/clipboard.svg'
import styles from './Qr.module.scss'
const onCopySuccess = e => {
e.trigger.classList.add(styles.copied)
}
const Qr = ({ address, title }) => ( const Qr = ({ address, title }) => (
<Fragment> <>
{title && <h4>{title}</h4>} {title && <h4>{title}</h4>}
<QRCode <QRCode
bgColor="transparent" bgColor="transparent"
@ -13,14 +19,21 @@ const Qr = ({ address, title }) => (
level="Q" level="Q"
style={{ width: 120 }} style={{ width: 120 }}
value={address} value={address}
className={styles.qr}
/> />
<pre>
<pre className={styles.code}>
<code>{address}</code> <code>{address}</code>
<Clipboard data-clipboard-text={address} button-title="Copy to clipboard"> <Clipboard
data-clipboard-text={address}
button-title="Copy to clipboard"
onSuccess={e => onCopySuccess(e)}
className={styles.button}
>
<IconClipboard /> <IconClipboard />
</Clipboard> </Clipboard>
</pre> </pre>
</Fragment> </>
) )
Qr.propTypes = { Qr.propTypes = {

View File

@ -0,0 +1,54 @@
@import 'variables';
.qr {
margin-bottom: $spacer / 2;
}
.code {
margin: 0;
position: relative;
padding: 0;
padding-right: 2rem;
code {
padding: $spacer / 2;
font-size: .65rem;
text-align: center;
}
}
.button {
margin: 0;
position: absolute;
right: 0;
top: 0;
bottom: 0;
border: 0;
box-shadow: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
background: rgba($brand-grey, .3);
padding: $spacer / 3;
svg {
width: 1rem;
height: 1rem;
fill: $brand-grey-light;
transition: .15s ease-out;
}
&:hover {
svg {
fill: $brand-grey-dimmed;
}
}
}
.copied {
background: green;
// stylelint-disable-next-line no-descending-specificity
svg {
fill: $brand-grey-dimmed;
}
}

View File

@ -39,48 +39,4 @@
width: 48%; width: 48%;
margin-top: 0; margin-top: 0;
} }
> svg {
margin-bottom: $spacer / 2;
}
pre {
margin: 0;
position: relative;
padding: 0;
padding-right: 2rem;
code {
padding: $spacer / 2;
font-size: .65rem;
text-align: center;
}
}
button {
margin: 0;
position: absolute;
right: 0;
top: 0;
bottom: 0;
border: 0;
box-shadow: none;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
background: rgba($brand-grey, .3);
padding: $spacer / 3;
svg {
width: 1rem;
height: 1rem;
fill: $brand-grey;
transition: .15s ease-out;
}
&:hover {
svg {
fill: $brand-grey-dimmed;
}
}
}
} }