def generate_pdf(markdown_file: Path):
"""Generate a beautifully formatted PDF version of the code summary."""
try:
import markdown
from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration
except ImportError:
print("\n⚠️ PDF generation requires additional packages.")
print("Install with: pip install markdown weasyprint")
print("\nSkipping PDF generation...")
return None
print("\n📄 Generating PDF version...")
# Read the markdown file
with open(markdown_file, 'r', encoding='utf-8') as f:
md_content = f.read()
# Remove MkDocs-specific admonitions for cleaner PDF
md_content = md_content.replace('!!! info "Auto-Generated Documentation"\n', '')
md_content = md_content.replace(' Last updated:', '\n**Last updated:**')
md_content = md_content.replace(' ', '')
# Convert markdown to HTML
md = markdown.Markdown(extensions=['extra', 'codehilite', 'toc', 'tables'])
html_content = md.convert(md_content)
# Get current date for cover page
current_date = datetime.now().strftime('%B %d, %Y')
# Create a beautifully styled HTML document
html_template = f"""
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MFX Code Repository - User Cheat Sheet</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
@page {{
size: A4;
margin: 2.5cm 2cm;
@top-left {{
content: "MFX Code Repository";
font-size: 9pt;
color: #666;
font-family: 'Inter', sans-serif;
}}
@top-right {{
content: "{current_date}";
font-size: 9pt;
color: #666;
font-family: 'Inter', sans-serif;
}}
@bottom-center {{
content: "Page " counter(page) " of " counter(pages);
font-size: 9pt;
color: #666;
font-family: 'Inter', sans-serif;
}}
}}
@page :first {{
@top-left {{ content: none; }}
@top-right {{ content: none; }}
@bottom-center {{ content: none; }}
}}
/* Cover page styling */
.cover {{
page-break-after: always;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
background: linear-gradient(135deg, #ff6f00 0%, #d84315 100%);
color: white;
margin: -2.5cm -2cm;
padding: 2.5cm 2cm;
}}
.cover h1 {{
font-size: 42pt;
font-weight: 700;
margin-bottom: 20px;
border: none;
color: white;
}}
.cover .subtitle {{
font-size: 18pt;
font-weight: 300;
margin-bottom: 40px;
opacity: 0.9;
}}
.cover .info {{
font-size: 12pt;
margin-top: 60px;
opacity: 0.8;
}}
/* Body styling */
body {{
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 10pt;
line-height: 1.6;
color: #2c3e50;
font-weight: 400;
}}
/* Headers */
h1 {{
color: #d84315;
border-bottom: 4px solid #ff6f00;
padding-bottom: 12px;
margin-top: 40px;
margin-bottom: 20px;
font-size: 24pt;
font-weight: 700;
page-break-before: always;
page-break-after: avoid;
}}
h1:first-of-type {{
page-break-before: avoid;
margin-top: 0;
}}
h2 {{
color: #ff6f00;
border-bottom: 2px solid #ffb74d;
padding-bottom: 8px;
margin-top: 30px;
margin-bottom: 15px;
font-size: 16pt;
font-weight: 600;
page-break-after: avoid;
}}
h3 {{
color: #e65100;
margin-top: 20px;
margin-bottom: 10px;
font-size: 12pt;
font-weight: 600;
page-break-after: avoid;
}}
h4 {{
color: #f57c00;
margin-top: 15px;
margin-bottom: 8px;
font-size: 11pt;
font-weight: 600;
}}
/* Code styling */
code {{
background-color: #f8f9fa;
padding: 2px 6px;
border-radius: 3px;
font-family: 'JetBrains Mono', 'Courier New', monospace;
font-size: 9pt;
color: #e91e63;
border: 1px solid #e9ecef;
}}
pre {{
background-color: #f8f9fa;
padding: 12px;
border-left: 4px solid #ff6f00;
border-radius: 4px;
overflow-x: auto;
page-break-inside: avoid;
margin: 10px 0;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}}
pre code {{
background-color: transparent;
padding: 0;
color: #2c3e50;
border: none;
font-size: 8.5pt;
line-height: 1.5;
}}
/* Text emphasis */
strong {{
color: #d84315;
font-weight: 600;
}}
em {{
color: #546e7a;
font-style: italic;
}}
/* Horizontal rules */
hr {{
border: none;
border-top: 2px solid #eceff1;
margin: 25px 0;
}}
/* Lists */
ul, ol {{
margin-left: 20px;
margin-bottom: 15px;
}}
li {{
margin-bottom: 6px;
line-height: 1.5;
}}
ul li {{
list-style-type: square;
}}
/* Links */
a {{
color: #1976d2;
text-decoration: none;
}}
a:hover {{
text-decoration: underline;
}}
/* Table of Contents */
.toc {{
background: linear-gradient(135deg, #fff3e0 0%, #ffe0b2 100%);
padding: 20px;
border-radius: 8px;
margin-bottom: 30px;
border: 2px solid #ffb74d;
page-break-inside: avoid;
}}
.toc h2 {{
color: #e65100;
border: none;
margin-top: 0;
}}
/* Statistics box */
.statistics {{
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
padding: 20px;
border-radius: 8px;
margin-top: 30px;
border: 2px solid #64b5f6;
page-break-inside: avoid;
}}
.statistics h2 {{
color: #1565c0;
border: none;
margin-top: 0;
}}
/* Tables */
table {{
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 9pt;
page-break-inside: avoid;
}}
th {{
background-color: #ff6f00;
color: white;
padding: 10px;
text-align: left;
font-weight: 600;
}}
td {{
padding: 8px;
border-bottom: 1px solid #eceff1;
}}
tr:nth-child(even) {{
background-color: #f8f9fa;
}}
/* Module sections */
.module {{
margin-bottom: 20px;
padding: 15px;
background-color: #fafafa;
border-left: 4px solid #ff6f00;
border-radius: 4px;
page-break-inside: avoid;
}}
/* Blockquotes */
blockquote {{
border-left: 4px solid #ff6f00;
padding-left: 15px;
margin-left: 0;
color: #546e7a;
font-style: italic;
}}
/* Page breaks */
.page-break {{
page-break-after: always;
}}
/* Avoid breaks */
h1, h2, h3, h4, h5, h6 {{
page-break-after: avoid;
}}
/* Footer note */
.footer-note {{
margin-top: 40px;
padding-top: 20px;
border-top: 2px solid #eceff1;
font-size: 9pt;
color: #78909c;
text-align: center;
}}
</style>
</head>
<body>
<!-- Cover Page -->
<div class="cover">
<h1>MFX Code Repository</h1>
<div class="subtitle">User Cheat Sheet & Function Reference</div>
<div class="info">
<p>LCLS MFX Beamline</p>
<p>Generated: {current_date}</p>
</div>
</div>
<!-- Content -->
{html_content}
<!-- Footer -->
<div class="footer-note">
<p>This document is automatically generated from the MFX repository.</p>
<p>For the most up-to-date information, visit the online documentation.</p>
</div>
</body>
</html>
"""
# Generate PDF with the desired filename
pdf_path = markdown_file.parent / 'user_cheat_sheet.pdf'
font_config = FontConfiguration()
html = HTML(string=html_template)
css = CSS(string='''
@page {
size: A4;
margin: 2.5cm 2cm;
}
''', font_config=font_config)
html.write_pdf(pdf_path, stylesheets=[css], font_config=font_config)
print(f"✅ PDF generated: {pdf_path}")
file_size = pdf_path.stat().st_size / 1024 # Size in KB
print(f" File size: {file_size:.1f} KB")
return pdf_path