feat(deps): remove Handlebars dependency

This commit is contained in:
Rafael Bardini 2023-01-30 02:38:45 +01:00
parent b79cb14c7e
commit de8646432b
41 changed files with 839 additions and 810 deletions

View File

@ -7,10 +7,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v2
uses: actions/setup-node@v3
with:
node-version: 16
@ -27,4 +27,4 @@ jobs:
run: npm run build
- name: Coverage
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v3

29
components/awards.js Normal file
View File

@ -0,0 +1,29 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Date from './date.js'
export default function Awards(awards = []) {
return awards.length > 0 && html`
<section id="awards">
<h3>Awards</h3>
<div class="stack">
${awards.map(({ awarder, date, summary, title }) => html`
<article>
<header>
<h4>${title}</h4>
<div class="meta">
${awarder && html`
<div>
Awarded by <strong>${awarder}</strong>
</div>
`}
${date && Date(date)}
</div>
</header>
${summary && markdown(summary)}
</article>
`)}
</div>
</section>
`
}

View File

@ -0,0 +1,28 @@
import html from '../utils/html.js'
import Date from './date.js'
import Link from './link.js'
export default function Certificates(certificates = []) {
return certificates.length > 0 && html`
<section id="certificates">
<h3>Certificates</h3>
<div class="stack">
${certificates.map(({ date, issuer, name, url }) => html`
<article>
<header>
<h4>${Link(url, name)}</h4>
<div class="meta">
${issuer && html`
<div>
Issued by <strong>${issuer}</strong>
</div>
`}
${date && Date(date)}
</div>
</header>
</article>
`)}
</div>
</section>
`
}

12
components/date.js Normal file
View File

@ -0,0 +1,12 @@
import html from '../utils/html.js'
const formatDate = dateString =>
new Date(dateString).toLocaleDateString('en', {
month: 'short',
year: 'numeric',
timeZone: 'UTC',
})
export default function Duration(date) {
return html`<time datetime="${date}">${formatDate(date)}</time>`
}

6
components/duration.js Normal file
View File

@ -0,0 +1,6 @@
import html from '../utils/html.js'
import Date from './date.js'
export default function Duration(startDate, endDate) {
return html`${Date(startDate)} ${endDate ? Date(endDate) : 'Present'}`
}

32
components/education.js Normal file
View File

@ -0,0 +1,32 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Duration from './duration.js'
import Link from './link.js'
export default function Education(education = []) {
return education.length > 0 && html`
<section id="education">
<h3>Education</h3>
<div class="stack">
${education.map(({ area, courses = [], institution, startDate, endDate, studyType, url }) => html`
<article>
<header>
<h4>${Link(url, institution)}</h4>
<div class="meta">
${area && html`<strong>${area}</strong>`}
<div>${Duration(startDate, endDate)}</div>
</div>
</header>
${studyType && markdown(studyType)}
${courses.length > 0 && html`
<h5>Courses</h5>
<ul>
${courses.map(course => html`<li>${markdown(course)}</li>`)}
</ul>
`}
</article>
`)}
</div>
</section>
`
}

56
components/header.js Normal file
View File

@ -0,0 +1,56 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Icon from './icon.js'
import Link from './link.js'
const formatCountry = countryCode => Intl.DisplayNames
? new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode)
: countryCode
export default function Header(basics = {}) {
const { email, image, label, location, name, phone, profiles = [], summary, url } = basics
return html`
<header class="masthead">
${image && html`<img src="${image}" alt="">`}
<div>
${name && html`<h1>${name}</h1>`}
${label && html`<h2>${label}</h2>`}
</div>
${summary && html`<article>${markdown(summary)}</article>`}
<ul class="icon-list">
${location?.city && html`
<li>
${Icon('map-pin')}
${location.city}${location.countryCode && html`, ${formatCountry(location.countryCode)}`}
</li>
`}
${email && html`
<li>
${Icon('mail')}
<a href="mailto:${email}">${email}</a>
</li>
`}
${phone && html`
<li>
${Icon('phone')}
<a href="tel:${phone.replace(/\s/g, '')}">${phone}</a>
</li>
`}
${url && html`
<li>
${Icon('link')}
${Link(url)}
</li>
`}
${profiles.map(({ network, url, username }) => html`
<li>
${Icon(network, 'user')}
${Link(url, username)}
${network && html`<span class="network">(${network})</span>`}
</li>
`)}
</ul>
</header>
`
}

6
components/icon.js Normal file
View File

@ -0,0 +1,6 @@
import { icons } from 'feather-icons'
export default function Icon(name, fallback) {
const ico = icons[name.toLowerCase()] || icons[fallback.toLowerCase()]
return ico.toSvg({ width: 16, height: 16 })
}

21
components/interests.js Normal file
View File

@ -0,0 +1,21 @@
import html from '../utils/html.js'
export default function Interests(interests = []) {
return interests.length > 0 && html`
<section id="interests">
<h3>Interests</h3>
<div class="grid-list">
${interests.map(({ keywords = [], name }) => html`
<div>
${name && html`<h4>${name}</h4>`}
${keywords.length > 0 && html`
<ul class="tag-list">
${keywords.map(keyword => html`<li>${keyword}</li>`)}
</ul>
`}
</div>
`)}
</div>
</section>
`
}

17
components/languages.js Normal file
View File

@ -0,0 +1,17 @@
import html from '../utils/html.js'
export default function Languages(languages = []) {
return languages.length > 0 && html`
<section id="languages">
<h3>Languages</h3>
<div class="grid-list">
${languages.map(({ fluency, language }) => html`
<div>
${language && html`<h4>${language}</h4>`}
${fluency}
</div>
`)}
</div>
</section>
`
}

9
components/link.js Normal file
View File

