mirror of
https://github.com/mmahdium/portfolio.git
synced 2026-09-28 02:21:41 +03:30
- Add print media queries to main.css for proper PDF export formatting - Ensure white background and light color scheme when printing - Refactor ResumeAdditionalInfo component to display skills in categorized format - Remove languages and certifications from additional info section - Add ResumeLanguages component for dedicated language display - Optimize spacing with print-specific margin utilities across all resume sections - Improve text wrapping and hyphenation in ResumeExperience component - Enhance ResumeHeader layout with print-optimized image sizing - Update resume data structure to support new component organization - Add research documentation on mentioning AI skills in resume - Update PDF export endpoint to work with refactored component structure - Remove outdated chat history file
139 lines
3.7 KiB
TypeScript
139 lines
3.7 KiB
TypeScript
import puppeteer from 'puppeteer'
|
|
import type { Browser } from 'puppeteer'
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
let browser: Browser | null = null
|
|
|
|
try {
|
|
const requestUrl = getRequestURL(event)
|
|
const host = requestUrl.host.includes('192.168') || requestUrl.host.includes('localhost')
|
|
? 'localhost:5000'
|
|
: requestUrl.host
|
|
const baseUrl = `http://${host}`
|
|
const resumeUrl = `${baseUrl}/resume?print=true`
|
|
|
|
console.log('[PDF API] Generating from:', resumeUrl)
|
|
|
|
const isDev = process.env.NODE_ENV === 'development'
|
|
|
|
if (isDev) {
|
|
browser = await puppeteer.launch({
|
|
headless: true,
|
|
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
})
|
|
} else {
|
|
const chromium = await import('@sparticuz/chromium')
|
|
const puppeteerCore = await import('puppeteer-core')
|
|
browser = await puppeteerCore.default.launch({
|
|
args: chromium.default.args,
|
|
executablePath: await chromium.default.executablePath(),
|
|
headless: true,
|
|
})
|
|
}
|
|
|
|
const page = await browser.newPage()
|
|
|
|
// Set viewport to A4 dimensions (210mm x 297mm at 96 DPI)
|
|
await page.setViewport({
|
|
width: 794, // 210mm
|
|
height: 1123 // 297mm
|
|
})
|
|
|
|
// Enable print media type BEFORE loading page
|
|
await page.emulateMediaType('print')
|
|
|
|
const response = await page.goto(resumeUrl, {
|
|
waitUntil: 'networkidle0',
|
|
timeout: 30000,
|
|
})
|
|
|
|
if (!response || !response.ok()) {
|
|
throw new Error(`Failed to load: ${response?.status()}`)
|
|
}
|
|
|
|
// Inject critical CSS fixes
|
|
await page.addStyleTag({
|
|
content: `
|
|
@page {
|
|
size: A4;
|
|
margin: 1.2cm;
|
|
}
|
|
|
|
* {
|
|
box-shadow: none !important;
|
|
word-break: normal !important;
|
|
hyphens: none !important;
|
|
-webkit-hyphens: none !important;
|
|
-ms-hyphens: none !important;
|
|
}
|
|
|
|
html, body {
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
background: white !important;
|
|
min-height: auto !important;
|
|
}
|
|
|
|
.resume-wrapper {
|
|
background: white !important;
|
|
padding: 0 !important;
|
|
display: block !important;
|
|
margin: 0 !important;
|
|
}
|
|
|
|
.resume-container {
|
|
box-shadow: none !important;
|
|
max-width: none !important;
|
|
width: 100% !important;
|
|
margin: 0 !important;
|
|
padding: 0 !important;
|
|
}
|
|
|
|
.resume-content {
|
|
padding: 0 !important;
|
|
}
|
|
|
|
section {
|
|
page-break-inside: auto !important;
|
|
break-inside: auto !important;
|
|
}
|
|
|
|
h2 {
|
|
page-break-after: avoid !important;
|
|
break-after: avoid !important;
|
|
}
|
|
`,
|
|
})
|
|
|
|
const pdf = await page.pdf({
|
|
format: 'A4',
|
|
printBackground: true,
|
|
margin: { top: 0, right: 0, bottom: 0, left: 0 },
|
|
preferCSSPageSize: true,
|
|
})
|
|
|
|
const query = getQuery(event)
|
|
const filename = (query.filename as string) || 'Ali_Arghyani_Resume.pdf'
|
|
const download = query.download === 'true'
|
|
|
|
setResponseHeaders(event, {
|
|
'Content-Type': 'application/pdf',
|
|
// inline = show in browser, attachment = force download
|
|
'Content-Disposition': `${download ? 'attachment' : 'inline'}; filename="${filename}"`,
|
|
})
|
|
|
|
return pdf
|
|
} catch (error) {
|
|
console.error('PDF generation failed:', error)
|
|
setResponseStatus(event, 500)
|
|
return {
|
|
error: 'PDF generation failed',
|
|
message: error instanceof Error ? error.message : 'Unknown error',
|
|
}
|
|
} finally {
|
|
if (browser) {
|
|
await browser.close()
|
|
}
|
|
}
|
|
})
|