mirror of
https://github.com/kremalicious/blog.git
synced 2024-12-22 17:23:50 +01:00
Merge pull request #180 from kremalicious/refactor
refactor & restyling
This commit is contained in:
commit
f928e13207
18
README.md
18
README.md
@ -68,12 +68,12 @@ As a fallback, QR codes are generated with [react-qr-svg](https://github.com/no2
|
||||
|
||||
If you want to know how this works, have a look at the respective components under
|
||||
|
||||
- [`src/components/Web3Donation/index.jsx`](src/components/Web3Donation/index.jsx)
|
||||
- [`src/components/Web3Donation/Account.jsx`](src/components/Web3Donation/Account.jsx)
|
||||
- [`src/components/Web3Donation/InputGroup.jsx`](src/components/Web3Donation/InputGroup.jsx)
|
||||
- [`src/components/Web3Donation/Conversion.jsx`](src/components/Web3Donation/Conversion.jsx)
|
||||
- [`src/components/Web3Donation/Alerts.jsx`](src/components/Web3Donation/Alerts.jsx)
|
||||
- [`src/components/Web3Donation/utils.jsx`](src/components/Web3Donation/utils.jsx)
|
||||
- [`src/components/molecules/Web3Donation/index.jsx`](src/components/molecules/Web3Donation/index.jsx)
|
||||
- [`src/components/molecules/Web3Donation/Account.jsx`](src/components/molecules/Web3Donation/Account.jsx)
|
||||
- [`src/components/molecules/Web3Donation/InputGroup.jsx`](src/components/molecules/Web3Donation/InputGroup.jsx)
|
||||
- [`src/components/molecules/Web3Donation/Conversion.jsx`](src/components/molecules/Web3Donation/Conversion.jsx)
|
||||
- [`src/components/molecules/Web3Donation/Alerts.jsx`](src/components/molecules/Web3Donation/Alerts.jsx)
|
||||
- [`src/components/molecules/Web3Donation/utils.jsx`](src/components/molecules/Web3Donation/utils.jsx)
|
||||
- [`src/components/atoms/Qr.jsx`](src/components/atoms/Qr.jsx)
|
||||
|
||||
### 🔍 Search
|
||||
@ -84,9 +84,9 @@ A global search is provided with [gatsby-plugin-lunr](https://github.com/humanse
|
||||
|
||||
If you want to know how this works, have a look at the respective components under
|
||||
|
||||
- [`src/components/Search/Search.jsx`](src/components/Search/Search.jsx)
|
||||
- [`src/components/Search/SearchResults.jsx`](src/components/Search/SearchResults.jsx)
|
||||
- more in [`src/components/Search/`](src/components/Search/)
|
||||
- [`src/components/molecules/Search/Search.jsx`](src/components/molecules/Search/Search.jsx)
|
||||
- [`src/components/molecules/Search/SearchResults.jsx`](src/components/molecules/Search/SearchResults.jsx)
|
||||
- more in [`src/components/molecules/Search/`](src/components/molecules/Search/)
|
||||
|
||||
### 🕸 Related Posts
|
||||
|
||||
|
@ -140,9 +140,9 @@ So it's a pretty good idea to make this backwards compatible with some quick if
|
||||
if ( (function_exists('has_post_thumbnail')) && (has_post_thumbnail()) ) {
|
||||
the_post_thumbnail();
|
||||
} else {
|
||||
$postimage = get_post_meta($post->ID, 'post-image', true);
|
||||
if ($postimage) {
|
||||
echo '<img src="'.$postimage.'" alt="" />';
|
||||
$Image = get_post_meta($post->ID, 'post-image', true);
|
||||
if ($Image) {
|
||||
echo '<img src="'.$Image.'" alt="" />';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -10,6 +10,8 @@ tags:
|
||||
- goodies
|
||||
- gatsby
|
||||
- matomo
|
||||
|
||||
featured: true
|
||||
---
|
||||
|
||||
Plugin for [Gatsby](https://www.gatsbyjs.org) to add tracking with the open-source analytics platform [Matomo](https://matomo.org) (formerly Piwik) onto a site, prioritizing user experience & privacy with sensible defaults.
|
||||
|
@ -35,7 +35,6 @@ module.exports = {
|
||||
options: {
|
||||
maxWidth: 630,
|
||||
quality: 80,
|
||||
withWebp: true,
|
||||
linkImagesToOriginal: true,
|
||||
showCaptions: true,
|
||||
backgroundColor: 'none',
|
||||
|
@ -7,7 +7,7 @@ const redirects = [
|
||||
]
|
||||
|
||||
exports.generatePostPages = (createPage, posts, numPages) => {
|
||||
const postTemplate = path.resolve('src/templates/Post.tsx')
|
||||
const postTemplate = path.resolve('src/templates/Post/index.tsx')
|
||||
|
||||
// Create Post pages
|
||||
posts.forEach(post => {
|
||||
|
40
package.json
40
package.json
@ -35,18 +35,18 @@
|
||||
"dms2dec": "^1.1.0",
|
||||
"fast-exif": "^1.0.1",
|
||||
"fraction.js": "^4.0.12",
|
||||
"gatsby": "^2.17.1",
|
||||
"gatsby-image": "^2.2.29",
|
||||
"gatsby": "^2.17.6",
|
||||
"gatsby-image": "^2.2.30",
|
||||
"gatsby-plugin-catch-links": "^2.1.15",
|
||||
"gatsby-plugin-feed": "^2.3.19",
|
||||
"gatsby-plugin-lunr": "^1.5.2",
|
||||
"gatsby-plugin-manifest": "^2.2.23",
|
||||
"gatsby-plugin-manifest": "^2.2.25",
|
||||
"gatsby-plugin-matomo": "^0.7.2",
|
||||
"gatsby-plugin-meta-redirect": "^1.1.1",
|
||||
"gatsby-plugin-offline": "^3.0.16",
|
||||
"gatsby-plugin-offline": "^3.0.17",
|
||||
"gatsby-plugin-react-helmet": "^3.1.13",
|
||||
"gatsby-plugin-sass": "^2.1.20",
|
||||
"gatsby-plugin-sharp": "^2.2.32",
|
||||
"gatsby-plugin-sharp": "^2.2.34",
|
||||
"gatsby-plugin-sitemap": "^2.2.19",
|
||||
"gatsby-plugin-svgr": "^2.0.2",
|
||||
"gatsby-plugin-typescript": "^2.1.15",
|
||||
@ -58,10 +58,10 @@
|
||||
"gatsby-remark-images": "^3.1.28",
|
||||
"gatsby-remark-smartypants": "^2.1.14",
|
||||
"gatsby-remark-vscode": "^1.2.0",
|
||||
"gatsby-source-filesystem": "^2.1.33",
|
||||
"gatsby-source-graphql": "^2.1.20",
|
||||
"gatsby-transformer-remark": "^2.6.30",
|
||||
"gatsby-transformer-sharp": "^2.3.0",
|
||||
"gatsby-source-filesystem": "^2.1.35",
|
||||
"gatsby-source-graphql": "^2.1.21",
|
||||
"gatsby-transformer-remark": "^2.6.32",
|
||||
"gatsby-transformer-sharp": "^2.3.1",
|
||||
"graphql": "^14.5.8",
|
||||
"intersection-observer": "^0.7.0",
|
||||
"js-scrypt": "^0.2.0",
|
||||
@ -73,7 +73,7 @@
|
||||
"react-clipboard.js": "^2.0.13",
|
||||
"react-dom": "^16.11.0",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-modal": "^3.10.1",
|
||||
"react-modal": "^3.11.1",
|
||||
"react-pose": "^4.0.9",
|
||||
"react-qr-svg": "^2.2.1",
|
||||
"react-transition-group": "^4.3.0",
|
||||
@ -88,25 +88,25 @@
|
||||
"@babel/preset-env": "^7.6.3",
|
||||
"@babel/preset-typescript": "^7.6.0",
|
||||
"@svgr/webpack": "^4.3.3",
|
||||
"@testing-library/jest-dom": "^4.1.2",
|
||||
"@testing-library/jest-dom": "^4.2.0",
|
||||
"@testing-library/react": "^9.3.0",
|
||||
"@types/classnames": "^2.2.9",
|
||||
"@types/jest": "^24.0.19",
|
||||
"@types/jest": "^24.0.20",
|
||||
"@types/lunr": "^2.3.2",
|
||||
"@types/node": "^12.11.5",
|
||||
"@types/react": "^16.9.9",
|
||||
"@types/react-dom": "^16.9.2",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/react": "^16.9.11",
|
||||
"@types/react-dom": "^16.9.3",
|
||||
"@types/react-helmet": "^5.0.13",
|
||||
"@types/react-modal": "^3.10.0",
|
||||
"@types/react-transition-group": "^4.2.3",
|
||||
"@types/shortid": "0.0.29",
|
||||
"@types/web3": "^1.0.20",
|
||||
"@typescript-eslint/eslint-plugin": "^2.5.0",
|
||||
"@typescript-eslint/parser": "^2.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.6.0",
|
||||
"@typescript-eslint/parser": "^2.6.0",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^24.9.0",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-prettier": "^6.4.0",
|
||||
"eslint": "^6.6.0",
|
||||
"eslint-config-prettier": "^6.5.0",
|
||||
"eslint-loader": "^3.0.2",
|
||||
"eslint-plugin-graphql": "^3.1.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
@ -117,7 +117,7 @@
|
||||
"jest": "^24.9.0",
|
||||
"markdownlint-cli": "^0.19.0",
|
||||
"node-iptc": "^1.0.5",
|
||||
"node-sass": "^4.12.0",
|
||||
"node-sass": "^4.13.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"ora": "^4.0.0",
|
||||
"pify": "^4.0.1",
|
||||
|
30
src/@types/Image.d.ts
vendored
Normal file
30
src/@types/Image.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import { FixedObject, FluidObject } from 'gatsby-image'
|
||||
|
||||
export interface ImageProps {
|
||||
title?: string
|
||||
fluid?: FluidObject
|
||||
fixed?: FixedObject
|
||||
alt: string
|
||||
original?: { src: string }
|
||||
}
|
||||
|
||||
export interface ImageNode {
|
||||
childImageSharp: ImageProps
|
||||
fields: {
|
||||
exif: Exif
|
||||
}
|
||||
}
|
||||
|
||||
export interface Exif {
|
||||
iso: string
|
||||
model: string
|
||||
fstop: string
|
||||
shutterspeed: string
|
||||
focalLength: string
|
||||
lensModel: string
|
||||
exposure: string
|
||||
gps: {
|
||||
latitude: string
|
||||
longitude: string
|
||||
}
|
||||
}
|
32
src/@types/Post.d.ts
vendored
Normal file
32
src/@types/Post.d.ts
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
import { ImageNode } from './Image'
|
||||
|
||||
export interface Fields {
|
||||
slug: string
|
||||
date: string
|
||||
githubLink?: string
|
||||
}
|
||||
|
||||
export interface Frontmatter {
|
||||
title: string
|
||||
type?: string
|
||||
description?: string
|
||||
image?: ImageNode
|
||||
author?: string
|
||||
updated?: string
|
||||
tags?: string[]
|
||||
linkurl?: string
|
||||
style?: {
|
||||
publicURL?: string
|
||||
}
|
||||
changelog?: string
|
||||
}
|
||||
|
||||
export interface Post {
|
||||
id?: string
|
||||
html?: string
|
||||
excerpt?: string
|
||||
frontmatter: Frontmatter
|
||||
fields?: Fields
|
||||
rawMarkdownBody?: string
|
||||
fileAbsolutePath?: string
|
||||
}
|
53
src/@types/PostMetadata.d.ts
vendored
53
src/@types/PostMetadata.d.ts
vendored
@ -1,53 +0,0 @@
|
||||
import { FluidObject } from 'gatsby-image'
|
||||
|
||||
export interface PostMetadataFields {
|
||||
slug: string
|
||||
date: string
|
||||
githubLink: string
|
||||
}
|
||||
|
||||
export interface PostMetadataImageExif {
|
||||
iso: string
|
||||
model: string
|
||||
fstop: string
|
||||
shutterspeed: string
|
||||
focalLength: string
|
||||
lensModel: string
|
||||
exposure: string
|
||||
gps: {
|
||||
latitude: string
|
||||
longitude: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface PostMetadataImage {
|
||||
childImageSharp: { fluid: FluidObject }
|
||||
fields: {
|
||||
exif: PostMetadataImageExif
|
||||
}
|
||||
}
|
||||
|
||||
export interface PostMetadataFrontmatter {
|
||||
type?: string
|
||||
title: string
|
||||
description?: string
|
||||
image?: PostMetadataImage
|
||||
author?: string
|
||||
updated?: string
|
||||
tags?: string[]
|
||||
linkurl?: string
|
||||
style?: {
|
||||
publicURL?: string
|
||||
}
|
||||
changelog?: string
|
||||
}
|
||||
|
||||
export interface PostMetadata {
|
||||
id?: string
|
||||
html?: string
|
||||
excerpt?: string
|
||||
frontmatter: PostMetadataFrontmatter
|
||||
fields?: PostMetadataFields
|
||||
rawMarkdownBody?: string
|
||||
fileAbsolutePath?: string
|
||||
}
|
@ -14,7 +14,7 @@ export interface Author {
|
||||
ether: string
|
||||
}
|
||||
|
||||
export interface SiteMetadata {
|
||||
export interface Site {
|
||||
siteTitle: string
|
||||
siteTitleShort: string
|
||||
siteDescription: string
|
@ -1,83 +0,0 @@
|
||||
import React, { useState } from 'react'
|
||||
import ModalThanks from '../molecules/ModalThanks'
|
||||
import styles from './PostActions.module.scss'
|
||||
|
||||
import { ReactComponent as Twitter } from '../../images/twitter.svg'
|
||||
import { ReactComponent as Bitcoin } from '../../images/bitcoin.svg'
|
||||
import { ReactComponent as GitHub } from '../../images/github.svg'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
|
||||
const ActionContent = ({ title, text }: { title: string; text: string }) => (
|
||||
<>
|
||||
<h1 className={styles.actionTitle}>{title}</h1>
|
||||
<p className={styles.actionText}>{text}</p>
|
||||
</>
|
||||
)
|
||||
|
||||
const ActionTwitter = ({ slug }: { slug: string }) => {
|
||||
const { siteUrl } = useSiteMetadata()
|
||||
|
||||
return (
|
||||
<a
|
||||
className={styles.action}
|
||||
href={`https://twitter.com/intent/tweet?text=@kremalicious&url=${siteUrl}${slug}`}
|
||||
>
|
||||
<Twitter />
|
||||
<ActionContent title="Have a comment?" text="Hit me up @kremalicious" />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
const ActionCrypto = ({ toggleModal }: { toggleModal(): void }) => (
|
||||
<button className={styles.action} onClick={toggleModal}>
|
||||
<Bitcoin />
|
||||
<ActionContent
|
||||
title="Found something useful?"
|
||||
text="Say thanks with Bitcoins or Ether"
|
||||
/>
|
||||
</button>
|
||||
)
|
||||
|
||||
const ActionGitHub = ({ githubLink }: { githubLink: string }) => (
|
||||
<a className={styles.action} href={githubLink}>
|
||||
<GitHub />
|
||||
<ActionContent
|
||||
title="Edit on GitHub"
|
||||
text="Contribute to this post on GitHub"
|
||||
/>
|
||||
</a>
|
||||
)
|
||||
|
||||
export default function PostActions({
|
||||
slug,
|
||||
githubLink
|
||||
}: {
|
||||
slug: string
|
||||
githubLink: string
|
||||
}) {
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
|
||||
const toggleModal = () => {
|
||||
setShowModal(!showModal)
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className={styles.actions}>
|
||||
<div>
|
||||
<ActionTwitter slug={slug} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ActionCrypto toggleModal={toggleModal} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<ActionGitHub githubLink={githubLink} />
|
||||
</div>
|
||||
|
||||
{showModal && (
|
||||
<ModalThanks isOpen={showModal} handleCloseModal={toggleModal} />
|
||||
)}
|
||||
</aside>
|
||||
)
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
import React from 'react'
|
||||
import Image from '../atoms/Image'
|
||||
import styles from './PostImage.module.scss'
|
||||
import { FluidObject, FixedObject } from 'gatsby-image'
|
||||
|
||||
interface PostImageProps {
|
||||
title?: string
|
||||
fluid?: FluidObject
|
||||
fixed?: FixedObject
|
||||
alt: string
|
||||
}
|
||||
|
||||
const PostImage = ({ title, fluid, fixed, alt }: PostImageProps) => (
|
||||
<figure className={styles.postImage}>
|
||||
<Image fluid={fluid} fixed={fixed} alt={alt} />
|
||||
{title && (
|
||||
<figcaption className={styles.postImageTitle}>{title}</figcaption>
|
||||
)}
|
||||
</figure>
|
||||
)
|
||||
|
||||
export default PostImage
|
@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import ExifMap from './ExifMap'
|
||||
import styles from './Exif.module.scss'
|
||||
import { PostMetadataImageExif } from '../../@types/PostMetadata'
|
||||
import { Exif as ExifMeta } from '../../@types/Image'
|
||||
|
||||
export default function Exif({ exif }: { exif: PostMetadataImageExif }) {
|
||||
export default function Exif({ exif }: { exif: ExifMeta }) {
|
||||
const { iso, model, fstop, shutterspeed, focalLength, exposure, gps } = exif
|
||||
|
||||
return (
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
@media (min-width: 940px) {
|
||||
max-width: 940px;
|
||||
border-radius: 0.25rem;
|
||||
border-radius: $border-radius;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
@ -1,30 +1,24 @@
|
||||
import React from 'react'
|
||||
import { graphql } from 'gatsby'
|
||||
import Img, { FixedObject, FluidObject } from 'gatsby-image'
|
||||
import Img from 'gatsby-image'
|
||||
import styles from './Image.module.scss'
|
||||
import { ImageProps } from '../../@types/Image'
|
||||
|
||||
export default function Image({
|
||||
fluid,
|
||||
fixed,
|
||||
alt
|
||||
}: {
|
||||
fluid?: FluidObject
|
||||
fixed?: FixedObject
|
||||
alt: string
|
||||
}) {
|
||||
return (
|
||||
<Img
|
||||
className={styles.imageWrap}
|
||||
backgroundColor="transparent"
|
||||
fluid={fluid}
|
||||
fixed={fixed}
|
||||
alt={alt}
|
||||
/>
|
||||
)
|
||||
}
|
||||
export const Image = ({ fluid, fixed, alt }: ImageProps) => (
|
||||
<Img
|
||||
className={styles.imageWrap}
|
||||
backgroundColor="transparent"
|
||||
fluid={fluid}
|
||||
fixed={fixed}
|
||||
alt={alt}
|
||||
/>
|
||||
)
|
||||
|
||||
export const imageSizeDefault = graphql`
|
||||
fragment ImageFluid on ImageSharp {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fluid(maxWidth: 940, quality: 85) {
|
||||
...GatsbyImageSharpFluid_withWebp_noBase64
|
||||
}
|
||||
@ -33,7 +27,10 @@ export const imageSizeDefault = graphql`
|
||||
|
||||
export const imageSizeThumb = graphql`
|
||||
fragment ImageFluidThumb on ImageSharp {
|
||||
fluid(maxWidth: 200, maxHeight: 85, quality: 85, cropFocus: CENTER) {
|
||||
original {
|
||||
src
|
||||
}
|
||||
fluid(maxWidth: 400, maxHeight: 170, quality: 85, cropFocus: CENTER) {
|
||||
...GatsbyImageSharpFluid_withWebp_noBase64
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
const query = graphql`
|
||||
query {
|
||||
@ -117,7 +117,7 @@ export default function SEO({
|
||||
slug,
|
||||
postSEO
|
||||
}: {
|
||||
post?: PostMetadata
|
||||
post?: Post
|
||||
slug?: string
|
||||
postSEO?: boolean
|
||||
}) {
|
||||
|
@ -2,26 +2,16 @@
|
||||
@import 'mixins';
|
||||
|
||||
.featured {
|
||||
@include breakoutviewport;
|
||||
@include divider;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
padding-left: $spacer;
|
||||
padding-right: $spacer;
|
||||
margin-bottom: -($spacer);
|
||||
padding-bottom: $spacer * $line-height;
|
||||
|
||||
@media (min-width: $screen-xs) {
|
||||
padding-bottom: $spacer * 3;
|
||||
margin-top: $spacer * $line-height;
|
||||
}
|
||||
display: grid;
|
||||
gap: $spacer;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
padding-bottom: $spacer * 3;
|
||||
margin-bottom: -($spacer / 2);
|
||||
|
||||
@media (min-width: $screen-md) {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
justify-content: initial;
|
||||
@include breakoutviewport;
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,28 +34,6 @@
|
||||
|
||||
.featuredItem {
|
||||
position: relative;
|
||||
max-width: 12rem;
|
||||
flex: 0 0 48%;
|
||||
margin-bottom: $spacer / 2;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-xs) {
|
||||
flex: 1;
|
||||
max-width: none;
|
||||
margin-left: $spacer / 2;
|
||||
|
||||
&:last-child {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
|
@ -1,17 +1,17 @@
|
||||
import React from 'react'
|
||||
import { Link, graphql, useStaticQuery } from 'gatsby'
|
||||
import Image from '../atoms/Image'
|
||||
import { Image } from '../atoms/Image'
|
||||
import styles from './Featured.module.scss'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
function FeaturedPure({
|
||||
data
|
||||
}: {
|
||||
data: { allMarkdownRemark: { edges: [{ node: PostMetadata }] } }
|
||||
data: { allMarkdownRemark: { edges: [{ node: Post }] } }
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.featured}>
|
||||
{data.allMarkdownRemark.edges.map(({ node }: { node: PostMetadata }) => {
|
||||
{data.allMarkdownRemark.edges.map(({ node }: { node: Post }) => {
|
||||
const { title, image } = node.frontmatter
|
||||
const { slug } = node.fields
|
||||
|
||||
|
@ -4,7 +4,7 @@ import { Link } from 'gatsby'
|
||||
import Hamburger from '../atoms/Hamburger'
|
||||
import styles from './Menu.module.scss'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
import { MenuItem } from '../../@types/SiteMetadata'
|
||||
import { MenuItem } from '../../@types/Site'
|
||||
|
||||
export default function Menu() {
|
||||
const [menuOpen, setMenuOpen] = useState(false)
|
||||
|
@ -52,8 +52,6 @@
|
||||
}
|
||||
|
||||
.title {
|
||||
@include heading-band;
|
||||
|
||||
font-size: $font-size-h3;
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,8 @@
|
||||
import React, { useState } from 'react'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import PostTeaser from '../Post/PostTeaser'
|
||||
import PostTeaser from '../../templates/Post/PostTeaser'
|
||||
import styles from './RelatedPosts.module.scss'
|
||||
import {
|
||||
PostMetadata,
|
||||
PostMetadataFrontmatter
|
||||
} from '../../@types/PostMetadata'
|
||||
import { Post, Frontmatter } from '../../@types/Post'
|
||||
|
||||
const query = graphql`
|
||||
query {
|
||||
@ -36,11 +33,11 @@ const query = graphql`
|
||||
`
|
||||
|
||||
function postsWithDataFilter(
|
||||
posts: [{ node: PostMetadata }],
|
||||
key: keyof PostMetadataFrontmatter,
|
||||
posts: [{ node: Post }],
|
||||
key: keyof Frontmatter,
|
||||
valuesToFind: string[]
|
||||
) {
|
||||
const newArray = posts.filter(({ node }: { node: PostMetadata }) => {
|
||||
const newArray = posts.filter(({ node }: { node: Post }) => {
|
||||
const frontmatterKey = node.frontmatter[key] as []
|
||||
|
||||
if (
|
||||
@ -54,7 +51,7 @@ function postsWithDataFilter(
|
||||
}
|
||||
|
||||
function photosWithDataFilter(posts: []) {
|
||||
const newArray = posts.filter((post: { node: PostMetadata }) => {
|
||||
const newArray = posts.filter((post: { node: Post }) => {
|
||||
const { fileAbsolutePath } = post.node
|
||||
|
||||
if (fileAbsolutePath.includes('content/photos')) {
|
||||
@ -93,7 +90,7 @@ export default function RelatedPosts({
|
||||
{filteredPosts
|
||||
.sort(() => 0.5 - Math.random())
|
||||
.slice(0, 6)
|
||||
.map(({ node }: { node: PostMetadata }) => (
|
||||
.map(({ node }: { node: Post }) => (
|
||||
<PostTeaser key={node.id} post={node} />
|
||||
))}
|
||||
</ul>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import { ReactComponent as SearchIcon } from '../../images/magnifying-glass.svg'
|
||||
import { ReactComponent as SearchIcon } from '../../../images/magnifying-glass.svg'
|
||||
import styles from './SearchButton.module.scss'
|
||||
|
||||
const SearchButton = (props: any) => (
|
@ -1,7 +1,7 @@
|
||||
@import 'variables';
|
||||
|
||||
.searchInput {
|
||||
composes: input from '../atoms/Input.module.scss';
|
||||
composes: input from '../../atoms/Input.module.scss';
|
||||
|
||||
&::-webkit-search-cancel-button {
|
||||
display: none;
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import Input from '../atoms/Input'
|
||||
import Input from '../../atoms/Input'
|
||||
import styles from './SearchInput.module.scss'
|
||||
|
||||
export default function SearchInput({
|
@ -1,11 +1,11 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { graphql, useStaticQuery } from 'gatsby'
|
||||
import Container from '../atoms/Container'
|
||||
import PostTeaser from '../Post/PostTeaser'
|
||||
import Container from '../../atoms/Container'
|
||||
import PostTeaser from '../../../templates/Post/PostTeaser'
|
||||
import SearchResultsEmpty from './SearchResultsEmpty'
|
||||
import styles from './SearchResults.module.scss'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../../@types/Post'
|
||||
|
||||
export interface Results {
|
||||
slug: string
|
||||
@ -40,7 +40,7 @@ function SearchResultsPure({
|
||||
toggleSearch,
|
||||
posts
|
||||
}: {
|
||||
posts: [{ node: PostMetadata }]
|
||||
posts: [{ node: Post }]
|
||||
searchQuery: string
|
||||
results: Results[]
|
||||
toggleSearch(): void
|
||||
@ -53,10 +53,9 @@ function SearchResultsPure({
|
||||
{results.map((page: { slug: string }) =>
|
||||
posts
|
||||
.filter(
|
||||
({ node }: { node: PostMetadata }) =>
|
||||
node.fields.slug === page.slug
|
||||
({ node }: { node: Post }) => node.fields.slug === page.slug
|
||||
)
|
||||
.map(({ node }: { node: PostMetadata }) => (
|
||||
.map(({ node }: { node: Post }) => (
|
||||
<PostTeaser
|
||||
key={page.slug}
|
||||
post={node}
|
@ -16,44 +16,34 @@ export const alertMessages = (
|
||||
success: 'Confirmed. You are awesome, thanks!'
|
||||
})
|
||||
|
||||
export default function Alerts({
|
||||
transactionHash,
|
||||
message
|
||||
}: {
|
||||
transactionHash: string | null
|
||||
message: { text?: string; status?: string } | null
|
||||
}) {
|
||||
const constructMessage = () => {
|
||||
let messageOutput
|
||||
interface AlertProps {
|
||||
transactionHash: string
|
||||
message?: { text?: string; status?: string }
|
||||
}
|
||||
|
||||
if (transactionHash) {
|
||||
messageOutput =
|
||||
message &&
|
||||
message.text +
|
||||
'<br />' +
|
||||
alertMessages(null, transactionHash).transaction
|
||||
} else {
|
||||
messageOutput = message && message.text
|
||||
}
|
||||
const constructMessage = (
|
||||
transactionHash: string,
|
||||
message?: { text?: string }
|
||||
) =>
|
||||
transactionHash
|
||||
? message &&
|
||||
message.text + '<br />' + alertMessages(null, transactionHash).transaction
|
||||
: message && message.text
|
||||
|
||||
return messageOutput
|
||||
}
|
||||
|
||||
const classes = () => {
|
||||
const { status } = message
|
||||
|
||||
if (status === 'success') {
|
||||
return styles.success
|
||||
} else if (status === 'error') {
|
||||
return styles.error
|
||||
}
|
||||
return styles.alert
|
||||
}
|
||||
const classes = (status: string) =>
|
||||
status === 'success'
|
||||
? styles.success
|
||||
: status === 'error'
|
||||
? styles.error
|
||||
: styles.alert
|
||||
|
||||
export default function Alerts({ transactionHash, message }: AlertProps) {
|
||||
return (
|
||||
<div
|
||||
className={classes()}
|
||||
dangerouslySetInnerHTML={{ __html: `${constructMessage()}` }}
|
||||
className={classes(message.status)}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `${constructMessage(transactionHash, message)}`
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import Input from '../atoms/Input'
|
||||
import Input from '../../atoms/Input'
|
||||
import Account from './Account'
|
||||
import Conversion from './Conversion'
|
||||
import styles from './InputGroup.module.scss'
|
@ -2,7 +2,7 @@ import React, { useState } from 'react'
|
||||
import Container from '../atoms/Container'
|
||||
import Vcard from '../molecules/Vcard'
|
||||
import ThemeSwitch from '../molecules/ThemeSwitch'
|
||||
import ModalThanks from '../molecules/ModalThanks'
|
||||
import ModalThanks from './ModalThanks'
|
||||
|
||||
import { ReactComponent as Github } from '../../images/github.svg'
|
||||
import { ReactComponent as Bitcoin } from '../../images/bitcoin.svg'
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'gatsby'
|
||||
import Container from '../atoms/Container'
|
||||
import Search from '../Search'
|
||||
import Search from '../molecules/Search'
|
||||
import Menu from '../molecules/Menu'
|
||||
import { ReactComponent as Logo } from '../../images/logo.svg'
|
||||
|
||||
|
@ -1,14 +1,26 @@
|
||||
import React, { lazy, Suspense } from 'react'
|
||||
import shortid from 'shortid'
|
||||
import { Author } from '../../@types/Site'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
|
||||
import Qr from '../atoms/Qr'
|
||||
import Modal from '../atoms/Modal'
|
||||
import styles from './ModalThanks.module.scss'
|
||||
|
||||
const Web3Donation = lazy(() => import('../Web3Donation'))
|
||||
const Qr = lazy(() => import('../atoms/Qr'))
|
||||
const Web3Donation = lazy(() => import('../molecules/Web3Donation'))
|
||||
|
||||
const Coin = ({ address, author }: { address: string; author: Author }) => (
|
||||
<div className={styles.coin}>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Qr title={address} address={(author as any)[address]} />
|
||||
</Suspense>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default function ModalThanks(props: any) {
|
||||
const { author } = useSiteMetadata()
|
||||
const coins = Object.keys(author).filter(
|
||||
key => key === 'bitcoin' || key === 'ether'
|
||||
)
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -26,15 +38,9 @@ export default function ModalThanks(props: any) {
|
||||
<p>Send Bitcoin or Ether from any wallet.</p>
|
||||
</header>
|
||||
|
||||
{Object.keys(author)
|
||||
.filter(key => key === 'bitcoin' || key === 'ether')
|
||||
.map((address: string, i: number) => (
|
||||
<div key={i} className={styles.coin}>
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Qr title={address} address={(author as any)[address]} />
|
||||
</Suspense>
|
||||
</div>
|
||||
))}
|
||||
{coins.map((address: string) => (
|
||||
<Coin key={shortid.generate()} address={address} author={author} />
|
||||
))}
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
@ -1,7 +1,7 @@
|
||||
import { useStaticQuery, graphql } from 'gatsby'
|
||||
import { SiteMetadata } from '../@types/SiteMetadata'
|
||||
import { Site } from '../@types/Site'
|
||||
|
||||
export function useSiteMetadata(): SiteMetadata {
|
||||
export function useSiteMetadata(): Site {
|
||||
const query = graphql`
|
||||
query {
|
||||
site {
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import { graphql, Link } from 'gatsby'
|
||||
import PostImage from '../components/Post/PostImage'
|
||||
import PostImage from '../templates/Post/PostImage'
|
||||
import Page from '../templates/Page'
|
||||
import styles from './goodies.module.scss'
|
||||
import { PostMetadata } from '../@types/PostMetadata'
|
||||
import { Post } from '../@types/Post'
|
||||
|
||||
const page = {
|
||||
frontmatter: {
|
||||
@ -13,7 +13,7 @@ const page = {
|
||||
}
|
||||
}
|
||||
|
||||
const GoodiesThumb = ({ post }: { post: PostMetadata }) => {
|
||||
const GoodiesThumb = ({ post }: { post: Post }) => {
|
||||
const { title, image } = post.frontmatter
|
||||
const { slug } = post.fields
|
||||
|
||||
@ -33,7 +33,7 @@ export default function Goodies({
|
||||
data,
|
||||
location
|
||||
}: {
|
||||
data: { goodies: { edges: [{ node: PostMetadata }] } }
|
||||
data: { goodies: { edges: [{ node: Post }] } }
|
||||
location: Location
|
||||
}) {
|
||||
return (
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import { graphql, Link } from 'gatsby'
|
||||
import Page from '../templates/Page'
|
||||
import PostImage from '../components/Post/PostImage'
|
||||
import PostImage from '../templates/Post/PostImage'
|
||||
import styles from './photos.module.scss'
|
||||
import { PostMetadata } from '../@types/PostMetadata'
|
||||
import { Post } from '../@types/Post'
|
||||
|
||||
const page = {
|
||||
frontmatter: {
|
||||
@ -12,7 +12,7 @@ const page = {
|
||||
}
|
||||
}
|
||||
|
||||
const PhotoThumb = ({ photo }: { photo: PostMetadata }) => {
|
||||
const PhotoThumb = ({ photo }: { photo: Post }) => {
|
||||
const { title, image } = photo.frontmatter
|
||||
const { slug } = photo.fields
|
||||
const { fluid } = image.childImageSharp
|
||||
@ -32,7 +32,7 @@ export default function Photos({
|
||||
data,
|
||||
location
|
||||
}: {
|
||||
data: { photos: { edges: [{ node: PostMetadata }] } }
|
||||
data: { photos: { edges: [{ node: Post }] } }
|
||||
location: Location
|
||||
}) {
|
||||
return (
|
||||
|
@ -1,32 +0,0 @@
|
||||
.gatsby-resp-image-figure,
|
||||
.gatsby-resp-image-wrapper {
|
||||
margin-bottom: $spacer;
|
||||
}
|
||||
|
||||
.anchor {
|
||||
margin-top: $spacer / 3;
|
||||
font-size: $font-size-large;
|
||||
color: $brand-grey-light;
|
||||
font-weight: 700;
|
||||
|
||||
span {
|
||||
transition: opacity 0.2s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
.anchor span {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.anchor span {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,57 +1,5 @@
|
||||
@import 'variables';
|
||||
|
||||
// Centering Blocks
|
||||
/////////////////////////////////////
|
||||
|
||||
@mixin aligncenter() {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
// Toggling content
|
||||
/////////////////////////////////////
|
||||
|
||||
// Hide from both screenreaders and browsers: h5bp.com/u
|
||||
@mixin hide() {
|
||||
display: none !important;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@mixin show() {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
// Hide only visually, but have it available for screenreaders: h5bp.com/v
|
||||
@mixin visuallyhidden() {
|
||||
border: 0;
|
||||
clip: rect(0 0 0 0);
|
||||
height: 1px;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
|
||||
// Extends the .visuallyhidden class to allow the
|
||||
// element to be focusable when navigated to via the keyboard: h5bp.com/p
|
||||
&.focusable:active,
|
||||
&.focusable:focus {
|
||||
clip: auto;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
overflow: visible;
|
||||
position: static;
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide visually and from screenreaders, but maintain layout
|
||||
@mixin invisible() {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
// CSS image replacement
|
||||
/////////////////////////////////////
|
||||
|
||||
@ -132,20 +80,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Heading band
|
||||
/////////////////////////////////////
|
||||
|
||||
@mixin heading-band() {
|
||||
display: inline-block;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
padding: ($spacer/2) $spacer ($spacer/2) 100%;
|
||||
margin-left: -100%;
|
||||
|
||||
:global(.dark) & {
|
||||
background: darken($body-background-color--dark, 2%);
|
||||
}
|
||||
}
|
||||
|
||||
// Layout breakout
|
||||
/////////////////////////////////////
|
||||
|
||||
|
@ -68,7 +68,7 @@ $font-family-monospace: 'Fira Code', 'Fira Mono', Menlo, Monaco, Consolas,
|
||||
|
||||
$font-family-headings: 'brandon-grotesque', 'Avenir Next', 'Helvetica Neue',
|
||||
Helvetica, Arial, sans-serif;
|
||||
$font-weight-headings: 500;
|
||||
$font-weight-headings: 700;
|
||||
$line-height-headings: 1.1;
|
||||
|
||||
$color-headings: $brand-main;
|
||||
@ -81,7 +81,7 @@ $spacer: ($font-size-base * $line-height);
|
||||
$padding-base-vertical: 0.75rem;
|
||||
$padding-base-horizontal: 1.25rem;
|
||||
|
||||
$border-radius: 3px;
|
||||
$border-radius: 0.25rem;
|
||||
|
||||
// Code
|
||||
/////////////////////////////////////
|
||||
|
@ -26,10 +26,7 @@ body {
|
||||
line-height: $line-height;
|
||||
color: $text-color;
|
||||
text-rendering: optimizeLegibility;
|
||||
letter-spacing: -0.01em;
|
||||
font-feature-settings: 'liga', 'kern';
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
min-height: 100vh;
|
||||
transition: background 0.4s $easing;
|
||||
background: $body-background-color;
|
||||
@ -105,20 +102,6 @@ a {
|
||||
// Headings
|
||||
/////////////////////////////////////
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
margin-top: $spacer * $line-height;
|
||||
margin-bottom: $spacer * 2;
|
||||
}
|
||||
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin-top: $spacer * $line-height;
|
||||
margin-bottom: $spacer;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: $font-size-h2;
|
||||
|
||||
@ -128,8 +111,6 @@ h1 {
|
||||
}
|
||||
|
||||
h2 {
|
||||
@include heading-band();
|
||||
|
||||
font-size: $font-size-h3;
|
||||
|
||||
@media (min-width: $screen-xs) {
|
||||
@ -174,7 +155,11 @@ h6 {
|
||||
font-family: $font-family-headings;
|
||||
line-height: $line-height-headings;
|
||||
font-weight: $font-weight-headings;
|
||||
letter-spacing: -0.02em;
|
||||
letter-spacing: -0.01em;
|
||||
margin-top: $spacer * $line-height;
|
||||
margin-bottom: $spacer;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
|
||||
// stylelint-disable no-descending-specificity
|
||||
&,
|
||||
@ -376,4 +361,3 @@ blockquote {
|
||||
@import 'code';
|
||||
@import 'buttons';
|
||||
@import 'alerts';
|
||||
@import 'content';
|
||||
|
@ -3,7 +3,7 @@ import { Helmet } from 'react-helmet'
|
||||
import SEO from '../components/atoms/SEO'
|
||||
import Layout from '../components/Layout'
|
||||
import styles from './Page.module.scss'
|
||||
import { PostMetadata } from '../@types/PostMetadata'
|
||||
import { Post } from '../@types/Post'
|
||||
|
||||
export default function Page({
|
||||
title,
|
||||
@ -16,7 +16,7 @@ export default function Page({
|
||||
children: any
|
||||
section?: string
|
||||
location?: Location
|
||||
post?: PostMetadata
|
||||
post?: Post
|
||||
}) {
|
||||
return (
|
||||
<>
|
||||
|
@ -1,26 +0,0 @@
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
.hentry {
|
||||
width: 100%;
|
||||
padding-top: $spacer;
|
||||
padding-bottom: $spacer * 3;
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
padding-bottom: $spacer;
|
||||
}
|
||||
}
|
||||
|
||||
.postImageWrap {
|
||||
@include breakoutviewport();
|
||||
|
||||
figure {
|
||||
max-width: none;
|
||||
margin-top: $spacer * 1.5;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
@ -9,32 +9,16 @@
|
||||
padding-top: $spacer;
|
||||
padding-bottom: $spacer;
|
||||
border-radius: $border-radius;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
display: grid;
|
||||
gap: $spacer / 2;
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
:global(.dark) & {
|
||||
background: darken($body-background-color--dark, 2%);
|
||||
}
|
||||
|
||||
> div {
|
||||
flex: 1 1 100%;
|
||||
border-bottom: 1px dashed rgba($brand-grey-light, 0.3);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
flex: 0 0 33%;
|
||||
border-bottom: 0;
|
||||
border-left: 1px dashed rgba($brand-grey-light, 0.3);
|
||||
|
||||
&:first-child {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
@ -66,9 +50,25 @@
|
||||
padding-right: $spacer;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
border-bottom: 1px dashed rgba($brand-grey-light, 0.3);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
border-bottom: 0;
|
||||
border-left: 1px dashed rgba($brand-grey-light, 0.3);
|
||||
|
||||
&:first-child {
|
||||
border-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
cursor: pointer;
|
||||
|
||||
.link,
|
||||
.actionTitle,
|
||||
.actionText {
|
74
src/templates/Post/PostActions.tsx
Normal file
74
src/templates/Post/PostActions.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import React, { useState } from 'react'
|
||||
import ModalThanks from '../../components/organisms/ModalThanks'
|
||||
import styles from './PostActions.module.scss'
|
||||
|
||||
import { ReactComponent as Twitter } from '../../images/twitter.svg'
|
||||
import { ReactComponent as Bitcoin } from '../../images/bitcoin.svg'
|
||||
import { ReactComponent as GitHub } from '../../images/github.svg'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
|
||||
interface ActionProps {
|
||||
title: string
|
||||
text: string
|
||||
url?: string
|
||||
onClick?(): void
|
||||
}
|
||||
|
||||
const Icon = ({ text }: { text: string }) =>
|
||||
text.includes('GitHub') ? (
|
||||
<GitHub />
|
||||
) : text.includes('Bitcoin') ? (
|
||||
<Bitcoin />
|
||||
) : (
|
||||
<Twitter />
|
||||
)
|
||||
|
||||
const Action = ({ title, text, url, onClick }: ActionProps) => {
|
||||
return (
|
||||
<a className={styles.action} href={url} onClick={onClick}>
|
||||
<Icon text={text} />
|
||||
<h1 className={styles.actionTitle}>{title}</h1>
|
||||
<p className={styles.actionText}>{text}</p>
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
export default function PostActions({
|
||||
slug,
|
||||
githubLink
|
||||
}: {
|
||||
slug: string
|
||||
githubLink: string
|
||||
}) {
|
||||
const { siteUrl } = useSiteMetadata()
|
||||
const [showModal, setShowModal] = useState(false)
|
||||
const urlTwitter = `https://twitter.com/intent/tweet?text=@kremalicious&url=${siteUrl}${slug}`
|
||||
|
||||
const toggleModal = () => {
|
||||
setShowModal(!showModal)
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className={styles.actions}>
|
||||
<Action
|
||||
title="Have a comment?"
|
||||
text="Hit me up @kremalicious"
|
||||
url={urlTwitter}
|
||||
/>
|
||||
<Action
|
||||
title="Found something useful?"
|
||||
text="Say thanks with Bitcoins or Ether"
|
||||
onClick={toggleModal}
|
||||
/>
|
||||
<Action
|
||||
title="Edit on GitHub"
|
||||
text="Contribute to this post on GitHub"
|
||||
url={githubLink}
|
||||
/>
|
||||
|
||||
{showModal && (
|
||||
<ModalThanks isOpen={showModal} handleCloseModal={toggleModal} />
|
||||
)}
|
||||
</aside>
|
||||
)
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import React from 'react'
|
||||
import Changelog from '../atoms/Changelog'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import Changelog from '../../components/atoms/Changelog'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
// Remove lead paragraph from content
|
||||
const PostContent = ({ post }: { post: PostMetadata }) => {
|
||||
const PostContent = ({ post }: { post: Post }) => {
|
||||
const separator = '<!-- more -->'
|
||||
const changelog = post.frontmatter.changelog
|
||||
|
@ -1,7 +1,7 @@
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
.postImageTitle {
|
||||
.imageTitle {
|
||||
transition: 0.1s ease-out;
|
||||
font-size: $font-size-h3;
|
||||
font-family: $font-family-headings;
|
||||
@ -9,7 +9,6 @@
|
||||
font-weight: $font-weight-headings;
|
||||
font-style: normal;
|
||||
text-align: left;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
top: 10%;
|
||||
@ -22,7 +21,7 @@
|
||||
transform: translate3d(0, -20px, 0);
|
||||
}
|
||||
|
||||
.postImage {
|
||||
.image {
|
||||
display: block;
|
||||
|
||||
a & {
|
||||
@ -31,7 +30,7 @@
|
||||
}
|
||||
|
||||
a:hover & {
|
||||
.postImageTitle {
|
||||
.imageTitle {
|
||||
opacity: 1;
|
||||
transform: translate3d(0, 0, 0);
|
||||
}
|
13
src/templates/Post/PostImage.tsx
Normal file
13
src/templates/Post/PostImage.tsx
Normal file
@ -0,0 +1,13 @@
|
||||
import React from 'react'
|
||||
import { Image } from '../../components/atoms/Image'
|
||||
import styles from './PostImage.module.scss'
|
||||
import { ImageProps } from '../../@types/Image'
|
||||
|
||||
const PostImage = ({ title, fluid, fixed, alt, original }: ImageProps) => (
|
||||
<figure className={styles.image} data-original={original && original.src}>
|
||||
<Image fluid={fluid} fixed={fixed} alt={alt} />
|
||||
{title && <figcaption className={styles.imageTitle}>{title}</figcaption>}
|
||||
</figure>
|
||||
)
|
||||
|
||||
export default PostImage
|
@ -1,10 +1,10 @@
|
||||
import React from 'react'
|
||||
import styles from './PostLead.module.scss'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
// Extract lead paragraph from content
|
||||
// Grab everything before more tag, or just first paragraph
|
||||
const PostLead = ({ post, index }: { post: PostMetadata; index?: boolean }) => {
|
||||
const PostLead = ({ post, index }: { post: Post; index?: boolean }) => {
|
||||
let lead
|
||||
const content = post.html
|
||||
const separator = '<!-- more -->'
|
@ -1,12 +1,12 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'gatsby'
|
||||
import slugify from 'slugify'
|
||||
import Time from '../atoms/Time'
|
||||
import Time from '../../components/atoms/Time'
|
||||
import { useSiteMetadata } from '../../hooks/use-site-metadata'
|
||||
import styles from './PostMeta.module.scss'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
export default function PostMeta({ post }: { post: PostMetadata }) {
|
||||
export default function PostMeta({ post }: { post: Post }) {
|
||||
const siteMeta = useSiteMetadata()
|
||||
const { author, updated, tags, type } = post.frontmatter
|
||||
const { date } = post.fields
|
@ -1,14 +1,14 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'gatsby'
|
||||
import Image from '../atoms/Image'
|
||||
import { Image } from '../../components/atoms/Image'
|
||||
import styles from './PostTeaser.module.scss'
|
||||
import { PostMetadata } from '../../@types/PostMetadata'
|
||||
import { Post } from '../../@types/Post'
|
||||
|
||||
export default function PostTeaser({
|
||||
post,
|
||||
toggleSearch
|
||||
}: {
|
||||
post: PostMetadata
|
||||
post: Post
|
||||
toggleSearch?: () => void
|
||||
}) {
|
||||
const { image, title } = post.frontmatter
|
63
src/templates/Post/index.module.scss
Normal file
63
src/templates/Post/index.module.scss
Normal file
@ -0,0 +1,63 @@
|
||||
@import 'variables';
|
||||
@import 'mixins';
|
||||
|
||||
.hentry {
|
||||
width: 100%;
|
||||
padding-top: $spacer;
|
||||
padding-bottom: $spacer * 3;
|
||||
|
||||
> a {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:only-child {
|
||||
padding-bottom: $spacer;
|
||||
}
|
||||
|
||||
.gatsby-resp-image-figure,
|
||||
.gatsby-resp-image-wrapper {
|
||||
margin-bottom: $spacer;
|
||||
}
|
||||
|
||||
:global(.anchor) {
|
||||
margin-top: $spacer / 3;
|
||||
font-size: $font-size-large;
|
||||
color: $brand-grey-light;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $link-color;
|
||||
}
|
||||
|
||||
span {
|
||||
transition: opacity 0.2s ease-out;
|
||||
}
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
:global(.anchor) span {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
:global(.anchor) span {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.imageWrap {
|
||||
@include breakoutviewport();
|
||||
|
||||
figure {
|
||||
max-width: none;
|
||||
margin-top: $spacer * 1.5;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
@ -1,19 +1,19 @@
|
||||
import React from 'react'
|
||||
import { Helmet } from 'react-helmet'
|
||||
import { graphql } from 'gatsby'
|
||||
import Layout from '../components/Layout'
|
||||
import PostImage from '../components/Post/PostImage'
|
||||
import PostTitle from '../components/Post/PostTitle'
|
||||
import PostLead from '../components/Post/PostLead'
|
||||
import PostContent from '../components/Post/PostContent'
|
||||
import PostActions from '../components/Post/PostActions'
|
||||
import PostLinkActions from '../components/Post/PostLinkActions'
|
||||
import SEO from '../components/atoms/SEO'
|
||||
import PostMeta from '../components/Post/PostMeta'
|
||||
import Exif from '../components/atoms/Exif'
|
||||
import RelatedPosts from '../components/molecules/RelatedPosts'
|
||||
import styles from './Post.module.scss'
|
||||
import { PostMetadata } from '../@types/PostMetadata'
|
||||
import Layout from '../../components/Layout'
|
||||
import PostImage from './PostImage'
|
||||
import PostTitle from './PostTitle'
|
||||
import PostLead from './PostLead'
|
||||
import PostContent from './PostContent'
|
||||
import PostActions from './PostActions'
|
||||
import PostLinkActions from './PostLinkActions'
|
||||
import SEO from '../../components/atoms/SEO'
|
||||
import PostMeta from './PostMeta'
|
||||
import Exif from '../../components/atoms/Exif'
|
||||
import RelatedPosts from '../../components/molecules/RelatedPosts'
|
||||
import styles from './index.module.scss'
|
||||
import { Post as PostMetadata } from '../../@types/Post'
|
||||
|
||||
export default function Post({
|
||||
data,
|
||||
@ -40,8 +40,12 @@ export default function Post({
|
||||
{type === 'post' && <PostLead post={post} />}
|
||||
{type === 'photo' && <PostContent post={post} />}
|
||||
{image && (
|
||||
<div className={styles.postImageWrap}>
|
||||
<PostImage fluid={image.childImageSharp.fluid} alt={title} />
|
||||
<div className={styles.imageWrap}>
|
||||
<PostImage
|
||||
fluid={image.childImageSharp.fluid}
|
||||
alt={title}
|
||||
original={image.childImageSharp.original}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{image && image.fields && <Exif exif={image.fields.exif} />}
|
@ -9,28 +9,13 @@
|
||||
padding-top: $spacer * 2;
|
||||
padding-bottom: $spacer * 2;
|
||||
|
||||
@media (min-width: $screen-sm) {
|
||||
padding-top: $spacer * 3;
|
||||
padding-bottom: $spacer * 3;
|
||||
|
||||
&:first-of-type {
|
||||
padding-top: $spacer * 4;
|
||||
}
|
||||
}
|
||||
|
||||
:global(.gatsby-image-wrapper) {
|
||||
max-height: 100vh;
|
||||
}
|
||||
}
|
||||
|
||||
.archiveTitle {
|
||||
@include heading-band();
|
||||
|
||||
font-size: $font-size-h3;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
|
||||
@media (min-width: $screen-md) {
|
||||
margin-left: -117%;
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,25 @@
|
||||
import React from 'react'
|
||||
import { Link, graphql } from 'gatsby'
|
||||
import Layout from '../components/Layout'
|
||||
import PostImage from '../components/Post/PostImage'
|
||||
import PostTitle from '../components/Post/PostTitle'
|
||||
import PostLead from '../components/Post/PostLead'
|
||||
import PostContent from '../components/Post/PostContent'
|
||||
import PostMore from '../components/Post/PostMore'
|
||||
import PostLinkActions from '../components/Post/PostLinkActions'
|
||||
import PostImage from './Post/PostImage'
|
||||
import PostTitle from './Post/PostTitle'
|
||||
import PostLead from './Post/PostLead'
|
||||
import PostContent from './Post/PostContent'
|
||||
import PostMore from './Post/PostMore'
|
||||
import PostLinkActions from './Post/PostLinkActions'
|
||||
import SEO from '../components/atoms/SEO'
|
||||
import Pagination from '../components/molecules/Pagination'
|
||||
import Featured from '../components/molecules/Featured'
|
||||
import styles from './Posts.module.scss'
|
||||
import stylesPost from './Post.module.scss'
|
||||
import { PostMetadata } from '../@types/PostMetadata'
|
||||
import stylesPost from './Post/index.module.scss'
|
||||
import { Post } from '../@types/Post'
|
||||
|
||||
export default function Posts({
|
||||
data,
|
||||
location,
|
||||
pageContext
|
||||
}: {
|
||||
data: { allMarkdownRemark: { edges: [{ node: PostMetadata }] } }
|
||||
data: { allMarkdownRemark: { edges: [{ node: Post }] } }
|
||||
location: Location
|
||||
pageContext: {
|
||||
tag: string
|
||||
@ -31,7 +31,7 @@ export default function Posts({
|
||||
const edges = data.allMarkdownRemark.edges
|
||||
const { tag, currentPageNumber, numPages, nextPage } = pageContext
|
||||
|
||||
const PostsList = edges.map(({ node }: { node: PostMetadata }) => {
|
||||
const PostsList = edges.map(({ node }: { node: Post }) => {
|
||||
const { type, linkurl, title, image } = node.frontmatter
|
||||
const { slug } = node.fields
|
||||
|
||||
@ -43,11 +43,12 @@ export default function Posts({
|
||||
|
||||
{image && (
|
||||
<Link to={slug} title={title}>
|
||||
<div className={stylesPost.postImageWrap}>
|
||||
<div className={stylesPost.imageWrap}>
|
||||
<PostImage
|
||||
title={type === 'photo' ? title : null}
|
||||
fluid={image.childImageSharp.fluid}
|
||||
alt={title}
|
||||
original={image.childImageSharp.original}
|
||||
/>
|
||||
</div>
|
||||
</Link>
|
||||
|
Loading…
Reference in New Issue
Block a user