feat: tilføj rigtig PDF download via WeasyPrint
All checks were successful
Build and Deploy Erika CV / build-and-deploy (push) Successful in 58s
All checks were successful
Build and Deploy Erika CV / build-and-deploy (push) Successful in 58s
- /download route genererer PDF server-side - PDF ser ud som hjemmesiden (ikke browser-print) - Kompakt print-CSS til 1 A4-side - Knap downloader direkte i stedet for at åbne print-dialog
This commit is contained in:
@@ -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 ./
|
||||
|
||||
15
app.py
15
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({
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
flask>=3.0.0
|
||||
gunicorn>=22.0.0
|
||||
weasyprint>=62.0
|
||||
|
||||
@@ -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 @@
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<button class="pdf-btn" onclick="window.print()">⬇ Download CV som PDF</button>
|
||||
{% if not pdf_mode %}
|
||||
<button class="pdf-btn" onclick="window.location='/download'">⬇ Download CV som PDF</button>
|
||||
{% endif %}
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user