1
0
mirror of https://github.com/kremalicious/blog.git synced 2024-12-23 01:30:01 +01:00

add thank you modal

This commit is contained in:
Matthias Kretschmann 2018-08-14 21:12:30 +02:00
parent 0ddc52425b
commit 62d98d0c19
Signed by: m
GPG Key ID: 606EEEF3C479A91F
9 changed files with 310 additions and 11 deletions

View File

@ -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",

View File

@ -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;

View 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}>
&times;
</button>
</ReactModal>
)
}
}
Modal.propTypes = {
title: PropTypes.string,
isOpen: PropTypes.bool,
handleCloseModal: PropTypes.func.isRequired,
children: PropTypes.node.isRequired
}
export default Modal

View 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;
}
}

View 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

View 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;
}
}
}
}

View File

@ -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>

View File

@ -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;
}
}

View File

@ -18,6 +18,14 @@
&:first-child {
padding-top: 0;
}
&:only-child {
border: 0;
&::before {
display: none;
}
}
}
// Post/photo teaser