1
0
mirror of https://github.com/kremalicious/portfolio.git synced 2025-01-03 18:35:00 +01:00

resume tweaks, markdown summaries

This commit is contained in:
Matthias Kretschmann 2019-11-08 23:00:47 +01:00
parent f44e0557ed
commit 9d5e33b146
Signed by: m
GPG Key ID: 606EEEF3C479A91F
16 changed files with 450 additions and 103 deletions

View File

@ -19,7 +19,7 @@
- [💍 One data file to rule all pages](#-one-data-file-to-rule-all-pages)
- [🐱 GitHub repositories](#-github-repositories)
- [💅 Theme switcher](#-theme-switcher)
- [🗂 Resume](#-resume)
- [🗂 JSON Resume](#-json-resume)
- [🏆 SEO component](#-seo-component)
- [📇 Client-side vCard creation](#-client-side-vcard-creation)
- [💫 Page transitions](#-page-transitions)
@ -77,14 +77,14 @@ If you want to know how, have a look at the respective components:
- [`src/components/molecules/ThemeSwitch.jsx`](src/components/molecules/ThemeSwitch.jsx)
- [`src/hooks/use-dark-mode.jsx`](src/hooks/use-dark-mode.jsx)
### 🗂 Resume
### 🗂 JSON Resume
Resume page based on [JSON Resume](https://jsonresume.org) standard.
Resume page based on [JSON Resume](https://jsonresume.org) standard. Most metadata and social profiles are defined in [`content/resume.json`](content/resume.json) and used throughout the site.
If you want to know how, have a look at the respective components:
- [`src/pages/resume.jsx`](src/pages/resume.jsx)
- [`content/resume.json`](content/resume.json)
- [`src/pages/resume.jsx`](src/pages/resume.jsx)
- [`src/hooks/use-resume.js`](src/hooks/use-resume.js)
### 🏆 SEO component

View File

@ -34,7 +34,6 @@
],
"location": {
"city": "Berlin",
"country": "Germany",
"countryCode": "DE"
}
},
@ -44,7 +43,7 @@
"position": "Lead UI Designer & Developer",
"website": "https://oceanprotocol.com",
"startDate": "2017-01-01",
"summary": "Leading the UI design & development of Ocean Protocol, iterating on a components-based UI design system spanning all of Ocean Protocol's web properties. Additionally, I conceptualize, execute and iterate on the creative and visual direction of the Ocean Protocol brand.",
"summary": "Leading the UI design & development of Ocean Protocol's user interfaces, iterating on a components-based UI design system spanning all of Ocean Protocol's web properties. \n\nConceptualize, execute and iterate on the creative and visual direction of the Ocean Protocol brand.\n\nAs a core developer leading the execution of [multiple user interfaces](/oceanprotocol) and core components.",
"highlights": ["Started the company"]
},
{
@ -53,7 +52,7 @@
"website": "https://bigchaindb.com",
"startDate": "2016-12-01",
"endDate": "2018-12-31",
"summary": "Leading the UI design & development of all BigchainDB web properties. I created the initial BigchainDB brand and further conceptualized, executed and iterated on the creative and visual direction of BigchainDB. This included creating and iterating on a components-based UI design system for all of BigchainDB's web properties.",
"summary": "Leading the UI design & development of all BigchainDB web properties. I created the initial BigchainDB brand and further conceptualized, executed and iterated on the creative and visual direction of BigchainDB. This included creating and iterating on a components-based UI design system for all of [BigchainDB's user interfaces](/bigchaindb).",
"highlights": ["Started the company"]
},
{
@ -71,7 +70,7 @@
"website": "https://chartmogul.com",
"startDate": "2015-07-15",
"endDate": "2017-02-01",
"summary": "Co-designing and leading the UI design & development of various ChartMogul web properties. This included the creation of a components-based UI design system and implementing it across all web touch points. Besides designing and implementing new features, I maintained the front-end of the ChartMogul application and implemented the UI design system by refactoring most of its front-end codebase.",
"summary": "Co-designing and leading the UI design & development of various [ChartMogul web properties](/chartmogul). This included the creation of a components-based UI design system and implementing it across all web touch points.\n\nBesides designing and implementing new features, I maintained the front-end of the ChartMogul application and implemented the UI design system by refactoring most of its front-end codebase.",
"highlights": ["Started the company"]
},
{
@ -80,7 +79,7 @@
"website": "https://sharethemeal.org",
"startDate": "2014-10-01",
"endDate": "2015-06-01",
"summary": "...",
"summary": "[app and website](/sharethemeal)",
"highlights": ["Started the company"]
},
{
@ -89,21 +88,21 @@
"website": "https://ezeep.com",
"startDate": "2012-01-01",
"endDate": "2014-09-01",
"summary": "Creating an unprecedented, market-leading & award-winning user experience around printing based on the principles of emotional design way ahead of all competitors. This included defining the product based on user & market research in an iterative process and designing & building ezeeps numerous touch points, like the web app, web site, desktop apps for Windows & Mac OS X and apps for iOS & Android. On top of that I created the corporate identity and a consistent visual branding including the logo."
"summary": "Creating an unprecedented, market-leading & award-winning user experience around printing based on the principles of emotional design way ahead of all competitors.\n\nThis included defining the product based on user & market research in an iterative process and designing & building [ezeeps numerous touch points](/ezeep), like the web app, web site, desktop apps for Windows & Mac OS X and apps for iOS & Android.\n\nOn top of that I created the corporate identity and a consistent visual branding, including the logo."
},
{
"company": "Martin Luther University Halle-Wittenberg",
"position": "UI/UX Designer & Front End Developer",
"startDate": "2009-02-01",
"endDate": "2012-01-01",
"summary": "Conceptualizing & implementing numerous in-house and public facing interfaces for thousands of students and staff. Additionally, conceptualizing, creating and maintaining the blog network & community for all students & staff."
"summary": "Conceptualizing & implementing [numerous in-house and public facing interfaces](/unihalle) for thousands of students and staff. Additionally, conceptualizing, creating and maintaining the blog network & community for all students & staff."
},
{
"company": "Harz University of Applied Sciences",
"position": "Consultant & Teacher",
"startDate": "2011-02-01",
"endDate": "2011-05-01",
"summary": "Conceptualizing a web design & development university seminar and building a responsive & fluid grid framework with a basic HTML/CSS template for students of Media Informatics at the Harz University of Applied Sciences to learn and use."
"summary": "Conceptualizing a web design & development university seminar and building a [responsive & fluid grid framework](https://github.com/kremalicious/hsresponsive) with a basic HTML/CSS template for students of Media Informatics at the Harz University of Applied Sciences to learn and use."
},
{
"company": "Martin Luther University Halle-Wittenberg",
@ -144,7 +143,7 @@
{
"institution": "Martin Luther University Halle-Wittenberg",
"area": "Media/Communication Science & Art History",
"studyType": "Bachelor",
"studyType": "Bachelor of Arts",
"startDate": "2008-01-01",
"endDate": "2012-01-01"
},
@ -160,7 +159,8 @@
{
"title": "German Design Award",
"date": "2015-11-01",
"awarder": "ezeep GmbH"
"awarder": "ezeep GmbH",
"summary": "Nominated in the category _Interactive User Experience (Excellent Communications Design)_"
},
{
"title": "CeBIT Preview Award",
@ -225,13 +225,13 @@
}
],
"languages": [
{
"language": "German",
"fluency": "Native speaker"
},
{
"language": "English",
"fluency": "Advanced speaker"
},
{
"language": "German",
"fluency": "Native speaker"
}
]
}

View File

@ -2,7 +2,7 @@
const path = require('path')
const remark = require('remark')
const markdown = require('remark-parse')
const parse = require('remark-parse')
const html = require('remark-html')
const axios = require('axios')
const fs = require('fs')
@ -111,7 +111,7 @@ exports.onCreateNode = ({ node, actions }) => {
let descriptionHtml
remark()
.use(markdown, { gfm: true, commonmark: true, pedantic: true })
.use(parse, { gfm: true, commonmark: true, pedantic: true })
.use(html)
.process(descriptionWithLineBreaks, (err, file) => {
if (err) throw Error('Could not transform project description')

View File

@ -0,0 +1,276 @@
{
"contentJson": {
"basics": {
"name": "Matthias Kretschmann",
"label": "Designer & Developer",
"picture": {
"childImageSharp": {
"fixed": {
"aspectRatio": 1,
"width": 256,
"height": 256,
"src": "/static/b45f45aa8d98d4e4019a242d38f2f248/c296b/avatar.jpg",
"srcSet": "/static/b45f45aa8d98d4e4019a242d38f2f248/c296b/avatar.jpg 1x,\n/static/b45f45aa8d98d4e4019a242d38f2f248/28b3a/avatar.jpg 1.5x,\n/static/b45f45aa8d98d4e4019a242d38f2f248/72cad/avatar.jpg 2x",
"srcWebp": "/static/b45f45aa8d98d4e4019a242d38f2f248/59c88/avatar.webp",
"srcSetWebp": "/static/b45f45aa8d98d4e4019a242d38f2f248/59c88/avatar.webp 1x,\n/static/b45f45aa8d98d4e4019a242d38f2f248/bd640/avatar.webp 1.5x,\n/static/b45f45aa8d98d4e4019a242d38f2f248/b957b/avatar.webp 2x",
"originalName": "avatar.jpg"
}
}
},
"email": "m@kretschmann.io",
"website": "https://matthiaskretschmann.com",
"summary": "",
"profiles": [
{
"network": "Blog",
"url": "https://kremalicious.com",
"username": null
},
{
"network": "Twitter",
"url": "https://twitter.com/kremalicious",
"username": "kremalicious"
},
{
"network": "GitHub",
"url": "https://github.com/kremalicious",
"username": "kremalicious"
},
{
"network": "Dribbble",
"url": "https://dribbble.com/kremalicious",
"username": "kremalicious"
},
{
"network": "Keybase",
"url": "https://keybase.io/kremalicious",
"username": "kremalicious"
}
],
"location": {
"city": "Berlin",
"countryCode": "DE"
}
},
"education": [
{
"institution": "Self-taught",
"area": "UI Design & Web Development",
"studyType": "Autodidactic",
"startDate": "1999-01-01",
"endDate": "2004-01-01"
},
{
"institution": "Martin Luther University Halle-Wittenberg",
"area": "Media/Communication Science & Art History",
"studyType": "Bachelor of Arts",
"startDate": "2008-01-01",
"endDate": "2012-01-01"
},
{
"institution": "Martin Luther University Halle-Wittenberg",
"area": "Political Science & Sociology",
"studyType": "Magister Artium",
"startDate": "2006-01-01",
"endDate": "2008-01-01"
}
],
"languages": [
{
"language": "English",
"fluency": "Advanced speaker"
},
{
"language": "German",
"fluency": "Native speaker"
}
],
"skills": [
{
"name": "Design",
"level": "Master",
"keywords": [
"Product Design",
"Service Design",
"Interface Design",
"User Experience Design",
"Communication Design",
"Interaction Design",
"Information Architecture",
"Icon Design",
"Web Design",
"Typography",
"Design management"
]
},
{
"name": "Web Development",
"level": "Master",
"keywords": [
"HTML",
"CSS",
"Javascript",
"Node.js",
"npm ecosystem",
"SASS/SCSS",
"Less",
"Stylus",
"Gulp",
"Gatsby",
"React",
"Styled Components",
"JAMstack"
]
},
{
"name": "General Software Development",
"level": "Master",
"keywords": [
"Git",
"GitHub",
"Bash",
"UNIX",
"Agile: Kanban & Scrum",
"Prototyping",
"Incremental"
]
},
{
"name": "DevOps",
"level": "Intermediate",
"keywords": [
"AWS",
"Now",
"Serverless",
"Cloudflare",
"NGINX",
"Apache"
]
}
],
"work": [
{
"company": "Ocean Protocol Foundation",
"position": "Lead UI Designer & Developer",
"website": "https://oceanprotocol.com",
"startDate": "2017-01-01",
"endDate": null,
"summary": "Leading the UI design & development of Ocean Protocol's user interfaces, iterating on a components-based UI design system spanning all of Ocean Protocol's web properties. \n\nConceptualize, execute and iterate on the creative and visual direction of the Ocean Protocol brand.\n\nAs a core developer leading the execution of [multiple user interfaces](/oceanprotocol) and core components.",
"highlights": ["Started the company"]
},
{
"company": "BigchainDB GmbH",
"position": "Lead UI Designer & Developer",
"website": "https://bigchaindb.com",
"startDate": "2016-12-01",
"endDate": "2018-12-31",
"summary": "Leading the UI design & development of all BigchainDB web properties. I created the initial BigchainDB brand and further conceptualized, executed and iterated on the creative and visual direction of BigchainDB. This included creating and iterating on a components-based UI design system for all of [BigchainDB's user interfaces](/bigchaindb).",
"highlights": ["Started the company"]
},
{
"company": "ascribe GmbH",
"position": "UI Designer & Developer",
"website": "https://ascribe.io",
"startDate": "2016-01-01",
"endDate": "2017-12-31",
"summary": "Description...",
"highlights": ["Started the company"]
},
{
"company": "ChartMogul Ltd.",
"position": "Lead UI Engineer",
"website": "https://chartmogul.com",
"startDate": "2015-07-15",
"endDate": "2017-02-01",
"summary": "Co-designing and leading the UI design & development of various [ChartMogul web properties](/chartmogul). This included the creation of a components-based UI design system and implementing it across all web touch points.\n\nBesides designing and implementing new features, I maintained the front-end of the ChartMogul application and implemented the UI design system by refactoring most of its front-end codebase.",
"highlights": ["Started the company"]
},
{
"company": "UN World Food Programme/ShareTheMeal",
"position": "UI Engineer",
"website": "https://sharethemeal.org",
"startDate": "2014-10-01",
"endDate": "2015-06-01",
"summary": "[app and website](/sharethemeal)",
"highlights": ["Started the company"]
},
{
"company": "ezeep GmbH",
"position": "Lead Designer & Front End Developer",
"website": "https://ezeep.com",
"startDate": "2012-01-01",
"endDate": "2014-09-01",
"summary": "Creating an unprecedented, market-leading & award-winning user experience around printing based on the principles of emotional design way ahead of all competitors.\n\nThis included defining the product based on user & market research in an iterative process and designing & building [ezeeps numerous touch points](/ezeep), like the web app, web site, desktop apps for Windows & Mac OS X and apps for iOS & Android.\n\nOn top of that I created the corporate identity and a consistent visual branding, including the logo.",
"highlights": null
},
{
"company": "Martin Luther University Halle-Wittenberg",
"position": "UI/UX Designer & Front End Developer",
"website": null,
"startDate": "2009-02-01",
"endDate": "2012-01-01",
"summary": "Conceptualizing & implementing [numerous in-house and public facing interfaces](/unihalle) for thousands of students and staff. Additionally, conceptualizing, creating and maintaining the blog network & community for all students & staff.",
"highlights": null
},
{
"company": "Harz University of Applied Sciences",
"position": "Consultant & Teacher",
"website": null,
"startDate": "2011-02-01",
"endDate": "2011-05-01",
"summary": "Conceptualizing a web design & development university seminar and building a [responsive & fluid grid framework](https://github.com/kremalicious/hsresponsive) with a basic HTML/CSS template for students of Media Informatics at the Harz University of Applied Sciences to learn and use.",
"highlights": null
},
{
"company": "Martin Luther University Halle-Wittenberg",
"position": "Consultant & Teacher",
"website": null,
"startDate": "2011-02-01",
"endDate": "2011-05-01",
"summary": "Conceptualizing a WordPress-based web design university seminar and building a minimal starting theme for students of media & communication science at the MLU Halle-Wittenberg to learn and use.",
"highlights": null
},
{
"company": "Shortmoves",
"position": "Web Designer & Developer",
"website": null,
"startDate": "2009-01-01",
"endDate": "2010-01-01",
"summary": "Creating & managing the web presence and marketing material of the International Shortfilm Festival Shortmoves in Halle (Saale), Germany.",
"highlights": null
},
{
"company": "Agentur Ahron",
"position": "Co-Founder & Photojournalist & Photographer",
"website": null,
"startDate": "2005-01-01",
"endDate": "2008-12-31",
"summary": "Co-founded and built up a photo agency from the ground up and worked as a photographer ranging from journalistic works for news agencies & newspapers to photographic work for private clients.",
"highlights": null
},
{
"company": "Freelance",
"position": "Designer & Developer",
"website": null,
"startDate": "2004-01-01",
"endDate": null,
"summary": "Numerous projects and clients as a UI/UX Designer, Front End Developer, Icon Designer & Photographer.",
"highlights": null
}
],
"awards": [
{
"title": "German Design Award",
"date": "2015-11-01",
"awarder": "ezeep GmbH",
"summary": "Nominated in the category _Interactive User Experience (Excellent Communications Design)_"
},
{
"title": "CeBIT Preview Award",
"date": "2013-11-01",
"awarder": "ezeep GmbH",
"summary": null
}
]
}
}

View File

@ -49,8 +49,10 @@
"react-helmet": "^5.2.1",
"react-pose": "^4.0.10",
"remark": "^11.0.2",
"remark-breaks": "^1.0.3",
"remark-html": "^10.0.0",
"remark-parse": "^7.0.2",
"remark-react": "^6.0.0",
"shortid": "^2.2.15",
"suncalc": "^1.8.0",
"vcf": "^2.0.6"

View File

@ -1,7 +1,7 @@
import React from 'react'
import Helmet from 'react-helmet'
import PropTypes from 'prop-types'
import { useMeta } from '../../hooks/use-meta'`
import { useMeta } from '../../hooks/use-meta'
import { useResume } from '../../hooks/use-resume'
const MetaTags = ({ title, description, url, image, meta }) => {
@ -10,33 +10,34 @@ const MetaTags = ({ title, description, url, image, meta }) => {
({ network }) => network === 'Twitter'
)[0].username
const MetaTags = ({ title, description, url, image, meta }) => (
<Helmet
defaultTitle={`${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`}
titleTemplate={`%s // ${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`}
title={title}
>
<html lang="en" />
return (
<Helmet
defaultTitle={`${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`}
titleTemplate={`%s // ${meta.title.toLowerCase()} { ${meta.tagline.toLowerCase()} }`}
title={title}
>
<html lang="en" />
{/* General tags */}
<meta name="description" content={description} />
<meta name="image" content={`${meta.url}${image}`} />
<link rel="canonical" href={url} />
{/* General tags */}
<meta name="description" content={description} />
<meta name="image" content={`${meta.url}${image}`} />
<link rel="canonical" href={url} />
{/* OpenGraph tags */}
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={`${meta.url}${image}`} />
{/* OpenGraph tags */}
<meta property="og:url" content={url} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={`${meta.url}${image}`} />
{/* Twitter Card tags */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content={twitterHandle} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<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={twitterHandle} />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={`${meta.url}${image}`} />
</Helmet>
)
}
MetaTags.propTypes = {
title: PropTypes.string,

View File

@ -7,7 +7,6 @@ import { useResume } from '../../hooks/use-resume'
export default function Vcard() {
const metaYaml = useMeta()
const { basics } = useResume()
const data = useStaticQuery(query)
const photoSrc = basics.picture.childImageSharp.fixed.src
const { name, label, email, profiles } = basics
@ -56,6 +55,12 @@ export const downloadVcard = (vcard, meta) => {
export const constructVcard = async (dataUrl, meta) => {
const contact = new vCard()
const blog = meta.profiles.filter(({ network }) => network === 'Blog')[0].url
const twitter = meta.profiles.filter(
({ network }) => network === 'Twitter'
)[0].url
const github = meta.profiles.filter(({ network }) => network === 'GitHub')[0]
.url
// stripping this data out of base64 string is required
// for vcard to actually display the image for whatever reason
@ -66,9 +71,9 @@ export const constructVcard = async (dataUrl, meta) => {
contact.set('email', meta.email)
contact.set('nickname', 'kremalicious')
contact.set('url', meta.url, { type: 'Portfolio' })
contact.add('url', meta.social.Blog, { type: 'Blog' })
contact.add('x-socialprofile', meta.social.Twitter, { type: 'twitter' })
contact.add('x-socialprofile', meta.social.GitHub, { type: 'GitHub' })
contact.add('url', blog, { type: 'Blog' })
contact.add('x-socialprofile', twitter, { type: 'twitter' })
contact.add('x-socialprofile', github, { type: 'GitHub' })
const vcard = contact.toString('3.0')

View File

@ -3,10 +3,12 @@ import PropTypes from 'prop-types'
import posed from 'react-pose'
import { moveInTop } from '../atoms/Transitions'
import Icon from '../atoms/Icon'
import { useMeta } from '../../hooks/use-meta'
import { useResume } from '../../hooks/use-resume'
import styles from './Networks.module.scss'
const linkClasses = key =>
key === 'Email' ? `u-email ${styles.link}` : `u-url ${styles.link}`
const NetworkLink = ({ name, url }) => (
<a
className={linkClasses(name)}
@ -24,25 +26,22 @@ NetworkLink.propTypes = {
}
export default function Networks({ small, hide }) {
const { social } = useMeta()
const { basics } = useResume()
if (hide) return null
const Animation = posed.aside(moveInTop)
const linkClasses = key =>
key === 'Email' ? `u-email ${styles.link}` : `u-url ${styles.link}`
return (
<Animation className={small ? styles.small : styles.networks}>
<NetworkLink name={'Email'} url={`mailto:${basics.email}`} />
{profiles.map(profile => (
<NetworkLink
key={profile.network}
name={profile.network}
url={profile.url}
/>
))}
{basics.profiles.map(profile => (
<NetworkLink
key={profile.network}
name={profile.network}
url={profile.url}
/>
))}
</Animation>
)
}

View File

@ -18,9 +18,13 @@ export default function Header({ minimal, isResume }) {
return (
<header className={minimal ? styles.minimal : styles.header}>
<ThemeSwitch />
<LogoUnit minimal={minimal} isResume={isResume} />
<Networks hide={minimal} />
<Availability hide={minimal && !availability.status} />
{!isResume && (
<>
<LogoUnit minimal={minimal} isResume={isResume} />
<Networks hide={minimal} />
<Availability hide={minimal && !availability.status} />
</>
)}
</header>
)
}

View File

@ -7,7 +7,6 @@ const query = graphql`
tagline
description
url
email
img {
childImageSharp {
resize(width: 980) {
@ -15,21 +14,6 @@ const query = graphql`
}
}
}
avatar {
childImageSharp {
resize {
src
}
}
}
social {
Mail
Blog
Twitter
GitHub
Dribbble
Keybase
}
availability {
status
available

View File

@ -23,7 +23,6 @@ const query = graphql`
}
location {
city
country
countryCode
}
}
@ -52,6 +51,12 @@ const query = graphql`
summary
highlights
}
awards {
title
date
awarder
summary
}
}
}
`

View File

@ -0,0 +1,18 @@
import React from 'react'
import { render } from '@testing-library/react'
import { useStaticQuery } from 'gatsby'
import { useResume } from './use-resume'
import data from '../../jest/__fixtures__/resume.json'
beforeEach(() => {
useStaticQuery.mockImplementationOnce(() => ({ ...data }))
})
describe('useResume', () => {
it('renders correctly', () => {
const { basics } = useResume()
const { container } = render(<div>{basics.name}</div>)
expect(container.textContent).toBe(data.contentJson.basics.name)
})
})

View File

@ -1,14 +1,43 @@
import React from 'react'
import PropTypes from 'prop-types'
import remark from 'remark'
import remark2react from 'remark-react'
import parse from 'remark-parse'
import html from 'remark-html'
import breaks from 'remark-breaks'
import styles from './ResumeItem.module.scss'
export default function ResumeItem({ workPlace, eduPlace }) {
const title = workPlace ? workPlace.company : eduPlace.institution
const subTitle = workPlace ? workPlace.position : eduPlace.area
const text = workPlace ? workPlace.summary : eduPlace.studyType
const { startDate, endDate } = workPlace || eduPlace
export const markdownOutput = text =>
remark()
.use(parse, { gfm: true, commonmark: true, pedantic: true })
.use(html)
.use(breaks)
.use(remark2react)
.processSync(text).contents
const dateStart = new Date(startDate).getFullYear()
export default function ResumeItem({ workPlace, eduPlace, award }) {
const title = workPlace
? workPlace.company
: award
? award.title
: eduPlace.institution
const subTitle = workPlace
? workPlace.position
: award
? award.awarder
: eduPlace.area
const text = workPlace
? workPlace.summary
: award && award.summary
? award.summary
: eduPlace
? eduPlace.studyType
: null
const { startDate, endDate, date } = workPlace || eduPlace || award
const dateStart = date
? new Date(date).getFullYear()
: new Date(startDate).getFullYear()
const dateEnd = endDate && new Date(endDate).getFullYear()
const isSameYear = dateStart === dateEnd
@ -16,13 +45,15 @@ export default function ResumeItem({ workPlace, eduPlace }) {
<div className={styles.resumeItem}>
<span className={styles.time}>
{dateStart}
{dateEnd ? !isSameYear && `${dateEnd}` : 'present'}{' '}
{dateEnd
? !isSameYear && `${dateEnd}`
: !date
? 'present'
: null}{' '}
</span>
<h4 className={styles.title}>{title}</h4>
<h5 className={styles.subTitle}>{subTitle}</h5>
<p>
<em>{text}</em>
</p>
{text && markdownOutput(text)}
</div>
)
}
@ -41,5 +72,11 @@ ResumeItem.propTypes = {
institution: PropTypes.string.isRequired,
area: PropTypes.string.isRequired,
studyType: PropTypes.string
}),
award: PropTypes.shape({
date: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
awarder: PropTypes.string.isRequired,
summary: PropTypes.string
})
}

View File

@ -4,22 +4,27 @@
padding-bottom: $spacer * 3;
padding-left: $spacer;
position: relative;
border-left: 1px solid $brand-grey-light;
border-left: 1px solid rgba($brand-grey-light, 0.25);
&::before {
content: '';
display: block;
width: 1rem;
height: 1rem;
width: $font-size-small;
height: $font-size-small;
border-radius: 50%;
background: $brand-grey-light;
position: absolute;
left: -0.5rem;
left: -($font-size-small / 2);
top: 0.1rem;
}
p:last-child {
margin-bottom: 0;
}
&:last-child {
border: none;
}
}
.title {

View File

@ -7,7 +7,8 @@ import styles from './index.module.scss'
import ResumeItem from './ResumeItem'
export default function Resume() {
const { basics, education, languages, work } = useResume()
const { basics, education, languages, work, awards } = useResume()
const { name, label, email, website, location } = basics
return (
<>
@ -16,25 +17,25 @@ export default function Resume() {
<div className={styles.resume}>
<header>
<p>Résumé</p>
<h1 className={styles.title}>{basics.name}</h1>
<h2 className={styles.label}>{basics.label}</h2>
<h1 className={styles.title}>{name}</h1>
<h2 className={styles.label}>{label}</h2>
</header>
<div>
<ul className={styles.contact}>
<li>
<a href={basics.website}>
<a href={website}>
<LinkIcon type="website" />
{basics.website.replace('https://', '')}
Portfolio
</a>
</li>
<li>
<LinkIcon type="Email" />
{basics.email}
<a href={`mailto:${email}`}>Email</a>
</li>
<li>
<LinkIcon type="Info" />
{basics.location.city}
{location.city}, {location.countryCode}
</li>
<li>
<LinkIcon type="Info" />
@ -56,6 +57,15 @@ export default function Resume() {
))}
</div>
<div>
<h3 className={styles.subTitle}>Awards</h3>
</div>
<div>
{awards.map(award => (
<ResumeItem key={shortid.generate()} award={award} />
))}
</div>
<div>
<h3 className={styles.subTitle}>Education</h3>
</div>

View File

@ -46,13 +46,14 @@
}
@media (min-width: $screen-md) {
margin-top: $spacer * 2;
margin-top: $spacer * 2.25;
}
}
.subTitle {
font-size: $font-size-h3;
margin-bottom: 0;
margin-top: -($spacer / 3);
}
@media print {