1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-11-15 01:25:28 +01:00

Merge pull request #68 from kremalicious/feature/web3-number-input

number input & modal tweaks
This commit is contained in:
Matthias Kretschmann 2018-10-13 19:22:16 +02:00 committed by GitHub
commit e69a4d5833
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 237 additions and 75 deletions

View File

@ -18,7 +18,7 @@
- [🎉 Features](#-features)
- [🎆 EXIF extraction](#-exif-extraction)
- [💰 Cryptocurrency donation via Web3/MetaMask](#-cryptocurrency-donation-via-web3-metamask)
- [💰 Cryptocurrency donation via Web3/MetaMask](#-cryptocurrency-donation-via-web3metamask)
- [🕸 Related Posts](#-related-posts)
- [🐝 Coinhive](#-coinhive)
- [🏆 SEO component](#-seo-component)
@ -55,11 +55,11 @@ If you want to know how this works, have a look at the respective component unde
### 💰 Cryptocurrency donation via Web3/MetaMask
Lets visitors say thanks with Bitcoin or Ether. Includes full Web3 client for sending Ether via MetaMask or Mist.
Lets visitors say thanks with Bitcoin or Ether. Uses [web3.js](https://github.com/ethereum/web3.js) for sending Ether transactions via MetaMask, Brave or Mist. Component listens to account & network changes and adapts accordingly.
As a fallback, QR codes are generated with [react-qr-svg](https://github.com/no23reason/react-qr-svg) from the addresses defined in [`config.js`](config.js).
<img width="743" alt="screen shot 2018-10-11 at 21 01 37" src="https://user-images.githubusercontent.com/90316/46827443-e1187680-cd98-11e8-9daf-00a37c0ee13a.png">
<img width="1091" alt="screen shot 2018-10-13 at 18 40 56" src="https://user-images.githubusercontent.com/90316/46907751-907b5780-cf17-11e8-902d-6c520b388292.png" />
If you want to know how this works, have a look at the respective components under
@ -70,7 +70,7 @@ If you want to know how this works, have a look at the respective components und
Under each post a list of related posts is displayed which are based on the tags of the currently viewed post. Also allows loading more related posts in place.
<img width="691" alt="screen shot 2018-10-11 at 21 03 03" src="https://user-images.githubusercontent.com/90316/46827531-14f39c00-cd99-11e8-84aa-0e851c32c89c.png">
<img width="691" alt="screen shot 2018-10-11 at 21 03 03" src="https://user-images.githubusercontent.com/90316/46827531-14f39c00-cd99-11e8-84aa-0e851c32c89c.png" />
If you want to know how this works, have a look at the respective component under
@ -80,7 +80,7 @@ If you want to know how this works, have a look at the respective component unde
Includes a component for mining Monero with JavaScript via [Coinhive](https://coinhive.com).
<img width="166" alt="screen shot 2018-10-11 at 21 09 49" src="https://user-images.githubusercontent.com/90316/46827858-03f75a80-cd9a-11e8-84f1-65b7d0027124.png">
<img width="166" alt="screen shot 2018-10-11 at 21 09 49" src="https://user-images.githubusercontent.com/90316/46827858-03f75a80-cd9a-11e8-84f1-65b7d0027124.png" />
Functionality is opt-in on a post basis. Simply add this to any post's frontmatter to activate it for this post:

View File

@ -31,8 +31,8 @@
"dms2dec": "^1.1.0",
"fast-exif": "^1.0.1",
"fraction.js": "^4.0.9",
"gatsby": "^2.0.21",
"gatsby-image": "^2.0.13",
"gatsby": "^2.0.22",
"gatsby-image": "^2.0.14",
"gatsby-plugin-catch-links": "^2.0.4",
"gatsby-plugin-favicon": "^3.1.4",
"gatsby-plugin-feed": "^2.0.8",
@ -78,7 +78,7 @@
"@babel/node": "^7.0.0",
"@babel/preset-env": "^7.1.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.6.1",
"eslint": "^5.7.0",
"eslint-config-prettier": "^3.1.0",
"eslint-loader": "^2.1.1",
"eslint-plugin-graphql": "^2.1.1",

View File

@ -10,14 +10,15 @@
bottom: 0;
z-index: 10;
background: rgba($body-background-color, .9);
backdrop-filter: blur(5px);
// backdrop-filter: blur(5px);
animation: fadein .3s;
padding: $spacer / 2;
padding: $spacer;
@media (min-width: $screen-sm) {
display: flex;
align-items: center;
align-items: flex-start;
justify-content: center;
padding-top: 6vh;
}
}
@ -42,20 +43,31 @@
cursor: pointer;
background: transparent;
border: 0;
-webkit-appearance: none;
appearance: none;
line-height: 1;
font-size: $font-size-large;
padding: 3px;
font-size: $font-size-h2;
padding: 4px;
position: absolute;
top: 0;
right: ($spacer/4);
color: $brand-grey;
color: $brand-grey-light;
font-weight: 500;
&:hover,
&:focus {
color: $brand-grey;
}
}
// Prevent background scrolling when modal is open
.isModalOpen {
// Prevent background scrolling when modal is open
overflow: hidden;
// more cross-browser backdrop-filter
body > div:first-child {
transition: filter .85s ease-out;
filter: blur(5px);
}
}
.modal__title {

View File

@ -1,11 +1,85 @@
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import Web3 from 'web3'
import Input from '../atoms/Input'
import styles from './Web3Donation.module.scss'
const ONE_SECOND = 1000
const ONE_MINUTE = ONE_SECOND * 60
const InputGroup = ({
networkId,
selectedAccount,
amount,
onAmountChange,
handleWeb3Button
}) => (
<div className={styles.inputGroup}>
<div className={styles.input}>
<Input
type="number"
disabled={!(networkId === '1') || !selectedAccount}
value={amount}
onChange={onAmountChange}
min="0"
step="0.01"
/>
<div className={styles.currency}>
<span>ETH</span>
</div>
</div>
<button
className="btn btn-primary"
onClick={handleWeb3Button}
disabled={!(networkId === '1') || !selectedAccount}
>
Make it rain
</button>
</div>
)
InputGroup.propTypes = {
networkId: PropTypes.string,
selectedAccount: PropTypes.string,
amount: PropTypes.number,
onAmountChange: PropTypes.func,
handleWeb3Button: PropTypes.func
}
const Alerts = ({ accounts, networkId, error, transactionHash }) => {
if (error || accounts.length === 0) {
return (
<div className={styles.alert}>
{accounts.length === 0 &&
'Web3 detected, but no account. Are you logged into your MetaMask account?'}
{networkId !== '1' && 'Please connect to Main network'}
{error && error.message}
</div>
)
}
if (transactionHash) {
return (
<div className={styles.success}>
You are awesome, thanks!
<br />
<a href={`https://etherscan.io/tx/${transactionHash}`}>
See your transaction on etherscan.io.
</a>
</div>
)
}
return null
}
Alerts.propTypes = {
accounts: PropTypes.array,
networkId: PropTypes.string,
error: PropTypes.object,
transactionHash: PropTypes.string
}
export default class Web3Donation extends PureComponent {
state = {
web3Connected: false,
@ -13,6 +87,7 @@ export default class Web3Donation extends PureComponent {
networkId: null,
accounts: [],
selectedAccount: null,
amount: 0.01,
receipt: null,
transactionHash: null,
loading: false,
@ -120,7 +195,7 @@ export default class Web3Donation extends PureComponent {
{
from: this.state.selectedAccount,
to: this.props.address,
value: '10000000000000000'
value: this.state.amount * 1e18 // ETH -> Wei
},
(error, transactionHash) => {
if (error) this.setState({ error, loading: false })
@ -130,57 +205,45 @@ export default class Web3Donation extends PureComponent {
)
}
onAmountChange = ({ target }) => {
this.setState({ amount: target.value })
}
render() {
return (
<div className={styles.web3}>
<h4>web3</h4>
<p>Send a donation with MetaMask or Mist.</p>
<header>
<h4>web3</h4>
<p>Send Ether with MetaMask, Brave, or Mist.</p>
</header>
{this.state.web3Connected ? (
<div>
<div className={styles.web3Row}>
{this.state.loading ? (
'Hang on...'
) : (
<button
className="btn btn-primary"
onClick={this.handleWeb3Button}
disabled={
!(this.state.networkId === '1') || !this.state.selectedAccount
}
>
Make it rain 0.01 Ξ
</button>
<InputGroup
networkId={this.state.networkId}
selectedAccount={this.state.selectedAccount}
amount={this.state.amount}
onAmountChange={this.onAmountChange}
handleWeb3Button={this.handleWeb3Button}
/>
)}
{this.state.accounts.length === 0 && (
<div className={styles.alert}>
Web3 detected, but no account. Are you logged into your MetaMask
account?
</div>
)}
{this.state.networkId !== '1' && (
<div className={styles.alert}>Please connect to Main network</div>
)}
{this.state.error && (
<div className={styles.alert}>{this.state.error.message}</div>
)}
{this.state.transactionHash && (
<div className={styles.success}>
You are awesome, thanks!
<br />
<a
href={`https://etherscan.io/tx/${this.state.transactionHash}`}
>
See your transaction on etherscan.io.
</a>
</div>
)}
<Alerts
accounts={this.state.accounts}
networkId={this.state.networkId}
error={this.state.error}
transactionHash={this.state.transactionHash}
/>
</div>
) : (
<div className={styles.alert}>No Web3 capable browser detected.</div>
<small>
No Web3 detected. Install <a href="https://metamask.io">MetaMask</a>
, <a href="https://brave.com">Brave</a>, or{' '}
<a href="https://github.com/ethereum/mist">Mist</a>.
</small>
)}
</div>
)

View File

@ -10,23 +10,89 @@
margin-bottom: $spacer;
padding-bottom: $spacer * 1.5;
small {
color: darken($alert-info, 60%);
margin-top: -($spacer / 2);
display: block;
}
}
.web3Row {
min-height: 58px;
}
.inputGroup {
max-width: 17rem;
margin: auto;
position: relative;
@media (min-width: $screen-sm) {
display: flex;
max-width: 18rem;
}
button {
margin: auto;
width: 100%;
border-top-left-radius: 0;
border-top-right-radius: 0;
border-color: lighten($brand-grey-light, 10%);
@media (min-width: $screen-sm) {
width: 50%;
border-top-right-radius: $border-radius;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 0;
}
}
}
.input {
position: relative;
@media (min-width: $screen-sm) {
width: 50%;
}
h4 {
font-size: $font-size-large;
margin-top: 0;
margin-bottom: $spacer / 4;
color: $brand-grey;
input {
text-align: center;
}
border: 1px solid lighten($brand-grey-light, 20%);
font-size: $font-size-large;
padding: $spacer / 3 $spacer / 3 $spacer / 3 $spacer * 1.7;
border-bottom: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
p {
color: $brand-grey-light;
@media (min-width: $screen-sm) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
border-bottom-left-radius: $border-radius;
border-bottom: 1px solid lighten($brand-grey-light, 20%);
border-right: 0;
}
&::-webkit-inner-spin-button {
margin-left: -($spacer / 2);
}
}
}
.currency {
position: absolute;
top: 1px;
bottom: 1px;
left: 1px;
font-size: $font-size-small;
padding: $spacer / 3;
color: $brand-grey-light;
background: $brand-light;
border-right: 1px solid rgba($brand-grey-light, .4);
border-top-left-radius: $border-radius;
border-bottom-left-radius: $border-radius;
display: flex;
align-items: center;
}
.alert {
margin-top: $spacer / 2;
font-size: $font-size-small;

View File

@ -36,6 +36,11 @@ class ModalThanks extends PureComponent {
<div className={styles.modalThanks}>
<Web3Donation address={author.ether} />
<header>
<h4>Other wallets</h4>
<p>Send Bitcoin or Ether from any wallet.</p>
</header>
{Object.keys(author).map((address, i) => (
<div key={i} className={styles.coin}>
<Qr title={address} address={author[address]} />

View File

@ -6,6 +6,30 @@
justify-content: space-between;
flex-wrap: wrap;
}
h4 {
text-align: center;
margin: 0;
margin-bottom: $spacer / 2;
color: $brand-grey;
text-transform: capitalize;
}
header {
width: 100%;
text-align: center;
margin-bottom: $spacer;
h4 {
font-size: $font-size-large;
margin-top: 0;
margin-bottom: $spacer / 6;
}
p {
color: $brand-grey-light;
}
}
}
.coin {
@ -16,14 +40,6 @@
margin-top: 0;
}
h4 {
font-size: $font-size-large;
margin-top: 0;
margin-bottom: $spacer / 2;
color: $brand-grey;
text-align: center;
}
> svg {
margin-bottom: $spacer / 2;
}

View File

@ -103,7 +103,7 @@ class RelatedPosts extends PureComponent {
className={`${styles.button} btn`}
onClick={this.shufflePosts}
>
More Related Posts
Refresh Related Posts
</button>
</aside>
)

View File

@ -43,7 +43,7 @@ pre {
border-radius: $border-radius;
// make 'em scrollable
overflow: scroll;
overflow: auto;
-webkit-overflow-scrolling: touch;
max-height: 300px;