@ -0,0 +1,9 @@
import html from '../utils/html.js'
const formatURL = url => url.replace(/^(https?:|)\/\//, '').replace(/\/$/, '')
export default function Link(url, name) {
return name
? (url ? html`<a href="${url}">${name}</a>` : name)
: url && html`<a href="${url}">${formatURL(url)}</a>`
}

11
components/meta.js Normal file
View File

@ -0,0 +1,11 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
export default function Meta(basics = {}) {
const { name, summary } = basics
return html`
${name && html`<title>${name}</title>`}
${summary && html`<meta name="description" content="${markdown(summary, true)}">`}
`
}

38
components/projects.js Normal file
View File

@ -0,0 +1,38 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Duration from './duration.js'
import Link from './link.js'
const formatRoles = arr => Intl.ListFormat
? new Intl.ListFormat('en').format(arr)
: arr.join(', ')
export default function Projects(projects = []) {
return projects.length > 0 && html`
<section id="projects">
<h3>Projects</h3>
<div class="stack">
${projects.map(({ description, entity, highlights = [], name, startDate, endDate, roles = [], url }) => html`
<article>
<header>
<h4>${Link(url, name)}</h4>
<div class="meta">
<div>
${roles.length > 0 && html`<strong>${formatRoles(roles)}</strong>`}
${entity && html`at <strong>${entity}</strong>`}
</div>
<div>${Duration(startDate, endDate)}</div>
</div>
</header>
${description && markdown(description)}
${highlights.length > 0 && html`
<ul>
${highlights.map(highlight => html`<li>${markdown(highlight)}</li>`)}
</ul>
`}
</article>
`)}
</div>
</section>
`
}

View File

@ -0,0 +1,30 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Date from './date.js'
import Link from './link.js'
export default function Publications(publications = []) {
return publications.length > 0 && html`
<section id="publications">
<h3>Publications</h3>
<div class="stack">
${publications.map(({ name, publisher, releaseDate, summary, url }) => html`
<article>
<header>
<h4>${Link(url, name)}</h4>
<div class="meta">
${publisher && html`
<div>
Published by <strong>${publisher}</strong>
</div>
`}
${releaseDate && Date(releaseDate)}
</div>
</header>
${summary && markdown(summary)}
</article>
`)}
</div>
</section>
`
}

22
components/references.js Normal file
View File

@ -0,0 +1,22 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
export default function References(references = []) {
return references.length > 0 && html`
<section id="references">
<h3>References</h3>
<div class="stack">
${references.map(({ name, reference }) => html`
<blockquote>
${reference && markdown(reference)}
${name && html`
<p>
<cite>${name}</cite>
</p>
`}
</blockquote>
`)}
</div>
</section>
`
}

21
components/skills.js Normal file
View File

@ -0,0 +1,21 @@
import html from '../utils/html.js'
export default function Skills(skills = []) {
return skills.length > 0 && html`
<section id="skills">
<h3>Skills</h3>
<div class="grid-list">
${skills.map(({ keywords = [], name }) => html`
<div>
${name && html`<h4>${name}</h4>`}
${keywords.length > 0 && html`
<ul class="tag-list">
${keywords.map(keyword => html`<li>${keyword}</li>`)}
</ul>
`}
</div>
`)}
</div>
</section>
`
}

31
components/volunteer.js Normal file
View File

@ -0,0 +1,31 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Duration from './duration.js'
import Link from './link.js'
export default function Volunteer(volunteer = []) {
return volunteer.length > 0 && html`
<section id="volunteer">
<h3>Volunteer</h3>
<div class="stack">
${volunteer.map(({ highlights = [], organization, position, startDate, endDate, summary, url }) => html`
<article>
<header>
<h4>${position}</h4>
<div class="meta">
<strong>${Link(url, organization)}</strong>
<div>${Duration(startDate, endDate)}</div>
</div>
</header>
${summary && markdown(summary)}
${highlights.length > 0 && html`
<ul>
${highlights.map(highlight => html`<li>${markdown(highlight)}</li>`)}
</ul>
`}
</article>
`)}
</div>
</section>
`
}

35
components/work.js Normal file
View File

@ -0,0 +1,35 @@
import html from '../utils/html.js'
import markdown from '../utils/markdown.js'
import Duration from './duration.js'
import Link from './link.js'
export default function Work(work = []) {
return work.length > 0 && html`
<section id="work">
<h3>Work</h3>
<div class="stack">
${work.map(({ description, highlights = [], location, name, position, startDate, endDate, summary, url }) => html`
<article>
<header>
<h4>${position}</h4>
<div class="meta">
<div>
<strong>${Link(url, name)}</strong>
${description && html`<span class="bullet-item">${description}</span>`}
</div>
<div>${Duration(startDate, endDate)}</div>
${location && html`<div>${location}</div>`}
</div>
</header>
${summary && markdown(summary)}
${highlights.length > 0 && html`
<ul>
${highlights.map(highlight => html`<li>${markdown(highlight)}</li>`)}
</ul>
`}
</article>
`)}
</div>
</section>
`
}

View File

@ -1,70 +1,17 @@
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import { icons } from 'feather-icons'
import Handlebars from 'handlebars'
import micromark from 'micromark'
import striptags from 'striptags'
const dirname =
typeof __dirname === 'string'
? __dirname
: path.dirname(fileURLToPath(import.meta.url))
const extname = '.hbs'
const partialsDir = path.join(dirname, 'partials')
import Resume from './resume.js'
fs.readdirSync(partialsDir)
.filter(filename => path.extname(filename) === extname)
.map(filename => [
filename,
fs.readFileSync(path.join(partialsDir, filename), 'utf8'),
])
.forEach(([filename, template]) =>
Handlebars.registerPartial(path.basename(filename, extname), template),
)
Handlebars.registerHelper('formatCountry', countryCode =>
Intl.DisplayNames
? new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode)
: countryCode,
)
Handlebars.registerHelper('formatDate', dateString =>
new Date(dateString).toLocaleDateString('en', {
month: 'short',
year: 'numeric',
timeZone: 'UTC',
}),
)
Handlebars.registerHelper('formatPhone', phone =>
phone.replace(/[^\d|+]+/g, ''),
)
Handlebars.registerHelper('formatURL', url =>
url.replace(/^(https?:|)\/\//, '').replace(/\/$/, ''),
)
Handlebars.registerHelper('icon', (name, fallback) =>
(icons[name.toLowerCase()] || icons[fallback.toLowerCase()]).toSvg({
width: 16,
height: 16,
}),
)
Handlebars.registerHelper('join', arr =>
Intl.ListFormat ? new Intl.ListFormat('en').format(arr) : arr.join(', '),
)
Handlebars.registerHelper('markdown', doc => micromark(doc))
Handlebars.registerHelper('stripTags', html => striptags(html))
const dirname = typeof __dirname === 'string'
? __dirname
: path.dirname(fileURLToPath(import.meta.url))
export const pdfRenderOptions = { mediaType: 'print' }
export const render = resume => {
const template = fs.readFileSync(path.resolve(dirname, 'resume.hbs'), 'utf-8')
const css = fs.readFileSync(path.resolve(dirname, 'style.css'), 'utf-8')
return Handlebars.compile(template)({ css, resume })
return Resume(resume, css)
}

200
package-lock.json generated
View File

@ -10,7 +10,6 @@
"license": "MIT",
"dependencies": {
"feather-icons": "^4.28.0",
"handlebars": "^4.7.0",
"micromark": "^2.11.0",
"striptags": "^3.2.0"
},
@ -55,9 +54,9 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.20.10",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.10.tgz",
"integrity": "sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==",
"version": "7.20.14",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz",
"integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@ -103,9 +102,9 @@
}
},
"node_modules/@babel/generator": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.7.tgz",
"integrity": "sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==",
"version": "7.20.14",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
"integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==",
"dev": true,
"dependencies": {
"@babel/types": "^7.20.7",
@ -471,13 +470,13 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.7.tgz",
"integrity": "sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==",
"version": "7.20.13",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz",
"integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==",
"dev": true,
"dependencies": {
"@babel/template": "^7.20.7",
"@babel/traverse": "^7.20.7",
"@babel/traverse": "^7.20.13",
"@babel/types": "^7.20.7"
},
"engines": {
@ -570,9 +569,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.7.tgz",
"integrity": "sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==",
"version": "7.20.13",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz",
"integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -1141,9 +1140,9 @@
}
},
"node_modules/@babel/plugin-transform-block-scoping": {
"version": "7.20.11",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.11.tgz",
"integrity": "sha512-tA4N427a7fjf1P0/2I4ScsHGc5jcHPbb30xMbaTke2gxDuWpUfXDuX1FEymJwKk4tuGUvGcejAR6HdZVqmmPyw==",
"version": "7.20.14",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.14.tgz",
"integrity": "sha512-sMPepQtsOs5fM1bwNvuJJHvaCfOEQfmc01FGw0ELlTpTJj5Ql/zuNRRldYhAPys4ghXdBIQJbRVYi44/7QflQQ==",
"dev": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.20.2"
@ -1503,9 +1502,9 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.7.tgz",
"integrity": "sha512-Tfq7qqD+tRj3EoDhY00nn2uP2hsRxgYGi5mLQ5TimKav0a9Lrpd4deE+fcLXU8zFYRjlKPHZhpCvfEA6qnBxqQ==",
"version": "7.20.13",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.20.13.tgz",
"integrity": "sha512-MmTZx/bkUrfJhhYAYt3Urjm+h8DQGrPrnKQ94jLo7NLuOU+T89a7IByhKmrb8SKhrIYIQ0FN0CHMbnFRen4qNw==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.18.6",
@ -1858,9 +1857,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.7.tgz",
"integrity": "sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ==",
"version": "7.20.13",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
"integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
"dev": true,
"dependencies": {
"regenerator-runtime": "^0.13.11"
@ -1884,9 +1883,9 @@
}
},
"node_modules/@babel/traverse": {
"version": "7.20.12",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.12.tgz",
"integrity": "sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==",
"version": "7.20.13",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz",
"integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.18.6",
@ -1895,7 +1894,7 @@
"@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.20.7",
"@babel/parser": "^7.20.13",
"@babel/types": "^7.20.7",
"debug": "^4.1.0",
"globals": "^11.1.0"
@ -2429,9 +2428,9 @@
}
},
"node_modules/acorn": {
"version": "8.8.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz",
"integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==",
"version": "8.8.2",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
"integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
"dev": true,
"bin": {
"acorn": "bin/acorn"
@ -2929,9 +2928,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001442",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001442.tgz",
"integrity": "sha512-239m03Pqy0hwxYPYR5JwOIxRJfLTWtle9FV8zosfV5pHg+/51uD4nxcUlM8+mWWGfwKtt8lJNHnD3cWw9VZ6ow==",
"version": "1.0.30001449",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001449.tgz",
"integrity": "sha512-CPB+UL9XMT/Av+pJxCKGhdx+yg1hzplvFJQlJ2n68PyQGMz9L/E2zCyLdOL8uasbouTUgnPl+y0tccI/se+BEw==",
"dev": true,
"funding": [
{
@ -3184,9 +3183,9 @@
"dev": true
},
"node_modules/core-js": {
"version": "3.27.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
"version": "3.27.2",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz",
"integrity": "sha512-9ashVQskuh5AZEZ1JdQWp1GqSoC1e1G87MzRqg2gIfVAQ7Qn9K+uFj8EcniUFA4P2NLZfV+TOlX1SzoKfo+s7w==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@ -3194,9 +3193,9 @@
}
},
"node_modules/core-js-compat": {
"version": "3.27.1",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.1.tgz",
"integrity": "sha512-Dg91JFeCDA17FKnneN7oCMz4BkQ4TcffkgHP4OWwp9yx3pi7ubqMDXXSacfNak1PQqjc95skyt+YBLHQJnkJwA==",
"version": "3.27.2",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz",
"integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==",
"dev": true,
"dependencies": {
"browserslist": "^4.21.4"
@ -3439,9 +3438,9 @@
"dev": true
},
"node_modules/deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz",
"integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -3621,13 +3620,14 @@
}
},
"node_modules/es-abstract": {
"version": "1.21.0",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.0.tgz",
"integrity": "sha512-GUGtW7eXQay0c+PRq0sGIKSdaBorfVqsCMhGHo4elP7YVqZu9nCZS4UkK4gv71gOWNMra/PaSKD3ao1oWExO0g==",
"version": "1.21.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.1.tgz",
"integrity": "sha512-QudMsPOz86xYz/1dG1OuGBKOELjCh99IIWHLzy5znUB6j8xG2yMA7bfTV86VSqKF+Y/H08vQPR+9jyXpuC6hfg==",
"dev": true,
"dependencies": {
"available-typed-arrays": "^1.0.5",
"call-bind": "^1.0.2",
"es-set-tostringtag": "^2.0.0",
"es-set-tostringtag": "^2.0.1",
"es-to-primitive": "^1.2.1",
"function-bind": "^1.1.1",
"function.prototype.name": "^1.1.5",
@ -3640,7 +3640,7 @@
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"internal-slot": "^1.0.4",
"is-array-buffer": "^3.0.0",
"is-array-buffer": "^3.0.1",
"is-callable": "^1.2.7",
"is-negative-zero": "^2.0.2",
"is-regex": "^1.1.4",
@ -4031,9 +4031,9 @@
}
},
"node_modules/filelist/node_modules/minimatch": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@ -4283,9 +4283,9 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz",
"integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
"integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.1",
@ -4334,9 +4334,9 @@
}
},
"node_modules/glob": {
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz",
"integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==",
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
@ -4374,9 +4374,9 @@
}
},
"node_modules/glob/node_modules/minimatch": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz",
"integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==",
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@ -4386,9 +4386,9 @@
}
},
"node_modules/globals": {
"version": "13.19.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz",
"integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==",
"version": "13.20.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
"integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@ -4472,26 +4472,6 @@
"integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
"dev": true
},
"node_modules/handlebars": {
"version": "4.7.7",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz",
"integrity": "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA==",
"dependencies": {
"minimist": "^1.2.5",
"neo-async": "^2.6.0",
"source-map": "^0.6.1",
"wordwrap": "^1.0.0"
},
"bin": {
"handlebars": "bin/handlebars"
},
"engines": {
"node": ">=0.4.7"
},
"optionalDependencies": {
"uglify-js": "^3.1.4"
}
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
@ -5391,9 +5371,9 @@
}
},
"node_modules/js-sdsl": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz",
"integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==",
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.3.0.tgz",
"integrity": "sha512-mifzlm2+5nZ+lEcLJMoBK0/IH/bDg8XnJfd/Wq6IP+xoCjLZsTOnV2QpxlVbX9bMnkl5PdEjNtBJ9Cj1NjifhQ==",
"dev": true,
"funding": {
"type": "opencollective",
@ -5567,9 +5547,9 @@
}
},
"node_modules/listr2": {
"version": "5.0.6",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.6.tgz",
"integrity": "sha512-u60KxKBy1BR2uLJNTWNptzWQ1ob/gjMzIJPZffAENzpZqbMZ/5PrXXOomDcevIS/+IB7s1mmCEtSlT2qHWMqag==",
"version": "5.0.7",
"resolved": "https://registry.npmjs.org/listr2/-/listr2-5.0.7.tgz",
"integrity": "sha512-MD+qXHPmtivrHIDRwPYdfNkrzqDiuaKU/rfBcec3WMyMF3xylQj3jMq344OtvQxz7zaCFViRAeqlr2AFhPvXHw==",
"dev": true,
"dependencies": {
"cli-truncate": "^2.1.0",
@ -5577,7 +5557,7 @@
"log-update": "^4.0.0",
"p-map": "^4.0.0",
"rfdc": "^1.3.0",
"rxjs": "^7.5.7",
"rxjs": "^7.8.0",
"through": "^2.3.8",
"wrap-ansi": "^7.0.0"
},
@ -6072,6 +6052,7 @@
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
"integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -6138,11 +6119,6 @@
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
"dev": true
},
"node_modules/neo-async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
},
"node_modules/node-preload": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
@ -6487,9 +6463,9 @@
}
},
"node_modules/object-inspect": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz",
"integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==",
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -7549,9 +7525,9 @@
}
},
"node_modules/punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
"dev": true,
"engines": {
"node": ">=6"
@ -8368,6 +8344,7 @@
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@ -10824,9 +10801,9 @@
"dev": true
},
"node_modules/tslib": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
"integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==",
"dev": true
},
"node_modules/type-check": {
@ -10889,18 +10866,6 @@
"node": ">=4.2.0"
}
},
"node_modules/uglify-js": {
"version": "3.17.4",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
"integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
"optional": true,
"bin": {
"uglifyjs": "bin/uglifyjs"
},
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
@ -11113,11 +11078,6 @@
"node": ">=0.10.0"
}
},
"node_modules/wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",

