1
0
mirror of https://github.com/kremalicious/blog.git synced 2025-01-05 03:15:07 +01:00
This commit is contained in:
Matthias Kretschmann 2019-10-13 19:08:36 +02:00
parent 71824fc3b8
commit fe69db7fdf
Signed by: m
GPG Key ID: 606EEEF3C479A91F
12 changed files with 155 additions and 92 deletions

View File

@ -12,6 +12,7 @@
"files": ["**/*.ts", "**/*.tsx"], "files": ["**/*.ts", "**/*.tsx"],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"extends": [ "extends": [
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"plugin:jsx-a11y/recommended", "plugin:jsx-a11y/recommended",
"prettier/@typescript-eslint", "prettier/@typescript-eslint",
@ -32,7 +33,8 @@
"ecmaFeatures": { "ecmaFeatures": {
"jsx": true "jsx": true
}, },
"project": "./tsconfig.json" "project": "./tsconfig.json",
"tsconfigRootDir": "./"
} }
} }
] ]

View File

@ -0,0 +1,20 @@
{
"edges": [
{
"node": {
"childImageSharp": {
"fixed": {
"aspectRatio": 1,
"width": 80,
"height": 80,
"src": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg",
"srcSet": "/static/b61a09d5f4cbd9d8b2844091590ddea4/fce1d/avatar.jpg 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c4de8/avatar.jpg 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/c3234/avatar.jpg 2x",
"srcWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp",
"srcSetWebp": "/static/b61a09d5f4cbd9d8b2844091590ddea4/ad6b8/avatar.webp 1x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5c322/avatar.webp 1.5x,\n/static/b61a09d5f4cbd9d8b2844091590ddea4/5bf6b/avatar.webp 2x",
"originalName": "avatar.jpg"
}
}
}
}
]
}

View File

@ -4,25 +4,11 @@ const gatsby = jest.requireActual('gatsby')
export default { export default {
...gatsby, ...gatsby,
graphql: jest.fn(), graphql: jest.fn(),
Link: jest.fn().mockImplementation( Link: jest
// these props are invalid for an `a` tag .fn()
({ .mockImplementation(({ to, ...rest }) =>
/* eslint-disable @typescript-eslint/no-unused-vars */ React.createElement('a', { ...rest, href: to })
activeClassName, ),
activeStyle,
getProps,
innerRef,
ref,
replace,
to,
/* eslint-enable @typescript-eslint/no-unused-vars */
...rest
}) =>
React.createElement('a', {
...rest,
href: to
})
),
StaticQuery: jest.fn(), StaticQuery: jest.fn(),
useStaticQuery: jest.fn() useStaticQuery: jest.fn()
} }

View File

@ -98,6 +98,7 @@
"@types/react-helmet": "^5.0.11", "@types/react-helmet": "^5.0.11",
"@types/react-modal": "^3.8.3", "@types/react-modal": "^3.8.3",
"@types/react-transition-group": "^4.2.3", "@types/react-transition-group": "^4.2.3",
"@types/shortid": "0.0.29",
"@types/web3": "^1.0.20", "@types/web3": "^1.0.20",
"@typescript-eslint/eslint-plugin": "^2.3.3", "@typescript-eslint/eslint-plugin": "^2.3.3",
"@typescript-eslint/parser": "^2.3.3", "@typescript-eslint/parser": "^2.3.3",
@ -121,6 +122,7 @@
"pify": "^4.0.1", "pify": "^4.0.1",
"prettier": "^1.18.2", "prettier": "^1.18.2",
"prettier-stylelint": "^0.4.2", "prettier-stylelint": "^0.4.2",
"shortid": "^2.2.15",
"stylelint": "^11.1.1", "stylelint": "^11.1.1",
"stylelint-config-css-modules": "^1.5.0", "stylelint-config-css-modules": "^1.5.0",
"stylelint-config-prettier": "^6.0.0", "stylelint-config-prettier": "^6.0.0",

View File

