mirror of
https://github.com/kremalicious/blog.git
synced 2024-11-22 18:00:06 +01:00
add thank you modal
This commit is contained in:
parent
0ddc52425b
commit
62d98d0c19
17
package.json
17
package.json
@ -24,14 +24,14 @@
|
||||
"dependencies": {
|
||||
"clipboard": "^2.0.1",
|
||||
"exif-js": "^2.3.0",
|
||||
"gatsby": "^2.0.0-beta.98",
|
||||
"gatsby": "^2.0.0-beta.100",
|
||||
"gatsby-image": "^2.0.0-beta.7",
|
||||
"gatsby-plugin-catch-links": "^2.0.2-beta.7",
|
||||
"gatsby-plugin-catch-links": "^2.0.2-beta.8",
|
||||
"gatsby-plugin-matomo": "^0.4.1",
|
||||
"gatsby-plugin-react-helmet": "^3.0.0-beta.4",
|
||||
"gatsby-plugin-sass": "^2.0.0-beta.10",
|
||||
"gatsby-plugin-sharp": "^2.0.0-beta.7",
|
||||
"gatsby-plugin-sitemap": "^2.0.0-beta.3",
|
||||
"gatsby-plugin-sitemap": "^2.0.0-beta.4",
|
||||
"gatsby-remark-autolink-headers": "^2.0.0-beta.5",
|
||||
"gatsby-remark-copy-linked-files": "^2.0.0-beta.3",
|
||||
"gatsby-remark-images": "^2.0.1-beta.10",
|
||||
@ -39,7 +39,7 @@
|
||||
"gatsby-remark-smartypants": "^2.0.0-beta.3",
|
||||
"gatsby-source-filesystem": "^2.0.1-beta.10",
|
||||
"gatsby-transformer-remark": "^2.1.1-beta.6",
|
||||
"gatsby-transformer-sharp": "^2.1.1-beta.6",
|
||||
"gatsby-transformer-sharp": "^2.1.1-beta.7",
|
||||
"gatsby-transformer-yaml": "^2.1.1-beta.3",
|
||||
"graphql": "^0.13.2",
|
||||
"intersection-observer": "^0.5.0",
|
||||
@ -48,21 +48,24 @@
|
||||
"prismjs": "^1.15.0",
|
||||
"qrious": "^4.0.2",
|
||||
"react": "^16.4.2",
|
||||
"react-clipboard.js": "^2.0.0",
|
||||
"react-dom": "^16.4.2",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-modal": "^3.5.1",
|
||||
"react-qr-svg": "^2.1.0",
|
||||
"react-time": "^4.3.0",
|
||||
"slugify": "^1.3.1",
|
||||
"vex-js": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/cli": "^2.1.1",
|
||||
"@svgr/cli": "^2.2.0",
|
||||
"babel-eslint": "^8.2.6",
|
||||
"eslint": "^5.3.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-config-prettier": "^2.10.0",
|
||||
"eslint-loader": "^2.1.0",
|
||||
"eslint-plugin-graphql": "^2.1.1",
|
||||
"eslint-plugin-prettier": "^2.6.2",
|
||||
"eslint-plugin-react": "^7.10.0",
|
||||
"eslint-plugin-react": "^7.11.0",
|
||||
"prettier": "^1.14.1",
|
||||
"prettier-stylelint": "^0.4.2",
|
||||
"stylelint": "^9.4.0",
|
||||
|
@ -39,7 +39,7 @@
|
||||
@include transition;
|
||||
|
||||
margin-top: $spacer * 2.65;
|
||||
margin-bottom: $spacer * 20;
|
||||
margin-bottom: $spacer * 20; // height of footer
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
|
||||
|
42
src/components/atoms/Modal.jsx
Normal file
42
src/components/atoms/Modal.jsx
Normal file
@ -0,0 +1,42 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ReactModal from 'react-modal'
|
||||
|
||||
import styles from './Modal.module.scss'
|
||||
|
||||
ReactModal.setAppElement('#___gatsby')
|
||||
|
||||
class Modal extends PureComponent {
|
||||
render() {
|
||||
if (!this.props.isOpen) {
|
||||
return null
|
||||
}
|
||||
|
||||
const { children, title, handleCloseModal } = this.props
|
||||
|
||||
return (
|
||||
<ReactModal
|
||||
overlayClassName={styles.modal}
|
||||
className={styles.modal__content}
|
||||
htmlOpenClassName={styles.isModalOpen}
|
||||
shouldReturnFocusAfterClose={false}
|
||||
{...this.props}
|
||||
>
|
||||
{title && <h1 className={styles.modal__title}>{title}</h1>}
|
||||
{children}
|
||||
<button className={styles.modal__close} onClick={handleCloseModal}>
|
||||
×
|
||||
</button>
|
||||
</ReactModal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Modal.propTypes = {
|
||||
title: PropTypes.string,
|
||||
isOpen: PropTypes.bool,
|
||||
handleCloseModal: PropTypes.func.isRequired,
|
||||
children: PropTypes.node.isRequired
|
||||
}
|
||||
|
||||
export default Modal
|
98
src/components/atoms/Modal.module.scss
Normal file
98
src/components/atoms/Modal.module.scss
Normal file
@ -0,0 +1,98 @@
|
||||
@import 'variables';
|
||||
|
||||
.modal {
|
||||
position: fixed;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
background: rgba($body-background-color, .9);
|
||||
backdrop-filter: blur(5px);
|
||||
animation: fadein .3s;
|
||||
padding: $spacer / 2;
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.modal__content {
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
position: relative;
|
||||
border-radius: $border-radius;
|
||||
border: 1px solid rgba($brand-grey-light, .4);
|
||||
box-shadow: 0 5px 30px rgba($brand-grey-light, .2);
|
||||
padding: 0 $spacer / 2 $spacer / 2;
|
||||
max-width: 100%;
|
||||
|
||||
@media (min-width: $screen-md) {
|
||||
max-width: $screen-sm;
|
||||
padding: 0 $spacer $spacer;
|
||||
}
|
||||
}
|
||||
|
||||
.modal__close {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
-webkit-appearance: none;
|
||||
line-height: 1;
|
||||
font-size: $font-size-large;
|
||||
padding: 3px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: ($spacer/4);
|
||||
color: $brand-grey;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
// Prevent background scrolling when modal is open
|
||||
.isModalOpen {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.modal__title {
|
||||
font-size: $font-size-h4;
|
||||
margin-top: $spacer / 2;
|
||||
margin-bottom: $spacer / 2;
|
||||
margin-left: -($spacer / 2);
|
||||
margin-right: -($spacer / 2);
|
||||
border-bottom: 1px solid rgba($brand-grey-light, .4);
|
||||
padding: 0 $spacer;
|
||||
padding-bottom: ($spacer/2);
|
||||
|
||||
@media (min-width: $screen-md) {
|
||||
margin-left: -($spacer);
|
||||
margin-right: -($spacer);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Overlay/content animations
|
||||
//
|
||||
@keyframes fadein {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeout {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
60
src/components/molecules/ModalThanks.jsx
Normal file
60
src/components/molecules/ModalThanks.jsx
Normal file
@ -0,0 +1,60 @@
|
||||
import React from 'react'
|
||||
import { StaticQuery, graphql } from 'gatsby'
|
||||
import { QRCode } from 'react-qr-svg'
|
||||
import Clipboard from 'react-clipboard.js'
|
||||
|
||||
import Modal from '../atoms/Modal'
|
||||
import IconClipboard from '../svg/Clipboard'
|
||||
import styles from './ModalThanks.module.scss'
|
||||
|
||||
const ModalThanks = ({ ...props }) => (
|
||||
<StaticQuery
|
||||
query={graphql`
|
||||
query {
|
||||
contentYaml {
|
||||
author {
|
||||
bitcoin
|
||||
ether
|
||||
}
|
||||
}
|
||||
}
|
||||
`}
|
||||
render={data => {
|
||||
const { author } = data.contentYaml
|
||||
|
||||
return (
|
||||
<Modal
|
||||
{...props}
|
||||
contentLabel="Say thanks with Bitcoin or Ether"
|
||||
title="Say thanks"
|
||||
>
|
||||
<div className={styles.modalThanks}>
|
||||
{Object.keys(author).map((address, i) => (
|
||||
<div key={i} className={styles.coin}>
|
||||
<h4>{address}</h4>
|
||||
<QRCode
|
||||
bgColor="transparent"
|
||||
fgColor="#6b7f88"
|
||||
level="Q"
|
||||
style={{ width: 150 }}
|
||||
value={author[address]}
|
||||
/>
|
||||
<pre>
|
||||
<code>{author[address]}</code>
|
||||
<Clipboard
|
||||
data-clipboard-text={author[address]}
|
||||
button-title="Copy to clipboard"
|
||||
>
|
||||
<IconClipboard />
|
||||
</Clipboard>
|
||||
</pre>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
export default ModalThanks
|
69
src/components/molecules/ModalThanks.module.scss
Normal file
69
src/components/molecules/ModalThanks.module.scss
Normal file
@ -0,0 +1,69 @@
|
||||
@import 'variables';
|
||||
|
||||
.modalThanks {
|
||||
@media (min-width: $screen-sm) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
}
|
||||
|
||||
.coin {
|
||||
margin-top: $spacer;
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
width: 48%;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ import { StaticQuery, graphql } from 'gatsby'
|
||||
import Img from 'gatsby-image'
|
||||
|
||||
import Container from '../atoms/Container'
|
||||
import ModalThanks from '../molecules/ModalThanks'
|
||||
|
||||
import Twitter from '../svg/Twitter'
|
||||
import Github from '../svg/Github'
|
||||
import Facebook from '../svg/Facebook'
|
||||
@ -16,7 +18,14 @@ class Footer extends PureComponent {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = { year: null }
|
||||
this.state = {
|
||||
year: null,
|
||||
showModal: false
|
||||
}
|
||||
}
|
||||
|
||||
toggleModal = () => {
|
||||
this.setState({ showModal: !this.state.showModal })
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@ -46,7 +55,6 @@ class Footer extends PureComponent {
|
||||
}
|
||||
}
|
||||
bitcoin
|
||||
ether
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -125,11 +133,20 @@ class Footer extends PureComponent {
|
||||
<Github />
|
||||
View source
|
||||
</a>
|
||||
<a href="#" className={styles.btc}>
|
||||
<a
|
||||
href="#"
|
||||
className={styles.btc}
|
||||
onClick={this.toggleModal}
|
||||
>
|
||||
<Bitcoin />
|
||||
<code>{author.bitcoin}</code>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<ModalThanks
|
||||
isOpen={this.state.showModal}
|
||||
handleCloseModal={this.toggleModal}
|
||||
/>
|
||||
</section>
|
||||
</Container>
|
||||
</footer>
|
||||
|
@ -37,6 +37,7 @@ pre {
|
||||
background-color: $code-bg;
|
||||
margin-left: -($spacer);
|
||||
margin-right: -($spacer);
|
||||
border-radius: $border-radius;
|
||||
|
||||
// make 'em scrollable
|
||||
overflow: scroll;
|
||||
@ -59,6 +60,7 @@ pre {
|
||||
overflow-wrap: normal;
|
||||
word-wrap: normal;
|
||||
word-break: normal;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,14 @@
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
border: 0;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Post/photo teaser
|
||||
|
Loading…
Reference in New Issue
Block a user