Generate PDF automatically

This commit is contained in:
Anders Englöf Ytterström 2024-10-18 12:41:28 +02:00
parent 0f57a2c305
commit e31c7ef854
6 changed files with 1502 additions and 132 deletions

4
README
View file

@ -1,4 +1,4 @@
1. npm run build or node.index.js 1. npm run build or node index.js
2. copy ./pub to public url 2. copy ./pub to public url
Use "print to PDF" to sync PDF file manually. Use "print to PDF" to sync PDF file manually if needed.

View file

@ -1,123 +1,132 @@
html { html {
font: normal small/1.5 apple-system, system-ui, BlinkMacSystemFont, Segoe UI, font:
Roboto, Helvetica Neue, Arial, sans-serif; normal small/1.5 apple-system,
background-color: var(--bg-color, #fff); system-ui,
color: var(--bg-color, #444); BlinkMacSystemFont,
Segoe UI,
Roboto,
Helvetica Neue,
Arial,
sans-serif;
background-color: var(--bg-color, #fff);
color: var(--bg-color, #444);
} }
body { body {
font-size: clamp(0.9em, 1.5vw, 1.4em); font-size: clamp(0.9em, 1.5vw, 1.4em);
} }
ul { ul {
margin: 0; margin: 0;
padding-left: 1em; padding-left: 1em;
} }
h1 { h1 {
margin-bottom: 0; margin-bottom: 0;
font-size: 3em; font-size: 3em;
line-height: 1; line-height: 1;
} }
h2 { h2 {
border-bottom: 0.3em solid #e3e3e3; border-bottom: 0.3em solid #e3e3e3;
padding-bottom: 0.25em; padding-bottom: 0.25em;
margin-bottom: 1em; margin-bottom: 1em;
} }
img { img {
display: block; display: block;
border-radius: 50%; border-radius: 50%;
margin: 0 auto; margin: 0 auto;
} }
figure { figure {
margin: 0; margin: 0;
} }
a { a {
color: var(--bg-color, #444); color: var(--bg-color, #444);
transition: background-color 0.3s ease-out, border-bottom-color 0.3s ease-out; transition:
background-color 0.3s ease-out,
border-bottom-color 0.3s ease-out;
} }
p:first-child { p:first-child {
margin-top: 0; margin-top: 0;
} }
a:link, a:link,
a:visited { a:visited {
display: inline-block; display: inline-block;
text-decoration: none; text-decoration: none;
border-bottom: 1px solid #bbb; border-bottom: 1px solid #bbb;
} }
a:hover, a:hover,
a:focus { a:focus {
background: rgba(0, 0, 0, 0.05); background: rgba(0, 0, 0, 0.05);
border-bottom-color: #000; border-bottom-color: #000;
color: #000; color: #000;
} }
a:active { a:active {
transform: translate(3px, 3px); transform: translate(3px, 3px);
} }
[href^="tel"]::before { [href^="tel"]::before {
content: "📞 "; content: "📞 ";
} }
[href^="mailto"]::before { [href^="mailto"]::before {
content: "✉️ "; content: "✉️ ";
} }
[href^="https://github.com"]::before [href^="https://github.com"]::before
{ {
content: "🐙 "; content: "🐙 ";
} }
[href^="https://madr"]::before [href^="https://madr"]::before
{ {
content: "🏠 "; content: "🏠 ";
} }
[href$="pdf"] { [href$="pdf"] {
font-size: 1.1em; font-size: 1.1em;
padding: 0.3em; padding: 0.3em;
} }
[href$="pdf"]::before { [href$="pdf"]::before {
content: "📑 "; content: "📑 ";
} }
[href$="pdf"]:hover::before, [href$="pdf"]:hover::before,
[href$="pdf"]:focus::before { [href$="pdf"]:focus::before {
background-color: rgba(0, 255, 0, 0.2); background-color: rgba(0, 255, 0, 0.2);
} }
[role="doc-subtitle"] { [role="doc-subtitle"] {
font-size: 1.25em; font-size: 1.25em;
color: #666; color: #666;
} }
@media (min-width: 40em) { @media (min-width: 40em) {
.h-aside { .h-aside {
border-bottom: 0; border-bottom: 0;
font-size: 1.4em; font-size: 1.4em;
margin-bottom: 0; margin-bottom: 0;
margin-top: 1.95em; margin-top: 1.95em;
} }
} }
.contact { .contact {
margin: 1em 0; margin: 1em 0;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: 2em; gap: 2em;
} }
@media (min-width: 40em) { @media (min-width: 40em) {
.contact { .contact {
margin: 0.5em 0 0; margin: 0.5em 0 0;
grid-template-columns: repeat(4, 1fr); grid-template-columns: repeat(4, 1fr);
gap: 2em; gap: 2em;
} }
} }
.contact > dd { .contact > dd {
margin-left: 0; margin-left: 0;
} }
.contact > dt { .contact > dt {
position: absolute; position: absolute;
left: -9999em; left: -9999em;
} }
.skillset { .skillset {
display: grid; display: grid;
gap: 0.5em 1em; gap: 0.5em 1em;
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
} }
.skillset > dt { .skillset > dt {
font-weight: bold; font-weight: bold;
} }
.skillset > dd { .skillset > dd {
margin-left: 0; margin-left: 0;
} }
/* /*
Left for good measure, could have been gold if Left for good measure, could have been gold if
@ -133,114 +142,125 @@ the upcoming Container queries was a thing.
} }
*/ */
.resume { .resume {
max-width: 70em; max-width: 70em;
margin: 0 auto; margin: 0 auto;
display: grid; display: grid;
grid-template-columns: 1fr; grid-template-columns: 1fr;
grid-template-areas: grid-template-areas:
"name" "name"
"about" "about"
"skills" "skills"
"work" "work"
"education" "education"
"projects" "projects"
"courses" "courses"
"personal"; "personal";
gap: 0; gap: 0;
} }
@media (min-width: 40em) { @media (min-width: 40em) {
.resume { .resume {
grid-template-columns: 2fr 1fr; grid-template-columns: 2fr 1fr;
grid-template-areas: grid-template-areas:
"name name" "name name"
"skills about" "skills about"
"work work" "work work"
"education courses" "education courses"
"projects personal"; "projects personal";
gap: 2em; gap: 2em;
} }
} }
.name { .name {
grid-area: name; grid-area: name;
display: flex; display: flex;
gap: 1em; gap: 1em;
place-items: center; place-items: center;
text-align: center; text-align: center;
flex-direction: column; flex-direction: column;
} }
.photo { .photo {
grid-area: photo; grid-area: photo;
} }
.work { .work {
grid-area: work; grid-area: work;
} }
.courses { .courses {
grid-area: courses; grid-area: courses;
} }
.personal { .personal {
grid-area: personal; grid-area: personal;
} }
.about { .about {
grid-area: about; grid-area: about;
background: #f1f1f1; background: #f1f1f1;
border-radius: 0.2em; border-radius: 0.2em;
padding: 1em; padding: 1em;
color: #111; color: #111;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }
.education { .education {
grid-area: education; grid-area: education;
} }
.projects { .projects {
grid-area: projects; grid-area: projects;
} }
.skills { .skills {
grid-area: skills; grid-area: skills;
} }
.event { .event {
display: grid; display: grid;
gap: 0.5em 0.5em; gap: 0.5em 0.5em;
margin: 2em 0; margin: 2em 0;
line-height: 1; line-height: 1;
} }
.event--aside { .event--aside {
margin: 1em 0; margin: 1em 0;
} }
.event__title { .event__title {
margin: 0; margin: 0;
} }
.event__position { .event__position {
font-variant: small-caps; font-variant: small-caps;
} }
.event__content { .event__content {
line-height: 1.5; line-height: 1.5;
padding-top: 0.5em; padding-top: 0.5em;
grid-column: 1 / 3; grid-column: 1 / 3;
} }
.event__aside { .event__aside {
text-align: right; text-align: right;
font-style: italic; font-style: italic;
} }
@page { @page {
padding: 0; padding: 2cm 0;
margin: 0; margin: 0;
size: A4 portrait; size: A4 portrait;
} }
@media print { @media print {
body { body {
padding: 1cm; padding: 0;
} }
[href$="pdf"] { [href$="pdf"] {
display: none; display: none;
visibility: hidden; visibility: hidden;
} }
a {
border: none !important;
color: #000 !important;
}
.education,
.projects,
.work {
page-break-before: always;
}
} }

View file

@ -4,6 +4,22 @@ var layouts = require("metalsmith-layouts");
var markdown = require("metalsmith-markdown-remarkable"); var markdown = require("metalsmith-markdown-remarkable");
var permalinks = require("@metalsmith/permalinks"); var permalinks = require("@metalsmith/permalinks");
var static = require("metalsmith-static"); var static = require("metalsmith-static");
var puppeteer = require("puppeteer");
var srcHTML = "file:" + __dirname + "/pub/index.html";
var destPDF = "./pub/cv-anders-englof-ytterstrom.pdf";
async function generatePDF() {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto(srcHTML, {
waitUntil: "networkidle2",
});
await page.pdf({
path: destPDF,
});
await browser.close();
}
Metalsmith(__dirname) Metalsmith(__dirname)
.source("./src") .source("./src")
@ -31,4 +47,5 @@ Metalsmith(__dirname)
if (err) { if (err) {
throw err; throw err;
} }
generatePDF();
}); });

1334
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,7 @@
"metalsmith-html-minifier": "^3.0.3", "metalsmith-html-minifier": "^3.0.3",
"metalsmith-layouts": "^1.4.1", "metalsmith-layouts": "^1.4.1",
"metalsmith-markdown-remarkable": "^1.0.2", "metalsmith-markdown-remarkable": "^1.0.2",
"metalsmith-static": "0.0.5" "metalsmith-static": "0.0.5",
"puppeteer": "^23.6.0"
} }
} }