mirror of
https://github.com/skoelle/moonweb-site.git
synced 2026-09-18 01:10:25 +00:00
pdf generator
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
dist/
|
dist/
|
||||||
.cache/
|
.cache/
|
||||||
|
.venv/
|
||||||
*.log
|
*.log
|
||||||
.idea/
|
.idea/
|
||||||
.env*
|
.env*
|
||||||
|
|||||||
+2
-1
@@ -17,7 +17,8 @@
|
|||||||
"build:code": "npx @11ty/eleventy --config=code/eleventy.config.js",
|
"build:code": "npx @11ty/eleventy --config=code/eleventy.config.js",
|
||||||
"build:retro": "npx @11ty/eleventy --config=retro/eleventy.config.js",
|
"build:retro": "npx @11ty/eleventy --config=retro/eleventy.config.js",
|
||||||
"build:stefankoelle": "npx @11ty/eleventy --config=stefankoelle/eleventy.config.js",
|
"build:stefankoelle": "npx @11ty/eleventy --config=stefankoelle/eleventy.config.js",
|
||||||
"build": "npm run build:hub && npm run build:infra && npm run build:smarthome && npm run build:code && npm run build:retro && npm run build:stefankoelle"
|
"build": "npm run build:hub && npm run build:infra && npm run build:smarthome && npm run build:code && npm run build:retro && npm run build:stefankoelle",
|
||||||
|
"pdf:cv": "bash stefankoelle/pdf/build-pdf.sh"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@11ty/eleventy": "^3.1.6"
|
"@11ty/eleventy": "^3.1.6"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<h3>Stefan Kölle</h3>
|
<h3>Stefan Kölle</h3>
|
||||||
<p>Senior Software Developer & Software Architect<br>
|
<p>Senior Software Developer & Software Architect<br>
|
||||||
Neumarkter Str. 86c, 81673 München<br>
|
Neumarkter Str. 86c, 81673 München<br>
|
||||||
E-Mail: <a id="email-link" href="#">[email protected]</a></p>
|
E-Mail: <a id="email-link" href="mailto:cv@stefankoelle.de">cv@stefankoelle.de</a></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="profile">
|
<div class="profile">
|
||||||
@@ -24,7 +24,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3>Senior Software Developer / Senior Software Architect</h3>
|
<h3 class="page-break">Senior Software Developer / Senior Software Architect</h3>
|
||||||
<p><strong>TENHIL GmbH & Co. KG</strong> (2025 - present)</p>
|
<p><strong>TENHIL GmbH & Co. KG</strong> (2025 - present)</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><b>MCP-Server for ChatGPT Integration (2026)</b> Built an MCP server for a major platform integration using Claude Code, from concept to production in 6 half-days solo. Full spec, Confluence documentation, Jira epics and stories, and PO artifacts fully generated within the same workflow.</li>
|
<li><b>MCP-Server for ChatGPT Integration (2026)</b> Built an MCP server for a major platform integration using Claude Code, from concept to production in 6 half-days solo. Full spec, Confluence documentation, Jira epics and stories, and PO artifacts fully generated within the same workflow.</li>
|
||||||
@@ -49,7 +49,7 @@
|
|||||||
<li>Technologies: .NET Core 10, Docker, Azure, Terraform, Uptrends, Sentry, Loki, Quartz.NET.</li>
|
<li>Technologies: .NET Core 10, Docker, Azure, Terraform, Uptrends, Sentry, Loki, Quartz.NET.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>Senior Software Developer / Senior Software Architect</h3>
|
<h3 class="page-break">Senior Software Developer / Senior Software Architect</h3>
|
||||||
<p><strong>stellenanzeigen.de GmbH & Co. KG</strong> (11/2018 - 07/2022)</p>
|
<p><strong>stellenanzeigen.de GmbH & Co. KG</strong> (11/2018 - 07/2022)</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Architecting hosting solutions and migrating services to Azure.</li>
|
<li>Architecting hosting solutions and migrating services to Azure.</li>
|
||||||
|
|||||||
@@ -5,13 +5,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
var emailLink = document.getElementById('email-link');
|
var emailLink = document.getElementById('email-link');
|
||||||
if (emailLink) {
|
if (emailLink) {
|
||||||
emailLink.href = 'mailto:' + obfuscateEmail('cv', 'stefankoelle', 'de');
|
emailLink.href = 'mailto:' + obfuscateEmail('cv', 'stefankoelle', 'de');
|
||||||
emailLink.textContent = obfuscateEmail('cv', 'stefankoelle', 'de');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
var emailLink = document.getElementById('email-impressum');
|
var emailLink = document.getElementById('email-impressum');
|
||||||
if (emailLink) {
|
if (emailLink) {
|
||||||
emailLink.href = 'mailto:' + obfuscateEmail('impressum', 'stefankoelle', 'de');
|
emailLink.href = 'mailto:' + obfuscateEmail('impressum', 'stefankoelle', 'de');
|
||||||
emailLink.textContent = obfuscateEmail('impressum', 'stefankoelle', 'de');
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,33 +4,19 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>CV - Stefan Koelle</title>
|
<title>CV - Stefan Koelle</title>
|
||||||
<link rel="stylesheet" href="/assets/style.css">
|
|
||||||
<style>
|
|
||||||
@media print {
|
|
||||||
body { background: white; }
|
|
||||||
#links, #head, #background-image, .headlinespace, .space,
|
|
||||||
#personalprojectscontent, #programminglanguagescontent, #impressumcontent {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
#container { max-width: 100%; padding: 0; }
|
|
||||||
#headline { position: static; width: 100%; box-shadow: none; background: none; }
|
|
||||||
#cvcontent {
|
|
||||||
position: static;
|
|
||||||
width: 100%;
|
|
||||||
box-shadow: none;
|
|
||||||
background: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
</head>
|
||||||
<body class="blog">
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
<div id="wrapper-content">
|
<div id="wrapper-content">
|
||||||
<div id="headline">
|
<div id="headline">
|
||||||
|
<div id="headline-text">
|
||||||
<h1>Stefan Kölle</h1>
|
<h1>Stefan Kölle</h1>
|
||||||
Senior Software Developer & Software Architect
|
Senior Software Developer & Software Architect
|
||||||
</div>
|
</div>
|
||||||
|
<div id="headline-photo">
|
||||||
|
<img src="../assets/stefan-koelle-foto.jpg" alt="Stefan Koelle">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% include "cv-content.njk" %}
|
{% include "cv-content.njk" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Executable
+26
@@ -0,0 +1,26 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
PROJECT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
||||||
|
VENV_DIR="$PROJECT_DIR/.venv"
|
||||||
|
REQUIREMENTS="$SCRIPT_DIR/requirements.txt"
|
||||||
|
OUTPUT="$SCRIPT_DIR/cv.pdf"
|
||||||
|
|
||||||
|
echo "==> Setting up Python venv..."
|
||||||
|
if [ ! -d "$VENV_DIR" ]; then
|
||||||
|
python3 -m venv "$VENV_DIR"
|
||||||
|
fi
|
||||||
|
source "$VENV_DIR/bin/activate"
|
||||||
|
|
||||||
|
echo "==> Installing WeasyPrint..."
|
||||||
|
pip install -q -r "$REQUIREMENTS"
|
||||||
|
|
||||||
|
echo "==> Building stefankoelle with Eleventy..."
|
||||||
|
npx @11ty/eleventy --config="$PROJECT_DIR/stefankoelle/eleventy.config.js"
|
||||||
|
|
||||||
|
echo "==> Generating PDF..."
|
||||||
|
weasyprint "$PROJECT_DIR/dist/stefankoelle/cv-print/index.html" "$OUTPUT" \
|
||||||
|
--stylesheet "$SCRIPT_DIR/cv-style.css"
|
||||||
|
|
||||||
|
echo "==> Done: $OUTPUT"
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
/* cv-style.css — Clean CV layout for PDF print */
|
/* cv-style.css — Clean CV layout for PDF print */
|
||||||
|
|
||||||
|
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap');
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--color-text: #333;
|
--color-text: #333;
|
||||||
--color-heading: #1a1a1a;
|
--color-heading: #1a1a1a;
|
||||||
@@ -44,6 +46,10 @@ h3 {
|
|||||||
margin-bottom: 4pt;
|
margin-bottom: 4pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h3.page-break {
|
||||||
|
page-break-before: always;
|
||||||
|
}
|
||||||
|
|
||||||
p { margin-bottom: 6pt; }
|
p { margin-bottom: 6pt; }
|
||||||
|
|
||||||
ul {
|
ul {
|
||||||
@@ -78,17 +84,36 @@ a {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#headline {
|
#headline {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: flex-start;
|
||||||
position: static;
|
position: static;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: none;
|
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0 0 12pt 0;
|
padding: 0 0 12pt 0;
|
||||||
|
margin-bottom: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#headline-text {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#headline-photo {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-left: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#headline-photo img {
|
||||||
|
width: 90pt;
|
||||||
|
height: 110pt;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: 70% top;
|
||||||
|
border-radius: 4pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#cvcontent {
|
#cvcontent {
|
||||||
position: static;
|
position: static;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: none;
|
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
weasyprint>=60.0
|
||||||
Reference in New Issue
Block a user