@tmjssz/jsonresume-theme-even
Version:
A flat JSON Resume theme, compatible with the latest resume schema
250 lines (242 loc) • 16.9 kB
JavaScript
(function(d,e){typeof exports=="object"&&typeof module<"u"?e(exports,require("@rbardini/html"),require("micromark"),require("striptags")):typeof define=="function"&&define.amd?define(["exports","@rbardini/html","micromark","striptags"],e):(d=typeof globalThis<"u"?globalThis:d||self,e(d.jsonresumeThemeEven={},d.html,d.micromark,d.striptags))})(this,function(d,e,j,B){"use strict";var I=Object.freeze,et=Object.defineProperty;var z=(d,e)=>I(et(d,"raw",{value:I(e||d.slice())}));var D;const L=`const pluralize = (num, str) => \`\${num} \${num === 1 ? str : str.concat('s')}\`
class TimeDuration extends HTMLElement {
connectedCallback() {
const [from, to] = this.querySelectorAll('time')
if (!from) return
const startDate = new Date(from.dateTime || from.textContent)
const endDate = new Date(to ? to.dateTime || to.textContent : Date.now())
const diffDate = new Date(endDate - startDate)
const years = diffDate.getFullYear() - 1970
const months = diffDate.getMonth()
const days = diffDate.getDate() - 1
const segments = [
years && pluralize(years, 'yr'),
months && pluralize(months, 'mo'),
days && !years && !months && pluralize(days, 'day'),
].filter(Boolean)
if (!segments.length) return
const duration = document.createElement('time')
duration.classList.add('duration')
duration.textContent = '· '.concat(segments.join(' '))
this.append(' ', duration)
}
}
customElements.define('time-duration', TimeDuration)
`,T=':root{color-scheme:light dark;--color-background-light: #ffffff;--color-dimmed-light: #f3f4f5;--color-primary-light: #191e23;--color-secondary-light: #6c7781;--color-tertiary-light: #d2d8dd;--color-accent-light: #0073aa;--color-background-dark: #191e23;--color-dimmed-dark: #23282d;--color-primary-dark: #fbfbfc;--color-secondary-dark: #989fa5;--color-tertiary-dark: #515357;--color-accent-dark: #00a0d2;--color-background: var(--color-background-light);--color-dimmed: var(--color-dimmed-light);--color-primary: var(--color-primary-light);--color-secondary: var(--color-secondary-light);--color-tertiary: var(--color-tertiary-light);--color-accent: var(--color-accent-light);--scale-ratio: 1.25;--scale0: 1rem;--scale1: calc(var(--scale0) * var(--scale-ratio));--scale2: calc(var(--scale1) * var(--scale-ratio));--scale3: calc(var(--scale2) * var(--scale-ratio));--scale4: calc(var(--scale3) * var(--scale-ratio));--scale5: calc(var(--scale4) * var(--scale-ratio))}@media (prefers-color-scheme: dark){:root{--color-background: var(--color-background-dark);--color-dimmed: var(--color-dimmed-dark);--color-primary: var(--color-primary-dark);--color-secondary: var(--color-secondary-dark);--color-tertiary: var(--color-tertiary-dark);--color-accent: var(--color-accent-dark)}}@media print{:root{--scale-ratio: 1.15}}*{box-sizing:border-box;margin:0;padding:0}html{font-size:14px}body{background:var(--color-background);color:var(--color-primary);display:grid;font:1em/1.3 Lato,sans-serif;gap:2em;grid-template-columns:[full-start] 1fr [main-start side-left-start content-start] minmax(min-content,18em) [side-left-end] minmax(min-content,20em) [content-end side-right-start] minmax(min-content,18em) [main-end side-right-end] 1fr [full-end];grid-template-rows:auto [content] 0;margin-bottom:4em}body:before{content:"";grid-column:full;grid-row:content}ol,ul{padding-left:1em}li::marker,.network{color:var(--color-secondary)}a{color:inherit}a:focus,a:hover{color:var(--color-accent)}.discrete-link>a{text-decoration:none}h1{font-weight:400}h1,h2,h3{line-height:1}h1>a,h2>a,h3>a,h4>a,h5>a,h6>a{text-decoration:none}h1{font-size:var(--scale5)}h2{color:var(--color-secondary);font-size:var(--scale4);font-weight:100}h3{color:var(--color-secondary);font-size:var(--scale3);margin-bottom:1rem;font-weight:100}h4{font-size:var(--scale2)}h5{font-size:var(--scale1)}h6{font-size:var(--scale0)}blockquote{border-left:.2em solid var(--color-dimmed);padding-left:1em}cite{color:var(--color-secondary);font-style:inherit}cite:before{content:"— "}svg{margin-right:.2em;vertical-align:text-bottom}.color-primary{color:var(--color-primary)}.material-icons,.zmdi{font-size:1.2em}.icon-item{display:flex;align-items:center;gap:.25em}.icon-item>a{text-decoration:none}.masthead{background:var(--color-dimmed);display:inherit;gap:2em;grid-column:full;grid-template-columns:inherit;padding:3.5em 0 2.5em;row-gap:1.5em;margin-bottom:-2em}.masthead>*{grid-column:main}.masthead>img{border:4px solid;border-radius:50%;margin:0 auto;max-width:12em}.masthead .title-row{display:flex;justify-content:space-between;align-items:center}article>*+*,blockquote>*+*,.timeline>div>*+*{margin-top:.6em}.main-content,.side-content{grid-column:main;display:grid;row-gap:3em}#work article .single .timeline{margin-top:0}#work article .single header{display:flex;justify-content:space-between;align-items:center}.meta{color:var(--color-secondary)}.stack{display:grid;gap:1.5em}.icon-list{display:flex;flex-wrap:wrap;gap:.4em 1.5em;justify-content:flex-start;list-style:none;padding:0}.grid-list{display:grid;gap:1em}.tag-list{display:flex;flex-wrap:wrap;gap:.4em;list-style:none;padding:0}.tag-list>li{background:var(--color-dimmed);border-radius:.7em;padding:.15em .4em}.timeline>div{position:relative}.timeline>div:not(:last-child){padding-bottom:1rem}.timeline>div:not(:last-child):before{content:"";position:absolute;top:2rem;left:-15px;width:2px;height:calc(100% - 2.4rem);background:var(--color-tertiary)}.timeline>div:not(:only-child):after{content:"";position:absolute;top:.3rem;left:-20px;width:.6rem;height:.6rem;background:var(--color-secondary);border:2px solid var(--color-background);border-radius:50%}.print-only{display:none}@media print,(min-width: 48em){h3{padding-bottom:.4em;border-bottom:1px solid var(--color-dimmed);margin-bottom:1em}.masthead img{grid-column:side-left;grid-row:span 2;max-width:100%}.icon-list{flex-direction:row}.grid-list{grid-template-columns:repeat(auto-fit,minmax(calc((100% - 1em)/2),1fr))}}@media print{html{font-size:12px}.masthead{row-gap:1em;padding:3em 0 2em}.main-content{grid-column:content;align-self:start}.side-content{grid-column:side-right;align-self:start}.side-content .grid-list{grid-template-columns:auto}.print-only{display:block}.page-break-before{margin-top:4em;page-break-before:always}}';function C(t={}){const i=t.themeOptions?.colors;return i&&Object.entries(i).map(([n,[r,o=r]])=>`--color-${n}-light:${r}; --color-${n}-dark:${o};`).join(" ")}function m(t,i=!1){const n=j(t);return i?B(n):n}function b(t){return`<i class="zmdi zmdi-${t.toLowerCase()}"></i>`}const q=t=>t.replace(/^(https?:|)\/\//,"").replace(/\/$/,"");function u(t,i){return i?t?e.html`<a href="${t}">${i}</a>`:i:t&&e.html`<a href="${t}">${q(t)}</a>`}const S=t=>Intl.DisplayNames?new Intl.DisplayNames(["en"],{type:"region"}).of(t):t;function E(t={}){const{email:i,image:n,label:r,location:o,name:a,phone:l,profiles:s=[],summary:c,url:$}=t;return e.html`
<header class="masthead">
${n&&e.html`<img src="${n}" alt="" />`}
<div>
<div class="title-row">
${a&&e.html`<h1>${a}</h1>`}
${o?.city&&e.html`
<div class="icon-item">
${b("pin")}
<span>${o.city}${o.countryCode&&e.html`, ${S(o.countryCode)}`}</span>
</div>
`}
</div>
${r&&e.html`<h2>${r}</h2>`}
</div>
${c&&e.html`<article>${m(c)}</article>`}
<ul class="icon-list">
${i&&e.html`
<li class="icon-item">
${b("email")}
<a href="mailto:${i}">${i}</a>
</li>
`}
${l&&e.html`
<li class="icon-item">
${b("smartphone")}
<a href="tel:${l.replace(/\s/g,"")}">${l}</a>
</li>
`}
${$&&e.html`<li class="icon-item">${b("link")} ${u($)}</li>`}
${s.map(({network:f,url:p,username:y})=>e.html`
<li class="icon-item">${f&&b(f)} ${u(p,y)}</li>
`)}
</ul>
</header>
`}function P(t={}){const{name:i,summary:n}=t;return e.html`
${i&&e.html`<title>${i}</title>`}
${n&&e.html`<meta name="description" content="${m(n,!0)}" />`}
`}function h(t="",i="",n="",r=!1){return n.length>0&&e.html`
<article${r?' class="page-break-before"':""}>
<header>
<h4>${t}</h4>
${i.length>0?e.html`<div class="meta">${i}</div>`:""}
</header>
${n}
</article>
`}const R=t=>new Date(t).toLocaleDateString("en",{month:"short",year:"numeric",timeZone:"UTC"});function v(t){return e.html`<time datetime="${t}">${R(t)}</time>`}function g(t="",i="",n="",r=!1){return n.length>0&&e.html`
<section ${i.length>0?`id="${i}"`:""}${r?' class="page-break-before"':""}>
<h3>${t}</h3>
${n}
</section>
`}function A(t=[]){const i=t[0];return t.length>0&&g("Awards","awards",e.html`
<div class="stack">
${t.map(({awarder:n,date:r,summary:o,title:a,breakBefore:l},s)=>h(a,e.html`${n&&e.html`<div>Awarded by <strong>${n}</strong></div>`} ${r&&v(r)}`,e.html`${o&&m(o)}`,!!l&&s>0))}
</div>
`,!!i?.breakBefore)}function O(t=[]){const i=t[0];return t.length>0&&g("Certificates","certificates",e.html`
<div class="stack">
${t.map(({date:n,issuer:r,name:o,url:a,breakBefore:l},s)=>h(u(a,o),`${r&&e.html`<div>Issued by <strong>${r}</strong></div>`} ${n&&v(n)}`,"",!!l&&s>0))}
</div>
`,!!i?.breakBefore)}function k(t,i){return i===t?v(i):e.html`<time-duration>${v(t)} – ${i?v(i):"Present"}</time-duration>`}function M(t=[]){const i=t[0];return t.length>0&&g("Education","education",e.html`
<div class="stack">
${t.map(({area:n,courses:r=[],institution:o,startDate:a,endDate:l,studyType:s,url:c,breakBefore:$},f)=>h(u(c,o),e.html`<span>
<strong class="color-primary">${s}</strong>
<span>${n&&e.html`· ${n}`}</span>
</span>
<div>${a&&e.html`<div>${k(a,l)}</div>`}</div>`,e.html`
${r.length>0&&e.html`
<ul>
${r.map(p=>e.html`<li>${m(p)}</li>`)}
</ul>
`}
`,!!$&&f>0))}
</div>
`,!!i?.breakBefore)}function F(t=[]){const i=t[0];return t.length>0&&g("Interests","interests",e.html`
<div class="grid-list">
${t.map(({keywords:n=[],name:r})=>e.html`
<div>
${r&&e.html`<h5>${r}</h5>`}
${n.length>0&&e.html`
<ul class="tag-list">
${n.map(o=>e.html`<li>${o}</li>`)}
</ul>
`}
</div>
`)}
</div>
`,!!i?.breakBefore)}function N(t=[]){const i=t[0];return t.length>0&&g("Languages","languages",e.html`
<div class="grid-list">
${t.map(({fluency:n,language:r})=>e.html`<div>${r&&e.html`<h5>${r}</h5>`} <span class="meta">${n}</span></div>`)}
</div>
`,!!i?.breakBefore)}const W=t=>Intl.ListFormat?new Intl.ListFormat("en").format(t):t.join(", ");function H(t=[]){const i=t[0];return t.length>0&&g("Projects","projects",e.html` <div class="stack">
${t.map(({breakBefore:n,description:r,entity:o,highlights:a=[],keywords:l=[],name:s,startDate:c,endDate:$,roles:f=[],type:p,url:y},x)=>h(u(y,s),e.html`<div>
${f.length>0&&e.html`<strong>${W(f)}</strong>`}
${o&&e.html`at <strong>${o}</strong>`}
</div>
${c&&e.html`<div>${k(c,$)}</div>`} ${p&&e.html`<div>${p}</div>`}`,e.html`
${r&&m(r)}
${a.length>0&&e.html`
<ul>
${a.map(w=>e.html`<li>${m(w)}</li>`)}
</ul>
`}
${l.length>0&&e.html`
<ul class="tag-list">
${l.map(w=>e.html`<li>${w}</li>`)}
</ul>
`}
`,!!n&&x>0))}
</div>`,!!i?.breakBefore)}function U(t=[]){const i=t[0];return t.length>0&&g("Publications","publications",e.html`
<div class="stack">
${t.map(({name:n,publisher:r,releaseDate:o,summary:a,url:l,breakBefore:s},c)=>h(u(l,n),e.html`<div>
${r&&e.html`<div>Published by <strong>${r}</strong></div>`}
${o&&v(o)}
</div>`,e.html`${a&&m(a)}`,!!s&&c>0))}
</div>
`,!!i?.breakBefore)}function V(t=[]){const i=t[0];return t.length>0&&g("References","references",e.html`
<div class="stack">
${t.map(({name:n,reference:r})=>e.html`
<blockquote>
${r&&m(r)}
${n&&e.html`
<p>
<cite>${n}</cite>
</p>
`}
</blockquote>
`)}
</div>
`,!!i?.breakBefore)}function Y(t=[]){const i=t[0];return t.length>0&&g("Skills","skills",e.html`
<div class="grid-list">
${t.map(({keywords:n=[],name:r})=>e.html`
<div>
${r&&e.html`<h5>${r}</h5>`}
${n.length>0&&e.html`
<ul class="tag-list">
${n.map(o=>e.html`<li>${o}</li>`)}
</ul>
`}
</div>
`)}
</div>
`,!!i?.breakBefore)}function Z(t=[]){const i=t[0];return t.length>0&&g("Volunteer","volunteer",e.html`
<div class="stack">
${t.map(({highlights:n=[],organization:r,position:o,startDate:a,endDate:l,summary:s,url:c,breakBefore:$},f)=>h(u(c,r),e.html`<div>
<strong>${o}</strong>
${a&&e.html`<div>${k(a,l)}</div>`}
</div>`,e.html`
${s&&m(s)}
${n.length>0&&e.html`
<ul>
${n.map(p=>e.html`<li>${m(p)}</li>`)}
</ul>
`}
`,!!$&&f>0))}
</div>
`,!!i?.breakBefore)}function G({breakBefore:t,description:i,name:n,url:r,items:o=[]}){if(o.length===0)return!1;const a=o.length===1,l=o[0],s=u(r,n),c=a?l.position:s,$=a?e.html`
<span>
<strong class="discrete-link color-primary">${s}</strong>
${l.location&&e.html`<span>${s&&"· "}${l.location}</span>`}
</span>
<div>${l.startDate&&k(l.startDate,l.endDate)}</div>
`:i;return h(c,$,e.html`
<div${a?' class="single"':""}>
<div class="timeline">
${o.map(({highlights:f=[],location:p,summary:y,startDate:x,endDate:w,position:_})=>e.html`
<div>
<div>
${!a&&e.html`<h5>${_}</h5>`}
<span>
<span class="meta">${p&&!a?p:""} </span>
</span>
<div class="meta">
${x&&!a&&e.html`<div>${k(x,w)}</div>`}
</div>
</div>
${y&&m(y)}
${f.length>0&&e.html`
<ul>
${f.map(tt=>e.html`<li>${m(tt)}</li>`)}
</ul>
`}
</div>
`)}
</div>
</div>
`,t)}function J(t=[]){const i=t.reduce((r,{description:o,name:a,url:l,...s})=>{const c=r[r.length-1];return c&&c.name===a&&c.description===o&&c.url===l?c.items.push(s):r.push({description:o,name:a,url:l,items:[s]}),r},[]),n=t[0];return t.length>0&&g("Experience","work",e.html`<div class="stack">
${i.map(({breakBefore:r,...o},a)=>G({...o,breakBefore:!!r&&a>0}))}
</div>`,!!n?.breakBefore)}function K(t,{css:i,js:n}={}){return e.html`
<html lang="en" style="${C(t.meta)}">
<head>
<meta charset="utf-8" />
${P(t.basics)}
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:300,400,700&display=swap" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css"
/>
${i&&e.html`<style>
${i}
</style>`}
${n&&e.html(D||(D=z([`<script type="module">
`,`
<\/script>`])),n)}
</head>
<body>
${E(t.basics)}
<div class="main-content">
${J(t.work)} ${Z(t.volunteer)} ${M(t.education)}
${H(t.projects)} ${A(t.awards)} ${O(t.certificates)}
${U(t.publications)}
</div>
<div class="side-content">
${Y(t.skills)} ${N(t.languages)} ${F(t.interests)}
${V(t.references)}
</div>
</body>
</html>`}const Q={mediaType:"print",printBackground:!0},X=t=>K(t,{css:T,js:L});d.pdfRenderOptions=Q,d.render=X,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})});