diff --git a/Dockerfile b/Dockerfile
index e856613..4c92330 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -14,6 +14,15 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
WORKDIR /app
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ libpango-1.0-0 \
+ libpangoft2-1.0-0 \
+ libharfbuzz0b \
+ libfontconfig1 \
+ libcairo2 \
+ fonts-liberation \
+ && rm -rf /var/lib/apt/lists/*
+
RUN pip install --upgrade --no-cache-dir pip
COPY requirements.txt ./
diff --git a/app.py b/app.py
index 68a4c03..2ade3ef 100644
--- a/app.py
+++ b/app.py
@@ -1,6 +1,8 @@
-from flask import Flask, render_template, jsonify
+from flask import Flask, render_template, jsonify, send_file, request
+from weasyprint import HTML
from datetime import datetime, timezone
import os
+import io
app = Flask(__name__)
@@ -11,6 +13,17 @@ GIT_COMMIT = os.getenv('GIT_COMMIT', 'unknown')
def index():
return render_template('index.html')
+@app.route('/download')
+def download_pdf():
+ html = render_template('index.html', pdf_mode=True)
+ pdf = HTML(string=html, base_url=request.host_url).write_pdf()
+ return send_file(
+ io.BytesIO(pdf),
+ mimetype='application/pdf',
+ as_attachment=True,
+ download_name='Erika_Nielsen_CV.pdf'
+ )
+
@app.route('/health')
def health():
return jsonify({
diff --git a/requirements.txt b/requirements.txt
index ab3471f..71579c2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
flask>=3.0.0
gunicorn>=22.0.0
+weasyprint>=62.0
diff --git a/templates/index.html b/templates/index.html
index 704cb54..e97dfa8 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -379,26 +379,44 @@
}
.pdf-btn:hover { background: #2f72d0; transform: scale(1.04); }
- /* Print */
+ /* Print / PDF via WeasyPrint */
@media print {
- @page { size: A4; margin: 0; }
- html, body { background: white; padding: 0; margin: 0; display: block; }
- body {
- -webkit-print-color-adjust: exact;
- print-color-adjust: exact;
- }
- .cv-wrapper {
- box-shadow: none;
- border-radius: 0;
- width: 100%;
- max-width: 100%;
- transform-origin: top left;
- transform: scale(0.78);
- height: 128vh;
- overflow: hidden;
- }
+ @page { size: A4; margin: 8mm; }
+ html, body { background: white !important; padding: 0; margin: 0; }
+ body { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
+ .cv-wrapper { box-shadow: none; border-radius: 0; width: 194mm; max-width: 194mm; }
.sidebar { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
- .pdf-btn { display: none; }
+ .pdf-btn { display: none !important; }
+ /* Kompakt til 1 side */
+ body { padding: 0; }
+ .hero { padding: 18px 22px 12px; }
+ .hero-name { font-size: 22px; }
+ .hero-tagline { font-size: 11px; margin-bottom: 6px; }
+ .hero-summary { font-size: 11px; line-height: 1.5; }
+ .main { padding: 0 18px 10px; }
+ section { margin-bottom: 10px; }
+ .section-title { font-size: 10px; padding: 5px 0 4px; margin-bottom: 8px; }
+ .timeline-item { padding: 7px 0; }
+ .timeline-period { font-size: 9px; }
+ .timeline-title { font-size: 12px; }
+ .timeline-subtitle { font-size: 10px; }
+ .timeline-bullets { font-size: 10px; margin-top: 2px; }
+ .timeline-bullets li { margin-bottom: 0; }
+ .edu-card { padding: 7px 10px; }
+ .edu-period { font-size: 9px; }
+ .edu-title { font-size: 11px; }
+ .edu-place { font-size: 10px; }
+ .lang-item label { font-size: 10px; margin-bottom: 3px; }
+ .lang-bar-track { height: 4px; }
+ .tag { font-size: 9px; padding: 2px 6px; }
+ .sidebar-name h1 { font-size: 17px; }
+ .sidebar-name p { font-size: 10px; }
+ .sidebar-section { margin-bottom: 16px; }
+ .sidebar-section-title { font-size: 8px; }
+ .sidebar-item { font-size: 11px; }
+ .sidebar-item small { font-size: 9px; }
+ .avatar-wrap { padding: 18px 0 10px; }
+ .avatar { width: 70px; height: 70px; font-size: 22px; }
}
/* Mobile */
@@ -604,7 +622,9 @@
-
+{% if not pdf_mode %}
+
+{% endif %}