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:
commit
e69a4d5833
10
README.md
10
README.md
@ -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:
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
)
|
||||
|
@ -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;
|
||||
|
@ -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]} />
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class RelatedPosts extends PureComponent {
|
||||
className={`${styles.button} btn`}
|
||||
onClick={this.shufflePosts}
|
||||
>
|
||||
More Related Posts
|
||||
Refresh Related Posts
|
||||
</button>
|
||||
</aside>
|
||||
)
|
||||
|
@ -43,7 +43,7 @@ pre {
|
||||
border-radius: $border-radius;
|
||||
|
||||
// make 'em scrollable
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
max-height: 300px;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user