mirror of
https://github.com/kremalicious/portfolio.git
synced 2025-01-03 18:35:00 +01:00
Merge pull request #22 from kremalicious/feature/queries
queries refactoring
This commit is contained in:
commit
f5a21fac85
@ -1,71 +1,22 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { StaticQuery, graphql } from 'gatsby'
|
|
||||||
import Head from './molecules/Head'
|
import Head from './molecules/Head'
|
||||||
import Header from './organisms/Header'
|
import Header from './organisms/Header'
|
||||||
import Footer from './organisms/Footer'
|
import Footer from './organisms/Footer'
|
||||||
import styles from './Layout.module.scss'
|
import styles from './Layout.module.scss'
|
||||||
|
|
||||||
const Layout = ({ children, location }) => {
|
const Layout = ({ children, location }) => {
|
||||||
|
const isHomepage = location.pathname === '/'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticQuery
|
<Fragment>
|
||||||
query={graphql`
|
<Head />
|
||||||
query {
|
<Header isHomepage={isHomepage} />
|
||||||
# the data/meta.yml file
|
|
||||||
dataYaml {
|
|
||||||
title
|
|
||||||
tagline
|
|
||||||
description
|
|
||||||
url
|
|
||||||
email
|
|
||||||
avatar {
|
|
||||||
childImageSharp {
|
|
||||||
original: resize {
|
|
||||||
src
|
|
||||||
}
|
|
||||||
small: resize(width: 256) {
|
|
||||||
src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
childImageSharp {
|
|
||||||
resize(width: 980) {
|
|
||||||
src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
social {
|
|
||||||
Email
|
|
||||||
Blog
|
|
||||||
Twitter
|
|
||||||
GitHub
|
|
||||||
Dribbble
|
|
||||||
}
|
|
||||||
availability {
|
|
||||||
status
|
|
||||||
}
|
|
||||||
gpg
|
|
||||||
addressbook
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
render={data => {
|
|
||||||
const meta = data.dataYaml
|
|
||||||
const isHomepage = location.pathname === '/'
|
|
||||||
|
|
||||||
return (
|
<main className={styles.screen}>{children}</main>
|
||||||
<Fragment>
|
|
||||||
<Head meta={meta} />
|
|
||||||
<Header meta={meta} isHomepage={isHomepage} />
|
|
||||||
|
|
||||||
<main className={styles.screen}>{children}</main>
|
<Footer />
|
||||||
|
</Fragment>
|
||||||
<Footer meta={meta} />
|
|
||||||
</Fragment>
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import Logo from '../svg/Logo'
|
import Logo from '../svg/Logo'
|
||||||
import styles from './LogoUnit.module.scss'
|
import styles from './LogoUnit.module.scss'
|
||||||
|
|
||||||
@ -25,23 +26,39 @@ class LogoUnit extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { meta } = this.props
|
|
||||||
const { minimal } = this.state
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={minimal ? styles.minimal : styles.logounit}>
|
<StaticQuery
|
||||||
<Logo className={styles.logounit__logo} />
|
query={graphql`
|
||||||
<h1 className={styles.logounit__title}>{meta.title.toLowerCase()}</h1>
|
query {
|
||||||
<p className={styles.logounit__description}>
|
dataYaml {
|
||||||
<span>{'{ '}</span> {meta.tagline.toLowerCase()} <span>{' }'}</span>
|
title
|
||||||
</p>
|
tagline
|
||||||
</div>
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const meta = data.dataYaml
|
||||||
|
const { minimal } = this.state
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={minimal ? styles.minimal : styles.logounit}>
|
||||||
|
<Logo className={styles.logounit__logo} />
|
||||||
|
<h1 className={styles.logounit__title}>
|
||||||
|
{meta.title.toLowerCase()}
|
||||||
|
</h1>
|
||||||
|
<p className={styles.logounit__description}>
|
||||||
|
<span>{'{ '}</span> {meta.tagline.toLowerCase()}{' '}
|
||||||
|
<span>{' }'}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LogoUnit.propTypes = {
|
LogoUnit.propTypes = {
|
||||||
meta: PropTypes.object.isRequired,
|
|
||||||
minimal: PropTypes.bool
|
minimal: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,13 +4,13 @@ import { graphql } from 'gatsby'
|
|||||||
import Img from 'gatsby-image'
|
import Img from 'gatsby-image'
|
||||||
import styles from './ProjectImage.module.scss'
|
import styles from './ProjectImage.module.scss'
|
||||||
|
|
||||||
const ProjectImage = props => (
|
const ProjectImage = ({ fluid, alt }) => (
|
||||||
<Img
|
<Img
|
||||||
className={styles.project__image}
|
className={styles.project__image}
|
||||||
outerWrapperClassName={styles.project__imagewrap}
|
outerWrapperClassName={styles.project__imagewrap}
|
||||||
backgroundColor="#6b7f88"
|
backgroundColor="#6b7f88"
|
||||||
fluid={props.fluid}
|
fluid={fluid}
|
||||||
alt={props.alt}
|
alt={alt}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import Helmet from 'react-helmet'
|
import Helmet from 'react-helmet'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
|
|
||||||
function truncate(n, useWordBoundary) {
|
function truncate(n, useWordBoundary) {
|
||||||
if (this.length <= n) {
|
if (this.length <= n) {
|
||||||
@ -14,49 +15,80 @@ function truncate(n, useWordBoundary) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const SEO = ({ project, meta }) => {
|
const SEO = ({ project }) => (
|
||||||
const title = project.title ? project.title : meta.title
|
<StaticQuery
|
||||||
const description = project.description
|
query={graphql`
|
||||||
? truncate.apply(project.description, [320, true])
|
query {
|
||||||
: truncate.apply(meta.description, [320, true])
|
dataYaml {
|
||||||
const image = project.img
|
title
|
||||||
? project.img.childImageSharp.twitterImage.src
|
tagline
|
||||||
: meta.img.childImageSharp.resize.src
|
description
|
||||||
const url = project.slug ? `${meta.url}${project.slug}` : meta.url
|
url
|
||||||
|
email
|
||||||
|
img {
|
||||||
|
childImageSharp {
|
||||||
|
resize(width: 980) {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
social {
|
||||||
|
Email
|
||||||
|
Blog
|
||||||
|
Twitter
|
||||||
|
GitHub
|
||||||
|
Dribbble
|
||||||
|
}
|
||||||
|
gpg
|
||||||
|
addressbook
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const meta = data.dataYaml
|
||||||
|
|
||||||
return (
|
const title = project.title ? project.title : meta.title
|
||||||
<Helmet>
|
const description = project.description
|
||||||
<html lang="en" />
|
? truncate.apply(project.description, [320, true])
|
||||||
|
: truncate.apply(meta.description, [320, true])
|
||||||
|
const image = project.img
|
||||||
|
? project.img.childImageSharp.twitterImage.src
|
||||||
|
: meta.img.childImageSharp.resize.src
|
||||||
|
const url = project.slug ? `${meta.url}${project.slug}` : meta.url
|
||||||
|
|
||||||
{/* General tags */}
|
return (
|
||||||
<meta name="description" content={description} />
|
<Helmet>
|
||||||
<meta name="image" content={`${meta.url}${image}`} />
|
<html lang="en" />
|
||||||
<link rel="canonical" href={url} />
|
|
||||||
|
|
||||||
{/* OpenGraph tags */}
|
{/* General tags */}
|
||||||
<meta property="og:url" content={url} />
|
<meta name="description" content={description} />
|
||||||
<meta property="og:title" content={title} />
|
<meta name="image" content={`${meta.url}${image}`} />
|
||||||
<meta property="og:description" content={description} />
|
<link rel="canonical" href={url} />
|
||||||
<meta property="og:image" content={`${meta.url}${image}`} />
|
|
||||||
|
|
||||||
{/* Twitter Card tags */}
|
{/* OpenGraph tags */}
|
||||||
<meta name="twitter:card" content="summary_large_image" />
|
<meta property="og:url" content={url} />
|
||||||
<meta name="twitter:creator" content={meta.social.Twitter} />
|
<meta property="og:title" content={title} />
|
||||||
<meta name="twitter:title" content={title} />
|
<meta property="og:description" content={description} />
|
||||||
<meta name="twitter:description" content={description} />
|
<meta property="og:image" content={`${meta.url}${image}`} />
|
||||||
<meta name="twitter:image" content={`${meta.url}${image}`} />
|
|
||||||
</Helmet>
|
{/* Twitter Card tags */}
|
||||||
)
|
<meta name="twitter:card" content="summary_large_image" />
|
||||||
}
|
<meta name="twitter:creator" content={meta.social.Twitter} />
|
||||||
|
<meta name="twitter:title" content={title} />
|
||||||
|
<meta name="twitter:description" content={description} />
|
||||||
|
<meta name="twitter:image" content={`${meta.url}${image}`} />
|
||||||
|
</Helmet>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
SEO.propTypes = {
|
SEO.propTypes = {
|
||||||
project: PropTypes.object,
|
project: PropTypes.object
|
||||||
meta: PropTypes.object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SEO.defaultProps = {
|
SEO.defaultProps = {
|
||||||
project: {},
|
project: {}
|
||||||
meta: {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SEO
|
export default SEO
|
||||||
|
@ -1,101 +1,132 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
import vCard from 'vcf'
|
import vCard from 'vcf'
|
||||||
|
|
||||||
class Vcard extends PureComponent {
|
const Vcard = () => (
|
||||||
constructor(props) {
|
<StaticQuery
|
||||||
super(props)
|
query={graphql`
|
||||||
|
query {
|
||||||
|
dataYaml {
|
||||||
|
title
|
||||||
|
tagline
|
||||||
|
description
|
||||||
|
url
|
||||||
|
email
|
||||||
|
avatar {
|
||||||
|
childImageSharp {
|
||||||
|
original: resize {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
social {
|
||||||
|
Email
|
||||||
|
Blog
|
||||||
|
Twitter
|
||||||
|
GitHub
|
||||||
|
Dribbble
|
||||||
|
}
|
||||||
|
gpg
|
||||||
|
addressbook
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const meta = data.dataYaml
|
||||||
|
|
||||||
|
const constructVcard = () => {
|
||||||
|
const contact = new vCard()
|
||||||
|
const photoSrc = meta.avatar.childImageSharp.original.src
|
||||||
|
|
||||||
|
// first, convert the avatar to base64,
|
||||||
|
// then construct all vCard elements
|
||||||
|
toDataURL(
|
||||||
|
photoSrc,
|
||||||
|
dataUrl => {
|
||||||
|
// stripping this data out of base64 string is required
|
||||||
|
// for vcard to actually display the image for whatever reason
|
||||||
|
const dataUrlCleaned = dataUrl
|
||||||
|
.split('data:image/jpeg;base64,')
|
||||||
|
.join('')
|
||||||
|
contact.set('photo', dataUrlCleaned, {
|
||||||
|
encoding: 'b',
|
||||||
|
type: 'JPEG'
|
||||||
|
})
|
||||||
|
contact.set('fn', meta.title)
|
||||||
|
contact.set('title', meta.tagline)
|
||||||
|
contact.set('email', meta.email)
|
||||||
|
contact.set('url', meta.url, { type: 'Portfolio' })
|
||||||
|
contact.add('url', meta.social.Blog, { type: 'Blog' })
|
||||||
|
contact.set('nickname', 'kremalicious')
|
||||||
|
contact.add('x-socialprofile', meta.social.Twitter, {
|
||||||
|
type: 'twitter'
|
||||||
|
})
|
||||||
|
contact.add('x-socialprofile', meta.social.GitHub, {
|
||||||
|
type: 'GitHub'
|
||||||
|
})
|
||||||
|
|
||||||
|
const vcard = contact.toString('3.0')
|
||||||
|
|
||||||
|
downloadVcard(vcard)
|
||||||
|
},
|
||||||
|
'image/jpeg'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the download from a blob of the just constructed vCard,
|
||||||
|
// and save it to user's file system
|
||||||
|
const downloadVcard = vcard => {
|
||||||
|
const name = meta.addressbook.split('/').join('')
|
||||||
|
const blob = new Blob([vcard], { type: 'text/x-vcard' })
|
||||||
|
FileSaver.saveAs(blob, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleAddressbookClick = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
constructVcard()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
// href is kinda fake, only there for usability
|
||||||
|
// so user knows what to expect when hovering the link before clicking
|
||||||
|
href={meta.addressbook}
|
||||||
|
onClick={handleAddressbookClick}
|
||||||
|
>
|
||||||
|
Add to addressbook
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
|
||||||
|
// Helper function to create base64 string from avatar image
|
||||||
|
// without the need to read image file from file system
|
||||||
|
const toDataURL = (src, callback, outputFormat) => {
|
||||||
|
const img = new Image()
|
||||||
|
img.crossOrigin = 'Anonymous'
|
||||||
|
|
||||||
|
img.onload = function() {
|
||||||
|
// yeah, we're gonna create a fake canvas to render the image
|
||||||
|
// and then create a base64 string from the rendered result
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
let dataURL
|
||||||
|
|
||||||
|
canvas.height = this.naturalHeight
|
||||||
|
canvas.width = this.naturalWidth
|
||||||
|
ctx.drawImage(this, 0, 0)
|
||||||
|
dataURL = canvas.toDataURL(outputFormat)
|
||||||
|
callback(dataURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to create base64 string from avatar image
|
img.src = src
|
||||||
// without the need to read image file from file system
|
if (img.complete || img.complete === undefined) {
|
||||||
toDataURL(src, callback, outputFormat) {
|
img.src =
|
||||||
const img = new Image()
|
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
|
||||||
img.crossOrigin = 'Anonymous'
|
|
||||||
|
|
||||||
img.onload = function() {
|
|
||||||
// yeah, we're gonna create a fake canvas to render the image
|
|
||||||
// and then create a base64 string from the rendered result
|
|
||||||
const canvas = document.createElement('canvas')
|
|
||||||
const ctx = canvas.getContext('2d')
|
|
||||||
let dataURL
|
|
||||||
|
|
||||||
canvas.height = this.naturalHeight
|
|
||||||
canvas.width = this.naturalWidth
|
|
||||||
ctx.drawImage(this, 0, 0)
|
|
||||||
dataURL = canvas.toDataURL(outputFormat)
|
|
||||||
callback(dataURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
img.src = src
|
img.src = src
|
||||||
if (img.complete || img.complete === undefined) {
|
|
||||||
img.src =
|
|
||||||
'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='
|
|
||||||
img.src = src
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructVcard() {
|
|
||||||
const meta = this.props.meta
|
|
||||||
const contact = new vCard()
|
|
||||||
const photoSrc = meta.avatar.childImageSharp.original.src
|
|
||||||
|
|
||||||
// first, convert the avatar to base64,
|
|
||||||
// then construct all vCard elements
|
|
||||||
this.toDataURL(
|
|
||||||
photoSrc,
|
|
||||||
dataUrl => {
|
|
||||||
// stripping this data out of base64 string is required
|
|
||||||
// for vcard to actually display the image for whatever reason
|
|
||||||
const dataUrlCleaned = dataUrl.split('data:image/jpeg;base64,').join('')
|
|
||||||
contact.set('photo', dataUrlCleaned, { encoding: 'b', type: 'JPEG' })
|
|
||||||
contact.set('fn', meta.title)
|
|
||||||
contact.set('title', meta.tagline)
|
|
||||||
contact.set('email', meta.email)
|
|
||||||
contact.set('url', meta.url, { type: 'Portfolio' })
|
|
||||||
contact.add('url', meta.social.Blog, { type: 'Blog' })
|
|
||||||
contact.set('nickname', 'kremalicious')
|
|
||||||
contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' })
|
|
||||||
contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' })
|
|
||||||
|
|
||||||
const vcard = contact.toString('3.0')
|
|
||||||
|
|
||||||
this.downloadVcard(vcard)
|
|
||||||
},
|
|
||||||
'image/jpeg'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the download from a blob of the just constructed vCard,
|
|
||||||
// and save it to user's file system
|
|
||||||
downloadVcard(vcard) {
|
|
||||||
const name = this.props.meta.addressbook.split('/').join('')
|
|
||||||
const blob = new Blob([vcard], { type: 'text/x-vcard' })
|
|
||||||
FileSaver.saveAs(blob, name)
|
|
||||||
}
|
|
||||||
|
|
||||||
handleAddressbookClick = e => {
|
|
||||||
e.preventDefault()
|
|
||||||
this.constructVcard()
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
// href is kinda fake, only there for usability
|
|
||||||
// so user knows what to expect when hovering the link before clicking
|
|
||||||
href={this.props.meta.addressbook}
|
|
||||||
onClick={this.handleAddressbookClick}
|
|
||||||
>
|
|
||||||
Add to addressbook
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Vcard.propTypes = {
|
|
||||||
meta: PropTypes.object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Vcard
|
export default Vcard
|
||||||
|
@ -1,30 +1,41 @@
|
|||||||
import React, { Fragment } from 'react'
|
import React, { Fragment } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import Helmet from 'react-helmet'
|
import Helmet from 'react-helmet'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import SEO from '../atoms/SEO'
|
import SEO from '../atoms/SEO'
|
||||||
import Typekit from '../atoms/Typekit'
|
import Typekit from '../atoms/Typekit'
|
||||||
|
|
||||||
const Head = ({ meta }) => {
|
const Head = () => (
|
||||||
const { title, tagline } = meta
|
<StaticQuery
|
||||||
|
query={graphql`
|
||||||
|
query {
|
||||||
|
dataYaml {
|
||||||
|
title
|
||||||
|
tagline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const { title, tagline } = data.dataYaml
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Helmet
|
<Helmet
|
||||||
defaultTitle={`${title.toLowerCase()} { ${tagline.toLowerCase()} }`}
|
defaultTitle={`${title.toLowerCase()} { ${tagline.toLowerCase()} }`}
|
||||||
titleTemplate={`%s // ${title.toLowerCase()} { ${tagline.toLowerCase()} }`}
|
titleTemplate={`%s // ${title.toLowerCase()} { ${tagline.toLowerCase()} }`}
|
||||||
>
|
>
|
||||||
<meta name="apple-mobile-web-app-title" content={title.toLowerCase()} />
|
<meta
|
||||||
</Helmet>
|
name="apple-mobile-web-app-title"
|
||||||
|
content={title.toLowerCase()}
|
||||||
|
/>
|
||||||
|
</Helmet>
|
||||||
|
|
||||||
<Typekit />
|
<Typekit />
|
||||||
|
|
||||||
<SEO meta={meta} />
|
<SEO />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}}
|
||||||
|
/>
|
||||||
Head.propTypes = {
|
)
|
||||||
meta: PropTypes.object.isRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Head
|
export default Head
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import { FadeIn } from '../atoms/Animations'
|
import { FadeIn } from '../atoms/Animations'
|
||||||
|
|
||||||
import Email from '../svg/Email'
|
import Email from '../svg/Email'
|
||||||
@ -55,28 +56,44 @@ class Network extends PureComponent {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
!this.props.hide && (
|
<StaticQuery
|
||||||
<FadeIn>
|
query={graphql`
|
||||||
<aside className={this.state.classes}>
|
query {
|
||||||
{Object.keys(this.props.meta.social).map((key, i) => (
|
dataYaml {
|
||||||
<a
|
social {
|
||||||
className={styles.link}
|
Email
|
||||||
href={this.props.meta.social[key]}
|
Blog
|
||||||
key={i}
|
Twitter
|
||||||
>
|
GitHub
|
||||||
<NetworkIcon title={key} className={icons.icon} />
|
Dribbble
|
||||||
<span className={styles.title}>{key}</span>
|
}
|
||||||
</a>
|
}
|
||||||
))}
|
}
|
||||||
</aside>
|
`}
|
||||||
</FadeIn>
|
render={data => {
|
||||||
)
|
const meta = data.dataYaml
|
||||||
|
|
||||||
|
return (
|
||||||
|
!this.props.hide && (
|
||||||
|
<FadeIn>
|
||||||
|
<aside className={this.state.classes}>
|
||||||
|
{Object.keys(meta.social).map((key, i) => (
|
||||||
|
<a className={styles.link} href={meta.social[key]} key={i}>
|
||||||
|
<NetworkIcon title={key} className={icons.icon} />
|
||||||
|
<span className={styles.title}>{key}</span>
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</aside>
|
||||||
|
</FadeIn>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Network.propTypes = {
|
Network.propTypes = {
|
||||||
meta: PropTypes.object,
|
|
||||||
minimal: PropTypes.bool,
|
minimal: PropTypes.bool,
|
||||||
hide: PropTypes.bool
|
hide: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import { StaticQuery, graphql } from 'gatsby'
|
import { StaticQuery, graphql } from 'gatsby'
|
||||||
import Vcard from '../atoms/Vcard'
|
import Vcard from '../atoms/Vcard'
|
||||||
import LogoUnit from '../atoms/LogoUnit'
|
import LogoUnit from '../atoms/LogoUnit'
|
||||||
@ -14,8 +13,6 @@ class Footer extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const meta = this.props.meta
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StaticQuery
|
<StaticQuery
|
||||||
query={graphql`
|
query={graphql`
|
||||||
@ -27,18 +24,24 @@ class Footer extends PureComponent {
|
|||||||
repository
|
repository
|
||||||
bugs
|
bugs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dataYaml {
|
||||||
|
title
|
||||||
|
gpg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
render={data => {
|
render={data => {
|
||||||
const pkg = data.portfolioJson
|
const pkg = data.portfolioJson
|
||||||
|
const meta = data.dataYaml
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={styles.footer}>
|
<footer className={styles.footer}>
|
||||||
<LogoUnit meta={meta} minimal />
|
<LogoUnit minimal />
|
||||||
<Networks meta={meta} minimal />
|
<Networks minimal />
|
||||||
|
|
||||||
<p className={styles.footer__actions}>
|
<p className={styles.footer__actions}>
|
||||||
<Vcard meta={meta} />
|
<Vcard />
|
||||||
<a href={meta.gpg}>PGP/GPG key</a>
|
<a href={meta.gpg}>PGP/GPG key</a>
|
||||||
<a href={pkg.bugs}>Found a bug?</a>
|
<a href={pkg.bugs}>Found a bug?</a>
|
||||||
</p>
|
</p>
|
||||||
@ -56,9 +59,4 @@ class Footer extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Footer.propTypes = {
|
|
||||||
meta: PropTypes.object,
|
|
||||||
pkg: PropTypes.object
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Footer
|
export default Footer
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React, { PureComponent } from 'react'
|
import React, { PureComponent } from 'react'
|
||||||
import { Link } from 'gatsby'
|
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import { Link, StaticQuery, graphql } from 'gatsby'
|
||||||
import Networks from '../molecules/Networks'
|
import Networks from '../molecules/Networks'
|
||||||
import Availability from '../molecules/Availability'
|
import Availability from '../molecules/Availability'
|
||||||
import ThemeSwitch from '../molecules/ThemeSwitch'
|
import ThemeSwitch from '../molecules/ThemeSwitch'
|
||||||
@ -29,28 +29,44 @@ class Header extends PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isHomepage, meta } = this.props
|
const { isHomepage } = this.props
|
||||||
const { minimal } = this.state
|
const { minimal } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={minimal ? styles.minimal : styles.header}>
|
<StaticQuery
|
||||||
<ThemeSwitch />
|
query={graphql`
|
||||||
|
query {
|
||||||
|
dataYaml {
|
||||||
|
availability {
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
render={data => {
|
||||||
|
const meta = data.dataYaml
|
||||||
|
|
||||||
<Link className={styles.header__link} to={'/'}>
|
return (
|
||||||
<LogoUnit meta={meta} minimal={!isHomepage} />
|
<header className={minimal ? styles.minimal : styles.header}>
|
||||||
</Link>
|
<ThemeSwitch />
|
||||||
|
|
||||||
<Networks meta={meta} hide={!isHomepage} />
|
<Link className={styles.header__link} to={'/'}>
|
||||||
|
<LogoUnit minimal={!isHomepage} />
|
||||||
|
</Link>
|
||||||
|
|
||||||
<Availability hide={!isHomepage && !meta.availability.status} />
|
<Networks hide={!isHomepage} />
|
||||||
</header>
|
|
||||||
|
<Availability hide={!isHomepage && !meta.availability.status} />
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Header.propTypes = {
|
Header.propTypes = {
|
||||||
isHomepage: PropTypes.bool,
|
isHomepage: PropTypes.bool
|
||||||
meta: PropTypes.object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Header
|
export default Header
|
||||||
|
@ -32,7 +32,6 @@ const ProjectImages = ({ projectImages, title }) => (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const Project = ({ data, location }) => {
|
const Project = ({ data, location }) => {
|
||||||
const meta = data.dataYaml
|
|
||||||
const project = data.projectsYaml
|
const project = data.projectsYaml
|
||||||
const projectImages = data.projectImages.edges
|
const projectImages = data.projectImages.edges
|
||||||
const { title, links, techstack } = project
|
const { title, links, techstack } = project
|
||||||
@ -43,7 +42,7 @@ const Project = ({ data, location }) => {
|
|||||||
<Layout location={location}>
|
<Layout location={location}>
|
||||||
<Helmet title={title} />
|
<Helmet title={title} />
|
||||||
|
|
||||||
<SEO project={project} meta={meta} />
|
<SEO project={project} />
|
||||||
|
|
||||||
<article className={styles.project}>
|
<article className={styles.project}>
|
||||||
<Content>
|
<Content>
|
||||||
@ -99,28 +98,6 @@ export const projectAndProjectsQuery = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# the data/meta.yml file
|
|
||||||
dataYaml {
|
|
||||||
title
|
|
||||||
tagline
|
|
||||||
description
|
|
||||||
url
|
|
||||||
social {
|
|
||||||
Email
|
|
||||||
Blog
|
|
||||||
Twitter
|
|
||||||
GitHub
|
|
||||||
Dribbble
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
childImageSharp {
|
|
||||||
resize(width: 980) {
|
|
||||||
src
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
projectImages: allImageSharp(
|
projectImages: allImageSharp(
|
||||||
filter: { fluid: { originalName: { regex: $slug } } }
|
filter: { fluid: { originalName: { regex: $slug } } }
|
||||||
sort: { fields: [fluid___originalName], order: ASC }
|
sort: { fields: [fluid___originalName], order: ASC }
|
||||||
|
Loading…
Reference in New Issue
Block a user