From 9d5e33b146abdf4568610cfd06fa94b69fb696f1 Mon Sep 17 00:00:00 2001 From: Matthias Kretschmann Date: Fri, 8 Nov 2019 23:00:47 +0100 Subject: [PATCH] resume tweaks, markdown summaries --- README.md | 8 +- content/resume.json | 28 +-- gatsby-node.js | 4 +- jest/__fixtures__/resume.json | 276 ++++++++++++++++++++++++ package.json | 2 + src/components/atoms/SEO.jsx | 51 ++--- src/components/atoms/Vcard.jsx | 13 +- src/components/molecules/Networks.jsx | 23 +- src/components/organisms/Header.jsx | 10 +- src/hooks/use-meta.js | 16 -- src/hooks/use-resume.js | 7 +- src/hooks/use-resume.test.js | 18 ++ src/pages/resume/ResumeItem.jsx | 57 ++++- src/pages/resume/ResumeItem.module.scss | 13 +- src/pages/resume/index.jsx | 24 ++- src/pages/resume/index.module.scss | 3 +- 16 files changed, 450 insertions(+), 103 deletions(-) create mode 100644 jest/__fixtures__/resume.json create mode 100644 src/hooks/use-resume.test.js diff --git a/README.md b/README.md index 7d45f34..56b9942 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/content/resume.json b/content/resume.json index 7e4e6a6..5ce0dd4 100644 --- a/content/resume.json +++ b/content/resume.json @@ -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 ezeep’s 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 [ezeep’s 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" } ] } diff --git a/gatsby-node.js b/gatsby-node.js index 0a4ff71..0152446 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -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') diff --git a/jest/__fixtures__/resume.json b/jest/__fixtures__/resume.json new file mode 100644 index 0000000..12b5acd --- /dev/null +++ b/jest/__fixtures__/resume.json @@ -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 [ezeep’s 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 + } + ] + } +} diff --git a/package.json b/package.json index a18aa02..a0d0205 100644 --- a/package.json +++ b/package.json @@ -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" diff --git a/src/components/atoms/SEO.jsx b/src/components/atoms/SEO.jsx index 725e075..faff192 100644 --- a/src/components/atoms/SEO.jsx +++ b/src/components/atoms/SEO.jsx @@ -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 }) => ( - - + return ( + + - {/* General tags */} - - - + {/* General tags */} + + + - {/* OpenGraph tags */} - - - - + {/* OpenGraph tags */} + + + + - {/* Twitter Card tags */} - - - - - - -) + {/* Twitter Card tags */} + + + + + + + ) +} MetaTags.propTypes = { title: PropTypes.string, diff --git a/src/components/atoms/Vcard.jsx b/src/components/atoms/Vcard.jsx index b462868..d1b3bcc 100644 --- a/src/components/atoms/Vcard.jsx +++ b/src/components/atoms/Vcard.jsx @@ -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') diff --git a/src/components/molecules/Networks.jsx b/src/components/molecules/Networks.jsx index c6430e8..917ce3f 100644 --- a/src/components/molecules/Networks.jsx +++ b/src/components/molecules/Networks.jsx @@ -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 }) => ( - key === 'Email' ? `u-email ${styles.link}` : `u-url ${styles.link}` - return ( - {profiles.map(profile => ( - - ))} + {basics.profiles.map(profile => ( + + ))} ) } diff --git a/src/components/organisms/Header.jsx b/src/components/organisms/Header.jsx index 95e330d..021ed69 100644 --- a/src/components/organisms/Header.jsx +++ b/src/components/organisms/Header.jsx @@ -18,9 +18,13 @@ export default function Header({ minimal, isResume }) { return (
- - - + {!isResume && ( + <> + + + + + )}
) } diff --git a/src/hooks/use-meta.js b/src/hooks/use-meta.js index b917d18..5335eef 100644 --- a/src/hooks/use-meta.js +++ b/src/hooks/use-meta.js @@ -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 diff --git a/src/hooks/use-resume.js b/src/hooks/use-resume.js index ebbee65..d422316 100644 --- a/src/hooks/use-resume.js +++ b/src/hooks/use-resume.js @@ -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 + } } } ` diff --git a/src/hooks/use-resume.test.js b/src/hooks/use-resume.test.js new file mode 100644 index 0000000..ef4ba21 --- /dev/null +++ b/src/hooks/use-resume.test.js @@ -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(
{basics.name}
) + + expect(container.textContent).toBe(data.contentJson.basics.name) + }) +}) diff --git a/src/pages/resume/ResumeItem.jsx b/src/pages/resume/ResumeItem.jsx index 0b91189..b18f209 100644 --- a/src/pages/resume/ResumeItem.jsx +++ b/src/pages/resume/ResumeItem.jsx @@ -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 }) {
{dateStart} - {dateEnd ? !isSameYear && `–${dateEnd}` : '–present'}{' '} + {dateEnd + ? !isSameYear && `–${dateEnd}` + : !date + ? '–present' + : null}{' '}

{title}

{subTitle}
-

- {text} -

+ {text && markdownOutput(text)}
) } @@ -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 }) } diff --git a/src/pages/resume/ResumeItem.module.scss b/src/pages/resume/ResumeItem.module.scss index b4e6dc1..1ce0ee5 100644 --- a/src/pages/resume/ResumeItem.module.scss +++ b/src/pages/resume/ResumeItem.module.scss @@ -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 { diff --git a/src/pages/resume/index.jsx b/src/pages/resume/index.jsx index eec1b5a..034633b 100644 --- a/src/pages/resume/index.jsx +++ b/src/pages/resume/index.jsx @@ -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() {

Résumé

-

{basics.name}

-

{basics.label}

+

{name}

+

{label}

+
+

Awards

+
+
+ {awards.map(award => ( + + ))} +
+

Education

diff --git a/src/pages/resume/index.module.scss b/src/pages/resume/index.module.scss index cffc176..a38214f 100644 --- a/src/pages/resume/index.module.scss +++ b/src/pages/resume/index.module.scss @@ -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 {