1
0
mirror of https://github.com/kremalicious/portfolio.git synced 2024-06-26 03:06:39 +02:00

get most site metadata from the resume

This commit is contained in:
Matthias Kretschmann 2019-11-19 22:49:17 +01:00
parent b46b006dd7
commit e84de746c7
Signed by: m
GPG Key ID: 606EEEF3C479A91F
7 changed files with 53 additions and 52 deletions

View File

@ -16,9 +16,9 @@
- [🎉 Features](#-features) - [🎉 Features](#-features)
- [⛵️ Lighthouse score](#-lighthouse-score) - [⛵️ Lighthouse score](#-lighthouse-score)
- [🗂 JSON Resume](#-json-resume)
- [💍 One data file to rule all pages](#-one-data-file-to-rule-all-pages) - [💍 One data file to rule all pages](#-one-data-file-to-rule-all-pages)
- [🐱 GitHub repositories](#-github-repositories) - [🐱 GitHub repositories](#-github-repositories)
- 🗂 JSON Resume](#-json-resume)
- [💅 Theme switcher](#-theme-switcher) - [💅 Theme switcher](#-theme-switcher)
- [🏆 SEO component](#-seo-component) - [🏆 SEO component](#-seo-component)
- [📇 Client-side vCard creation](#-client-side-vcard-creation) - [📇 Client-side vCard creation](#-client-side-vcard-creation)
@ -38,37 +38,17 @@
## 🎉 Features ## 🎉 Features
The whole [portfolio](https://matthiaskretschmann.com) is a React-based Single Page App built with [Gatsby v2](https://www.gatsbyjs.org). The whole [portfolio](https://matthiaskretschmann.com) is a React-based single page app built with [Gatsby v2](https://www.gatsbyjs.org).
Most metadata is powered by one `resume.json` file based on [🗂 JSON Resume](#-json-resume), and one `projects.yml` file to [define the displayed projects](#-one-data-file-to-rule-all-pages).
### ⛵️ Lighthouse score ### ⛵️ Lighthouse score
![Lighthouse scores](https://lighthouse.now.sh/?perf=100&pwa=100&a11y=100&bp=100&seo=100) ![Lighthouse scores](https://lighthouse.now.sh/?perf=100&pwa=100&a11y=100&bp=100&seo=100)
### 💍 One data file to rule all pages
All content is powered by one YAML file where all the portfolio's projects are defined. The project description itself is transformed from Markdown written inside the YAML file into HTML on build time.
Gatsby automatically creates pages from each item in that file utilizing the [`Project.jsx`](src/templates/Project.jsx) template.
- [`gatsby-node.js`](gatsby-node.js)
- [`content/projects.yml`](content/projects.yml)
- [`src/templates/Project.jsx`](src/templates/Project.jsx)
### 🐱 GitHub repositories
The open source section at the bottom of the front page shows selected GitHub repositories, sourced from GitHub.
On build time, all my public repositories are fetched from GitHub, then filtered against the ones defined in `content/repos.yml`, sorted by the last push date, and provided via the page context of the front page.
If you want to know how, have a look at the respective components:
- [`gatsby-node.js`](gatsby-node.js)
- [`content/repos.yml`](content/repos.yml)
- [`src/components/molecules/Repository.jsx`](src/components/molecules/Repository.jsx)
### 🗂 JSON Resume ### 🗂 JSON Resume
Resume page based on [JSON Resume](https://jsonresume.org) standard. Most site metadata and social profiles are defined in [`content/resume.json`](content/resume.json) and used throughout the site. Most site metadata and social profiles are defined in [`content/resume.json`](content/resume.json) based on the [JSON Resume](https://jsonresume.org) standard and used throughout the site as a custom React hook. Additionally, a resume page is created under `/resume`.
If you want to know how, have a look at the respective components: If you want to know how, have a look at the respective components:
@ -76,6 +56,28 @@ If you want to know how, have a look at the respective components:
- [`src/pages/resume/index.jsx`](src/pages/resume/index.jsx) - [`src/pages/resume/index.jsx`](src/pages/resume/index.jsx)
- [`src/hooks/use-resume.js`](src/hooks/use-resume.js) - [`src/hooks/use-resume.js`](src/hooks/use-resume.js)
### 💍 One data file to rule all pages
All displayed project content is powered by one YAML file where all the portfolio's projects are defined. The project description itself is transformed from Markdown written inside the YAML file into HTML on build time.
Gatsby automatically creates pages from each item in that file utilizing the [`Project.jsx`](src/templates/Project.jsx) template.
- [`content/projects.yml`](content/projects.yml)
- [`gatsby-node.js`](gatsby-node.js)
- [`src/templates/Project.jsx`](src/templates/Project.jsx)
### 🐱 GitHub repositories
The open source section at the bottom of the front page shows selected GitHub repositories, sourced from GitHub.
On build time, all my public repositories are fetched from GitHub, then filtered against the ones defined in `content/repos.yml`, sorted by the last push date, and provided via the `pageContext` of the front page.
If you want to know how, have a look at the respective components:
- [`gatsby-node.js`](gatsby-node.js)
- [`content/repos.yml`](content/repos.yml)
- [`src/components/molecules/Repository.jsx`](src/components/molecules/Repository.jsx)
### 💅 Theme switcher ### 💅 Theme switcher
Includes a theme switcher which allows user to toggle between a light and a dark theme. Switching between them also happens automatically based on user's local sunset and sunrise times. Uses Cloudflare's geo location HTTP header functionality. Includes a theme switcher which allows user to toggle between a light and a dark theme. Switching between them also happens automatically based on user's local sunset and sunrise times. Uses Cloudflare's geo location HTTP header functionality.

View File

@ -1,9 +1,6 @@
# more personal metadata can be found in ./resume.json # most personal metadata can be found in ./resume.json
- title: Matthias Kretschmann - description: Portfolio of web & ui designer/developer hybrid Matthias Kretschmann.
tagline: Designer & Developer
description: Portfolio of web & ui designer/developer hybrid Matthias Kretschmann.
url: https://matthiaskretschmann.com
img: ../src/images/twitter-card.png img: ../src/images/twitter-card.png
availability: availability:

View File

@ -2,13 +2,15 @@ const path = require('path')
const fs = require('fs') const fs = require('fs')
const yaml = require('js-yaml') const yaml = require('js-yaml')
const meta = yaml.load(fs.readFileSync('./content/meta.yml', 'utf8')) const meta = yaml.load(fs.readFileSync('./content/meta.yml', 'utf8'))
const { title, url, matomoSite, matomoUrl } = meta[0] const resume = require('./content/resume.json')
const { matomoSite, matomoUrl } = meta[0]
const { name, website } = resume.basics
require('dotenv').config() require('dotenv').config()
module.exports = { module.exports = {
siteMetadata: { siteMetadata: {
siteUrl: `${url}` siteUrl: `${website}`
}, },
plugins: [ plugins: [
'gatsby-transformer-yaml', 'gatsby-transformer-yaml',
@ -50,7 +52,7 @@ module.exports = {
resolve: 'gatsby-plugin-matomo', resolve: 'gatsby-plugin-matomo',
options: { options: {
siteId: `${matomoSite}`, siteId: `${matomoSite}`,
siteUrl: `${url}`, siteUrl: `${website}`,
matomoUrl: `${matomoUrl}`, matomoUrl: `${matomoUrl}`,
localScript: '/piwik.js' localScript: '/piwik.js'
} }
@ -58,7 +60,7 @@ module.exports = {
{ {
resolve: 'gatsby-plugin-manifest', resolve: 'gatsby-plugin-manifest',
options: { options: {
name: title.toLowerCase(), name: name.toLowerCase(),
short_name: 'mk', short_name: 'mk',
start_url: '/', start_url: '/',
background_color: '#e7eef4', background_color: '#e7eef4',

6
package-lock.json generated
View File

@ -12308,9 +12308,9 @@
"integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==" "integrity": "sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ=="
}, },
"handlebars": { "handlebars": {
"version": "4.5.2", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.2.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-29Zxv/cynYB7mkT1rVWQnV7mGX6v7H/miQ6dbEpYTKq5eJBN7PsRB+ViYJlcT6JINTSu4dVB9kOqEun78h6Exg==", "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"dev": true, "dev": true,
"requires": { "requires": {
"neo-async": "^2.6.0", "neo-async": "^2.6.0",

View File

@ -5,36 +5,36 @@ import { useMeta } from '../../hooks/use-meta'
import { useResume } from '../../hooks/use-resume' import { useResume } from '../../hooks/use-resume'
const MetaTags = ({ title, description, url, image, meta }) => { const MetaTags = ({ title, description, url, image, meta }) => {
const resume = useResume() const { basics } = useResume()
const twitterHandle = resume.basics.profiles.filter( const twitterHandle = basics.profiles.filter(
({ network }) => network === 'Twitter' ({ network }) => network === 'Twitter'
)[0].username )[0].username
return ( return (
<Helmet <Helmet
defaultTitle={`${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`} defaultTitle={`${basics.name.toLowerCase()} { ${basics.label.toLowerCase()} }`}
titleTemplate={`%s // ${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`} titleTemplate={`%s // ${basics.name.toLowerCase()} { ${basics.label.toLowerCase()} }`}
title={title} title={title}
> >
<html lang="en" /> <html lang="en" />
{/* General tags */} {/* General tags */}
<meta name="description" content={description} /> <meta name="description" content={description} />
<meta name="image" content={`${meta.url}${image}`} /> <meta name="image" content={`${basics.website}${image}`} />
<link rel="canonical" href={url} /> <link rel="canonical" href={url} />
{/* OpenGraph tags */} {/* OpenGraph tags */}
<meta property="og:url" content={url} /> <meta property="og:url" content={url} />
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
<meta property="og:description" content={description} /> <meta property="og:description" content={description} />
<meta property="og:image" content={`${meta.url}${image}`} /> <meta property="og:image" content={`${basics.website}${image}`} />
{/* Twitter Card tags */} {/* Twitter Card tags */}
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content={twitterHandle} /> <meta name="twitter:creator" content={twitterHandle} />
<meta name="twitter:title" content={title} /> <meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} /> <meta name="twitter:description" content={description} />
<meta name="twitter:image" content={`${meta.url}${image}`} /> <meta name="twitter:image" content={`${basics.website}${image}`} />
</Helmet> </Helmet>
) )
} }
@ -53,12 +53,13 @@ SEO.propTypes = {
export default function SEO({ project }) { export default function SEO({ project }) {
const meta = useMeta() const meta = useMeta()
const { basics } = useResume()
const title = (project && project.title) || null const title = (project && project.title) || null
const description = (project && project.fields.excerpt) || meta.description const description = (project && project.fields.excerpt) || meta.description
const image = const image =
(project && project.img.childImageSharp.twitterImage.src) || (project && project.img.childImageSharp.twitterImage.src) ||
meta.img.childImageSharp.resize.src meta.img.childImageSharp.resize.src
const url = (project && `${meta.url}${project.slug}`) || meta.url const url = (project && `${basics.website}${project.slug}`) || basics.website
return ( return (
<MetaTags <MetaTags

View File

@ -2,10 +2,10 @@ import React from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import { Link } from 'gatsby' import { Link } from 'gatsby'
import posed from 'react-pose' import posed from 'react-pose'
import { useMeta } from '../../hooks/use-meta'
import { moveInBottom } from '../atoms/Transitions' import { moveInBottom } from '../atoms/Transitions'
import { ReactComponent as Logo } from '../../images/logo.svg' import { ReactComponent as Logo } from '../../images/logo.svg'
import styles from './LogoUnit.module.scss' import styles from './LogoUnit.module.scss'
import { useResume } from '../../hooks/use-resume'
LogoUnit.propTypes = { LogoUnit.propTypes = {
minimal: PropTypes.bool, minimal: PropTypes.bool,
@ -13,16 +13,18 @@ LogoUnit.propTypes = {
} }
export default function LogoUnit({ minimal }) { export default function LogoUnit({ minimal }) {
const { title, tagline } = useMeta() const { basics } = useResume()
const Animation = posed.div(moveInBottom) const Animation = posed.div(moveInBottom)
return ( return (
<Animation> <Animation>
<Link className={minimal ? styles.minimal : styles.logounit} to={'/'}> <Link className={minimal ? styles.minimal : styles.logounit} to={'/'}>
<Logo className={styles.logo} /> <Logo className={styles.logo} />
<h1 className={`p-name ${styles.title}`}>{title.toLowerCase()}</h1> <h1 className={`p-name ${styles.title}`}>
{basics.name.toLowerCase()}
</h1>
<p className={`p-job-title ${styles.description}`}> <p className={`p-job-title ${styles.description}`}>
{tagline.toLowerCase()} {basics.label.toLowerCase()}
</p> </p>
</Link> </Link>
</Animation> </Animation>

View File

@ -3,10 +3,7 @@ import { useStaticQuery, graphql } from 'gatsby'
const query = graphql` const query = graphql`
query Meta { query Meta {
metaYaml { metaYaml {
title
tagline
description description
url
img { img {
childImageSharp { childImageSharp {
resize(width: 980) { resize(width: 980) {