View File

@ -38,7 +38,7 @@
],
"scripts": {
"build": "microbundle build --target node",
"postbuild": "cp -r resume.hbs partials style.css dist",
"postbuild": "cp -r style.css dist",
"prebuild:demo": "npm run build",
"build:demo": "mkdir -p public && cat node_modules/resume-schema/sample.resume.json | ./bin/cli.js > public/index.html",
"format": "prettier --ignore-path .gitignore .",
@ -49,7 +49,6 @@
},
"dependencies": {
"feather-icons": "^4.28.0",
"handlebars": "^4.7.0",
"micromark": "^2.11.0",
"striptags": "^3.2.0"
},

View File

@ -1,27 +0,0 @@
{{#if resume.awards.length}}
<section id="awards">
<h3>Awards</h3>
<div class="stack">
{{#each resume.awards}}
<article>
<header>
<h4>{{title}}</h4>
<div class="meta">
{{#awarder}}
<div>
Awarded by <strong>{{.}}</strong>
</div>
{{/awarder}}
{{#date}}
<time datetime="{{.}}">{{formatDate .}}</time>
{{/date}}
</div>
</header>
{{#summary}}
{{{markdown .}}}
{{/summary}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,24 +0,0 @@
{{#if resume.certificates.length}}
<section id="certificates">
<h3>Certificates</h3>
<div class="stack">
{{#each resume.certificates}}
<article>
<header>
<h4>{{> link}}</h4>
<div class="meta">
{{#issuer}}
<div>
Issued by <strong>{{.}}</strong>
</div>
{{/issuer}}
{{#date}}
<time datetime="{{.}}">{{formatDate .}}</time>
{{/date}}
</div>
</header>
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,34 +0,0 @@
{{#if resume.education.length}}
<section id="education">
<h3>Education</h3>
<div class="stack">
{{#each resume.education}}
<article>
<header>
<h4>{{> link name=institution}}</h4>
<div class="meta">
{{#area}}
<strong>{{.}}</strong>
{{/area}}
<div>
<time datetime="{{startDate}}">{{formatDate startDate}}</time>
{{#if endDate}}<time datetime="{{endDate}}">{{formatDate endDate}}</time>{{else}}Present{{/if}}
</div>
</div>
</header>
{{#studyType}}
{{{markdown .}}}
{{/studyType}}
{{#if courses.length}}
<h5>Courses</h5>
<ul>
{{#courses}}
<li>{{{markdown .}}}</li>
{{/courses}}
</ul>
{{/if}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,65 +0,0 @@
<header class="masthead">
{{#image}}
<img src="{{.}}" alt="">
{{/image}}
<div>
{{#name}}
<h1>{{.}}</h1>
{{/name}}
{{#label}}
<h2>{{.}}</h2>
{{/label}}
</div>
{{#summary}}
<article>
{{{markdown .}}}
</article>
{{/summary}}
<ul class="icon-list">
{{#location}}
{{#if city}}
<li>
{{{icon 'map-pin'}}}
{{city}}{{#countryCode}}, {{formatCountry .}}{{/countryCode}}
</li>
{{/if}}
{{/location}}
{{#email}}
<li>
{{{icon 'mail'}}}
<a href="mailto:{{.}}">{{.}}</a>
</li>
{{/email}}
{{#phone}}
<li>
{{{icon 'phone'}}}
<a href="tel:{{formatPhone .}}">{{.}}</a>
</li>
{{/phone}}
{{#url}}
<li>
{{{icon 'link'}}}
<a href="{{.}}">{{formatURL .}}</a>
</li>
{{/url}}
{{#profiles}}
<li>
{{{icon network 'user'}}}
{{#if username}}
{{#if url}}
<a href="{{url}}">{{username}}</a>
{{else}}
{{username}}
{{/if}}
{{else}}
{{#url}}
<a href="{{.}}">{{formatURL .}}</a>
{{/url}}
{{/if}}
{{#network}}
<span class="network">({{.}})</span>
{{/network}}
</li>
{{/profiles}}
</ul>
</header>

View File

@ -1,21 +0,0 @@
{{#if resume.interests.length}}
<section id="interests">
<h3>Interests</h3>
<div class="grid-list">
{{#each resume.interests}}
<div>
{{#name}}
<h4>{{.}}</h4>
{{/name}}
{{#if keywords.length}}
<ul class="tag-list">
{{#keywords}}
<li>{{.}}</li>
{{/keywords}}
</ul>
{{/if}}
</div>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,15 +0,0 @@
{{#if resume.languages.length}}
<section id="languages">
<h3>Languages</h3>
<div class="grid-list">
{{#each resume.languages}}
<div>
{{#language}}
<h4>{{.}}</h4>
{{/language}}
{{fluency}}
</div>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1 +0,0 @@
{{#if name}}{{#if url}}<a href="{{url}}">{{name}}</a>{{else}}{{name}}{{/if}}{{else}}{{#url}}<a href="{{.}}">{{formatURL .}}</a>{{/url}}{{/if}}

View File

@ -1,2 +0,0 @@
{{#name}}<title>{{.}}</title>{{/name}}
{{#summary}}<meta name="description" content="{{stripTags (markdown .)}}">{{/summary}}

View File

@ -1,38 +0,0 @@
{{#if resume.projects.length}}
<section id="projects">
<h3>Projects</h3>
<div class="stack">
{{#each resume.projects}}
<article>
<header>
<h4>{{> link}}</h4>
<div class="meta">
<div>
{{#if roles}}
<strong>{{join roles}}</strong>
{{/if}}
{{#entity}}
at <strong>{{.}}</strong>
{{/entity}}
</div>
<div>
<time datetime="{{startDate}}">{{formatDate startDate}}</time>
{{#if endDate}}<time datetime="{{endDate}}">{{formatDate endDate}}</time>{{else}}Present{{/if}}
</div>
</div>
</header>
{{#description}}
{{{markdown .}}}
{{/description}}
{{#if highlights.length}}
<ul>
{{#highlights}}
<li>{{{markdown .}}}</li>
{{/highlights}}
</ul>
{{/if}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,27 +0,0 @@
{{#if resume.publications.length}}
<section id="publications">
<h3>Publications</h3>
<div class="stack">
{{#each resume.publications}}
<article>
<header>
<h4>{{> link}}</h4>
<div class="meta">
{{#publisher}}
<div>
Published by <strong>{{.}}</strong>
</div>
{{/publisher}}
{{#releaseDate}}
<time datetime="{{.}}">{{formatDate .}}</time>
{{/releaseDate}}
</div>
</header>
{{#summary}}
{{{markdown .}}}
{{/summary}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,19 +0,0 @@
{{#if resume.references.length}}
<section id="references">
<h3>References</h3>
<div class="stack">
{{#each resume.references}}
{{#if reference}}
<blockquote>
{{{markdown reference}}}
{{#name}}
<p>
<cite>{{.}}</cite>
</p>
{{/name}}
</blockquote>
{{/if}}
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,21 +0,0 @@
{{#if resume.skills.length}}
<section id="skills">
<h3>Skills</h3>
<div class="grid-list">
{{#each resume.skills}}
<div>
{{#name}}
<h4>{{.}}</h4>
{{/name}}
{{#if keywords.length}}
<ul class="tag-list">
{{#keywords}}
<li>{{.}}</li>
{{/keywords}}
</ul>
{{/if}}
</div>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,31 +0,0 @@
{{#if resume.volunteer.length}}
<section id="volunteer">
<h3>Volunteer</h3>
<div class="stack">
{{#each resume.volunteer}}
<article>
<header>
<h4>{{position}}</h4>
<div class="meta">
<strong>{{> link name=organization}}</strong>
<div>
<time datetime="{{startDate}}">{{formatDate startDate}}</time>
{{#if endDate}}<time datetime="{{endDate}}">{{formatDate endDate}}</time>{{else}}Present{{/if}}
</div>
</div>
</header>
{{#summary}}
{{{markdown .}}}
{{/summary}}
{{#if highlights.length}}
<ul>
{{#highlights}}
<li>{{{markdown .}}}</li>
{{/highlights}}
</ul>
{{/if}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,39 +0,0 @@
{{#if resume.work.length}}
<section id="work">
<h3>Work</h3>
<div class="stack">
{{#each resume.work}}
<article>
<header>
<h4>{{position}}</h4>
<div class="meta">
<div>
<strong>{{> link}}</strong>
{{#description}}
<span class="bullet-item">{{.}}</span>
{{/description}}
</div>
<div>
<time datetime="{{startDate}}">{{formatDate startDate}}</time>
{{#if endDate}}<time datetime="{{endDate}}">{{formatDate endDate}}</time>{{else}}Present{{/if}}
</div>
{{#location}}
<div>{{.}}</div>
{{/location}}
</div>
</header>
{{#summary}}
{{{markdown .}}}
{{/summary}}
{{#if highlights.length}}
<ul>
{{#highlights}}
<li>{{{markdown .}}}</li>
{{/highlights}}
</ul>
{{/if}}
</article>
{{/each}}
</div>
</section>
{{/if}}

View File

@ -1,29 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{{#resume.basics}}
{{> meta}}
{{/resume.basics}}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700&display=swap">
<style>{{{css}}}</style>
</head>
<body>
{{#resume.basics}}
{{> header}}
{{/resume.basics}}
{{> work}}
{{> volunteer}}
{{> education}}
{{> projects}}
{{> awards}}
{{> certificates}}
{{> publications}}
{{> skills}}
{{> languages}}
{{> interests}}
{{> references}}
</body>
</html>

41
resume.js Normal file
View File

@ -0,0 +1,41 @@
import Awards from './components/awards.js'
import Certificates from './components/certificates.js'
import Education from './components/education.js'
import Header from './components/header.js'
import Interests from './components/interests.js'
import Languages from './components/languages.js'
import Meta from './components/meta.js'
import Projects from './components/projects.js'
import Publications from './components/publications.js'
import References from './components/references.js'
import Skills from './components/skills.js'
import Volunteer from './components/volunteer.js'
import Work from './components/work.js'
import html from './utils/html.js'
export default function Resume(resume, css) {
return html`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
${Meta(resume.basics)}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700&display=swap">
<style>${css}</style>
</head>
<body>
${Header(resume.basics)}
${Work(resume.work)}
${Volunteer(resume.volunteer)}
${Education(resume.education)}
${Projects(resume.projects)}
${Awards(resume.awards)}
${Certificates(resume.certificates)}
${Publications(resume.publications)}
${Skills(resume.skills)}
${Languages(resume.languages)}
${Interests(resume.interests)}
${References(resume.references)}
</body>
</html>`
}

View File

@ -7,14 +7,16 @@
'use strict'
exports[`test/render.js TAP renders a resume > must match snapshot 1`] = `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Richard Hendriks</title>
<meta name="description" content="Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. (Go Sooners and Cardinal!) Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory. He could tell you about it, but THAT would NOT be a “length-limited” conversation!">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700&display=swap">
<style>:root {
<html lang="en">
<head>
<meta charset="utf-8">
<title>Richard Hendriks</title>
<meta name="description" content="Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. (Go Sooners and Cardinal!) Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory. He could tell you about it, but THAT would NOT be a “length-limited” conversation!">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700&display=swap">
<style>:root {
color-scheme: light dark;
--color-background: #ffffff; /* White */
@ -268,232 +270,281 @@ blockquote > * + * {
}
}
</style>
</head>
<body>
<header class="masthead">
<img src="image.jpg" alt="">
<div>
<h1>Richard Hendriks</h1>
<h2>Programmer</h2>
</div>
</head>
<body>
<header class="masthead">
<img src="image.jpg" alt="">
<div>
<h1>Richard Hendriks</h1>
<h2>Programmer</h2>
</div>
<article><p>Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. (Go Sooners and Cardinal!) Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory. He could tell you about it, but THAT would NOT be a length-limited conversation!</p></article>
<ul class="icon-list">
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-map-pin"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
San Francisco, United States
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-mail"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
<a href="mailto:richard.hendriks@mail.com">richard.hendriks@mail.com</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-phone"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path></svg>
<a href="tel:(912)555-4321">(912) 555-4321</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
<a href="http://richardhendricks.example.com">richardhendricks.example.com</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-twitter"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>
neutralthoughts
<span class="network">(Twitter)</span>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
<a href="https://soundcloud.example.com/dandymusicnl">dandymusicnl</a>
<span class="network">(SoundCloud)</span>
</li>
</ul>
</header>
<section id="work">
<h3>Work</h3>
<div class="stack">
<article>
<p>Richard hails from Tulsa. He has earned degrees from the University of Oklahoma and Stanford. (Go Sooners and Cardinal!) Before starting Pied Piper, he worked for Hooli as a part time software developer. While his work focuses on applied information theory, mostly optimizing lossless compression schema of both the length-limited and adaptive variants, his non-work interests range widely, everything from quantum computing to chaos theory. He could tell you about it, but THAT would NOT be a length-limited conversation!</p>
<header>
<h4>CEO/President</h4>
<div class="meta">
<div>
<strong><a href="http://piedpiper.example.com">Pied Piper</a></strong>
<span class="bullet-item">Awesome compression company</span>
</div>
<div><time datetime="2013-12-01">Dec 2013</time> <time datetime="2014-12-01">Dec 2014</time></div>
<div>Palo Alto, CA</div>
</div>
</header>
<p>Pied Piper is a multi-platform technology based on a proprietary universal compression algorithm that has consistently fielded high Weisman Scores that are not merely competitive, but approach the theoretical limit of lossless compression.</p>
<ul>
<li><p>Build an algorithm for artist to detect if their music was violating copy right infringement laws</p></li><li><p>Successfully won Techcrunch Disrupt</p></li><li><p>Optimized an algorithm that holds the current world record for Weisman Scores</p></li>
</ul>
</article>
<ul class="icon-list">
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-map-pin"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path><circle cx="12" cy="10" r="3"></circle></svg>
San Francisco, United States
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-mail"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
<a href="mailto:richard.hendriks@mail.com">richard.hendriks@mail.com</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-phone"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"></path></svg>
<a href="tel:9125554321">(912) 555-4321</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-link"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path></svg>
<a href="http://richardhendricks.example.com">richardhendricks.example.com</a>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-twitter"><path d="M23 3a10.9 10.9 0 0 1-3.14 1.53 4.48 4.48 0 0 0-7.86 3v1A10.66 10.66 0 0 1 3 4s-4 9 5 13a11.64 11.64 0 0 1-7 2c9 5 20 0 20-11.5a4.5 4.5 0 0 0-.08-.83A7.72 7.72 0 0 0 23 3z"></path></svg>
neutralthoughts
<span class="network">(Twitter)</span>
</li>
<li>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-user"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
<a href="https://soundcloud.example.com/dandymusicnl">dandymusicnl</a>
<span class="network">(SoundCloud)</span>
</li>
</ul>
</header>
<section id="work">
<h3>Work</h3>
<div class="stack">
<article>
<header>
<h4>CEO/President</h4>
<div class="meta">
<div>
<strong><a href="http://piedpiper.example.com">Pied Piper</a></strong>
<span class="bullet-item">Awesome compression company</span>
</div>
<div>
<time datetime="2013-12-01">Dec 2013</time>
<time datetime="2014-12-01">Dec 2014</time>
</div>
<div>Palo Alto, CA</div>
</div>
</header>
<p>Pied Piper is a multi-platform technology based on a proprietary universal compression algorithm that has consistently fielded high Weisman Scores that are not merely competitive, but approach the theoretical limit of lossless compression.</p>
<ul>
<li><p>Build an algorithm for artist to detect if their music was violating copy right infringement laws</p></li>
<li><p>Successfully won Techcrunch Disrupt</p></li>
<li><p>Optimized an algorithm that holds the current world record for Weisman Scores</p></li>
</ul>
</article>
</div>
</section>
<section id="volunteer">
<h3>Volunteer</h3>
<div class="stack">
<article>
<header>
<h4>Teacher</h4>
<div class="meta">
<strong><a href="http://coderdojo.example.com/">CoderDojo</a></strong>
<div>
<time datetime="2012-01-01">Jan 2012</time>
<time datetime="2013-01-01">Jan 2013</time>
</div>
</div>
</header>
<p>Global movement of free coding clubs for young people.</p>
<ul>
<li><p>Awarded 'Teacher of the Month'</p></li>
</ul>
</article>
</div>
</section>
<section id="education">
<h3>Education</h3>
<div class="stack">
<article>
<header>
<h4><a href="https://www.ou.edu/">University of Oklahoma</a></h4>
<div class="meta">
<strong>Information Technology</strong>
<div>
<time datetime="2011-06-01">Jun 2011</time>
<time datetime="2014-01-01">Jan 2014</time>
</div>
</div>
</header>
<p>Bachelor</p>
<h5>Courses</h5>
<ul>
<li><p>DB1101 - Basic SQL</p></li>
<li><p>CS2011 - Java Introduction</p></li>
</ul>
</article>
</div>
</section>
<section id="projects">
<h3>Projects</h3>
<div class="stack">
<article>
<header>
<h4><a href="missdirection.example.com">Miss Direction</a></h4>
<div class="meta">
<div>
<strong>Team lead and Designer</strong>
at <strong>Smoogle</strong>
</div>
<div>
<time datetime="2016-08-24">Aug 2016</time>
<time datetime="2016-08-24">Aug 2016</time>
</div>
</div>
</header>
<p>A mapping engine that misguides you</p>
<ul>
<li><p>Won award at AIHacks 2016</p></li>
<li><p>Built by all women team of newbie programmers</p></li>
<li><p>Using modern technologies such as GoogleMaps, Chrome Extension and Javascript</p></li>
</ul>
</article>
</div>
</section>
<section id="awards">
<h3>Awards</h3>
<div class="stack">
<article>
<header>
<h4>Digital Compression Pioneer Award</h4>
<div class="meta">
<div>
Awarded by <strong>Techcrunch</strong>
</div>
<time datetime="2014-11-01">Nov 2014</time>
</div>
</header>
<p>There is no spoon.</p>
</article>
</div>
</section>
<section id="publications">
<h3>Publications</h3>
<div class="stack">
<article>
<header>
<h4><a href="http://en.wikipedia.org/wiki/Silicon_Valley_(TV_series)">Video compression for 3d media</a></h4>
<div class="meta">
<div>
Published by <strong>Hooli</strong>
</div>
<time datetime="2014-10-01">Oct 2014</time>
</div>
</header>
<p>Innovative middle-out compression algorithm that changes the way we store data.</p>
</article>
</div>
</section>
<section id="skills">
<h3>Skills</h3>
<div class="grid-list">
<div>
<h4>Web Development</h4>
<ul class="tag-list">
<li>HTML</li>
<li>CSS</li>
<li>Javascript</li>
</ul>
</div>
</section>
<section id="volunteer">
<h3>Volunteer</h3>
<div class="stack">
<article>
<header>
<h4>Teacher</h4>
<div class="meta">
<strong><a href="http://coderdojo.example.com/">CoderDojo</a></strong>
<div><time datetime="2012-01-01">Jan 2012</time> <time datetime="2013-01-01">Jan 2013</time></div>
</div>
</header>
<p>Global movement of free coding clubs for young people.</p>
<ul>
<li><p>Awarded 'Teacher of the Month'</p></li>
</ul>
</article>
</div>
</section>
<section id="education">
<h3>Education</h3>
<div class="stack">
<article>
<header>
<h4><a href="https://www.ou.edu/">University of Oklahoma</a></h4>
<div class="meta">
<strong>Information Technology</strong>
<div><time datetime="2011-06-01">Jun 2011</time> <time datetime="2014-01-01">Jan 2014</time></div>
</div>
</header>
<p>Bachelor</p>
<h5>Courses</h5>
<ul>
<li><p>DB1101 - Basic SQL</p></li><li><p>CS2011 - Java Introduction</p></li>
</ul>
</article>
</div>
</section>
<section id="projects">
<h3>Projects</h3>
<div class="stack">
<article>
<header>
<h4><a href="missdirection.example.com">Miss Direction</a></h4>
<div class="meta">
<div>
<strong>Team lead and Designer</strong>
at <strong>Smoogle</strong>
</div>
<div><time datetime="2016-08-24">Aug 2016</time> <time datetime="2016-08-24">Aug 2016</time></div>
</div>
<div>
<h4>Compression</h4>
<ul class="tag-list">
<li>Mpeg</li>
<li>MP4</li>
<li>GIF</li>
</ul>
</div>
</div>
</section>
<section id="languages">
<h3>Languages</h3>
<div class="grid-list">
<div>
<h4>English</h4>
Native speaker
</div>
</div>
</section>
<section id="interests">
<h3>Interests</h3>
<div class="grid-list">
<div>
<h4>Wildlife</h4>
<ul class="tag-list">
<li>Ferrets</li>
<li>Unicorns</li>
</ul>
</div>
</div>
</section>
<section id="references">
<h3>References</h3>
<div class="stack">
<blockquote>
<p>It is my pleasure to recommend Richard, his performance working as a consultant for Main St. Company proved that he will be a valuable addition to any company.</p>
<p>
<cite>Erlich Bachman</cite>
</p>
</blockquote>
</div>
</section>
</body>
</html>
</header>
<p>A mapping engine that misguides you</p>
<ul>
<li><p>Won award at AIHacks 2016</p></li><li><p>Built by all women team of newbie programmers</p></li><li><p>Using modern technologies such as GoogleMaps, Chrome Extension and Javascript</p></li>
</ul>
</article>
</div>
</section>
<section id="awards">
<h3>Awards</h3>
<div class="stack">
<article>
<header>
<h4>Digital Compression Pioneer Award</h4>
<div class="meta">
<div>
Awarded by <strong>Techcrunch</strong>
</div>
<time datetime="2014-11-01">Nov 2014</time>
</div>
</header>
<p>There is no spoon.</p>
</article>
</div>
</section>
<section id="publications">
<h3>Publications</h3>
<div class="stack">
<article>
<header>
<h4><a href="http://en.wikipedia.org/wiki/Silicon_Valley_(TV_series)">Video compression for 3d media</a></h4>
<div class="meta">
<div>
Published by <strong>Hooli</strong>
</div>
<time datetime="2014-10-01">Oct 2014</time>
</div>
</header>
<p>Innovative middle-out compression algorithm that changes the way we store data.</p>
</article>
</div>
</section>
<section id="skills">
<h3>Skills</h3>
<div class="grid-list">
<div>
<h4>Web Development</h4>
<ul class="tag-list">
<li>HTML</li><li>CSS</li><li>Javascript</li>
</ul>
</div>
<div>
<h4>Compression</h4>
<ul class="tag-list">
<li>Mpeg</li><li>MP4</li><li>GIF</li>
</ul>
</div>
</div>
</section>
<section id="languages">
<h3>Languages</h3>
<div class="grid-list">
<div>
<h4>English</h4>
Native speaker
</div>
</div>
</section>
<section id="interests">
<h3>Interests</h3>
<div class="grid-list">
<div>
<h4>Wildlife</h4>
<ul class="tag-list">
<li>Ferrets</li><li>Unicorns</li>
</ul>
</div>
</div>
</section>
<section id="references">
<h3>References</h3>
<div class="stack">
<blockquote>
<p>It is my pleasure to recommend Richard, his performance working as a consultant for Main St. Company proved that he will be a valuable addition to any company.</p>
<p>
<cite>Erlich Bachman</cite>
</p>
</blockquote>
</div>
</section>
</body>
</html>
`

View File

@ -15,7 +15,10 @@ test('renders a resume', t => {
test('renders valid HTML', t => {
const htmlvalidate = new HtmlValidate({
extends: ['html-validate:recommended'],
rules: { 'tel-non-breaking': 'off' },
rules: {
'no-trailing-whitespace': 'off',
'tel-non-breaking': 'off',
},
})
const {

10
utils/html.js Normal file
View File

@ -0,0 +1,10 @@
// Based on https://github.com/jimniels/html
export default function html(strings, ...values) {
return strings.reduce((acc, string, i) => {
const value = values[i]
if (Array.isArray(value)) return acc + string + value.join('')
if (value != null && !!value !== value) return acc + string + value
return acc + string
}, '')
}

7
utils/markdown.js Normal file
View File

@ -0,0 +1,7 @@
import micromark from 'micromark'
import striptags from 'striptags'
export default function markdown(doc, stripTags = false) {
const html = micromark(doc)
return stripTags ? striptags(html) : html
}