@ -1,10 +1,10 @@
import React from 'react' import React from 'react'
import { render, fireEvent, wait } from '@testing-library/react' import { render, fireEvent } from '@testing-library/react'
import Qr from './Qr' import Qr from './Qr'
describe('Qr', () => { describe('Qr', () => {
it('renders without crashing', async () => { it('renders without crashing', () => {
const { container } = render(<Qr address="xxx" />) const { container } = render(<Qr address="xxx" />)
expect(container.firstChild).toBeInTheDocument() expect(container.firstChild).toBeInTheDocument()
fireEvent.click(container.querySelector('button')) fireEvent.click(container.querySelector('button'))

View File

@ -20,6 +20,8 @@ function NetworkIcon({ link }: { link: string }) {
Icon = <Rss className={styles.rss} /> Icon = <Rss className={styles.rss} />
} else if (link.includes('feed.json')) { } else if (link.includes('feed.json')) {
Icon = <Jsonfeed className={styles.json} /> Icon = <Jsonfeed className={styles.json} />
} else {
return null
} }
return Icon return Icon

View File

@ -1,23 +1,26 @@
import React from 'react' import React from 'react'
import { Link } from 'gatsby' import { Link } from 'gatsby'
import shortid from 'shortid'
import styles from './Pagination.module.scss' import styles from './Pagination.module.scss'
const PageNumber = ({ i, current }: { i: number; current?: boolean }) => ( function PageNumber({ i, current }: { i: number; current?: boolean }) {
<Link const classes = current ? styles.current : styles.number
className={current ? styles.current : styles.number} const link = i === 0 ? '' : `/page/${i + 1}`
to={i === 0 ? '' : `/page/${i + 1}`}
>
{i + 1}
</Link>
)
const PrevNext = ({ return (
<Link className={classes} to={link}>
{i + 1}
</Link>
)
}
function PrevNext({
prevPagePath, prevPagePath,
nextPagePath nextPagePath
}: { }: {
prevPagePath?: string prevPagePath?: string
nextPagePath?: string nextPagePath?: string
}) => { }) {
const link = prevPagePath || nextPagePath const link = prevPagePath || nextPagePath
const rel = prevPagePath ? 'prev' : 'next' const rel = prevPagePath ? 'prev' : 'next'
const title = prevPagePath ? 'Newer Posts' : 'Older Posts' const title = prevPagePath ? 'Newer Posts' : 'Older Posts'
@ -45,13 +48,13 @@ export default function Pagination({
const prevPagePath = currentPageNumber === 2 ? '/' : `/page/${prevPage}` const prevPagePath = currentPageNumber === 2 ? '/' : `/page/${prevPage}`
const nextPagePath = `/page/${nextPage}` const nextPagePath = `/page/${nextPage}`
return nextPage && nextPage > 1 ? ( return (
<div className={styles.pagination}> <div className={styles.pagination}>
<div>{!isFirst && <PrevNext prevPagePath={prevPagePath} />}</div> <div>{!isFirst && <PrevNext prevPagePath={prevPagePath} />}</div>
<div> <div>
{Array.from({ length: numPages }, (_, i) => ( {Array.from({ length: numPages }, (_, i) => (
<PageNumber <PageNumber
key={`pagination-number${i + 1}`} key={shortid.generate()}
i={i} i={i}
current={currentPageNumber === i + 1} current={currentPageNumber === i + 1}
/> />
@ -59,5 +62,5 @@ export default function Pagination({
</div> </div>
<div>{!isLast && <PrevNext nextPagePath={nextPagePath} />}</div> <div>{!isLast && <PrevNext nextPagePath={nextPagePath} />}</div>
</div> </div>
) : null )
} }

View File

@ -0,0 +1,28 @@
import React from 'react'
import { render } from '@testing-library/react'
import { VcardPure as Vcard } from './Vcard'
import avatar from '../../../jest/__fixtures__/avatar.json'
const links = [
'twitter.com',
'github.com',
'facebook.com',
'feed.xml',
'feed.json',
'whatever'
]
describe('Vcard', () => {
it('renders without crashing', () => {
const { container } = render(
<Vcard
avatar={avatar.edges[0].node.childImageSharp.fixed}
name="Hello You"
uri="https://demo.com"
links={links}
/>
)
expect(container.firstChild).toBeInTheDocument()
})
})

View File

@ -1,33 +1,21 @@
import React from 'react' import React from 'react'
import { graphql, useStaticQuery } from 'gatsby' import { graphql, useStaticQuery } from 'gatsby'
import Img from 'gatsby-image' import Img, { FixedObject } from 'gatsby-image'
import IconLinks from './IconLinks' import IconLinks from './IconLinks'
import styles from './Vcard.module.scss' import styles from './Vcard.module.scss'
import { useSiteMetadata } from '../../hooks/use-site-metadata' import { useSiteMetadata } from '../../hooks/use-site-metadata'
const query = graphql` export function VcardPure({
query { avatar,
avatar: allFile(filter: { name: { eq: "avatar" } }) { uri,
edges { name,
node { links
childImageSharp { }: {
fixed(width: 80, height: 80, quality: 90) { avatar: FixedObject
...GatsbyImageSharpFixed_withWebp_noBase64 uri: string
} name: string
} links: string[]
} }) {
}
}
}
`
export default function Vcard() {
const data = useStaticQuery(query)
const { author, rss, jsonfeed } = useSiteMetadata()
const { twitter, github, name, uri } = author
const avatar = data.avatar.edges[0].node.childImageSharp.fixed
const links = [twitter, github, rss, jsonfeed]
return ( return (
<div className={styles.vcard}> <div className={styles.vcard}>
<Img className={styles.avatar} fixed={avatar} alt="avatar" /> <Img className={styles.avatar} fixed={avatar} alt="avatar" />
@ -42,3 +30,29 @@ export default function Vcard() {
</div> </div>
) )
} }
export default function Vcard() {
const query = graphql`
query {
avatar: allFile(filter: { name: { eq: "avatar" } }) {
edges {
node {
childImageSharp {
fixed(width: 80, height: 80, quality: 90) {
...GatsbyImageSharpFixed_withWebp_noBase64
}
}
}
}
}
}
`
const data = useStaticQuery(query)
const { author, rss, jsonfeed } = useSiteMetadata()
const { twitter, github, name, uri } = author
const avatar = data.avatar.edges[0].node.childImageSharp.fixed
const links = [twitter, github, rss, jsonfeed]
return <VcardPure avatar={avatar} links={links} uri={uri} name={name} />
}

View File

@ -1,38 +1,38 @@
import { useStaticQuery, graphql } from 'gatsby' import { useStaticQuery, graphql } from 'gatsby'
const query = graphql` export const useSiteMetadata = () => {
query { const query = graphql`
site { query {
siteMetadata { site {
siteTitle siteMetadata {
siteTitleShort siteTitle
siteDescription siteTitleShort
siteUrl siteDescription
author { siteUrl
name author {
email name
uri email
twitter uri
github twitter
facebook github
bitcoin facebook
ether bitcoin
ether
}
typekitID
menu {
title
link
}
rss
jsonfeed
itemsPerPage
repoContentPath
} }
typekitID
menu {
title
link
}
rss
jsonfeed
itemsPerPage
repoContentPath
} }
} }
} `
`
export const useSiteMetadata = () => {
const { site } = useStaticQuery(query) const { site } = useStaticQuery(query)
return site.siteMetadata return site.siteMetadata
} }

View File

@ -20,10 +20,15 @@ export default function Posts({
}: { }: {
data: any data: any
location: Location location: Location
pageContext: { tag: string; currentPageNumber: number; numPages: number } pageContext: {
tag: string
currentPageNumber: number
numPages: number
nextPage: number
}
}) { }) {
const edges = data.allMarkdownRemark.edges const edges = data.allMarkdownRemark.edges
const { tag, currentPageNumber, numPages } = pageContext const { tag, currentPageNumber, numPages, nextPage } = pageContext
const PostsList = edges.map(({ node }: { node: any }) => { const PostsList = edges.map(({ node }: { node: any }) => {
const { type, linkurl, title, image } = node.frontmatter const { type, linkurl, title, image } = node.frontmatter
@ -75,7 +80,7 @@ export default function Posts({
>{`Page ${currentPageNumber} / ${numPages}`}</h1> >{`Page ${currentPageNumber} / ${numPages}`}</h1>
)} )}
{PostsList} {PostsList}
<Pagination pageContext={pageContext} /> {nextPage && nextPage > 1 && <Pagination pageContext={pageContext} />}
</Layout> </Layout>
) )
} }

View File

@ -9,7 +9,8 @@
"lib": ["dom", "esnext"], "lib": ["dom", "esnext"],
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"esModuleInterop": true, "esModuleInterop": true,
"allowJs": true "allowJs": true,
"resolveJsonModule": true
}, },
"exclude": ["node_modules", "public", ".cache", "*.js"], "exclude": ["node_modules", "public", ".cache", "*.js"],
"include": ["./src/**/*", "./jest/**/*"] "include": ["./src/**/*", "./jest/**/*"]