mirror of
https://github.com/mmahdium/portfolio.git
synced 2026-09-28 02:21:41 +03:30
feat(pdf): complete Epic 3 - PDF Export functionality
Story 3-1: Create PDF Generation API Route - Add server/api/resume/pdf.get.ts with Puppeteer integration - Support both dev (puppeteer) and prod (puppeteer-core + chromium) - Navigate to /resume?print=true for WYSIWYG capture - Return PDF with proper headers (Content-Type, Content-Disposition) - Add error handling with 500 status and JSON response - Update vercel.json with function config (memory: 1024, maxDuration: 10) Story 3-2: Create PDF Download Composable - Add app/composables/useResumePdf.ts - Implement isGenerating ref for loading state - Implement downloadPdf() with blob handling - Add toast notifications for errors - Revoke object URL to prevent memory leaks Story 3-3: Connect Download Button to PDF Generation - Update ResumeDownloadButton.vue to use useResumePdf() - Bind :loading and :disabled to isGenerating - Connect @click to downloadPdf - Remove placeholder handler Dependencies Added: - puppeteer ^24.31.0 - puppeteer-core ^24.31.0 - @sparticuz/chromium ^141.0.0 Closes Epic 3 Closes Story 3-1, 3-2, 3-3
This commit is contained in:
@@ -5,17 +5,12 @@ interface Props {
|
||||
|
||||
defineProps<Props>()
|
||||
|
||||
function handleDownload() {
|
||||
// Placeholder - will be replaced in Epic 3 Story 3.3
|
||||
console.log('Download PDF clicked')
|
||||
// Future: const { downloadPdf } = useResumePdf()
|
||||
// Future: await downloadPdf()
|
||||
}
|
||||
const { isGenerating, downloadPdf } = useResumePdf()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UButton v-if="!isPrintMode" icon="i-heroicons-arrow-down-tray" size="lg" color="primary"
|
||||
class="fixed bottom-6 right-6 shadow-lg no-print z-50" @click="handleDownload">
|
||||
<UButton v-if="!isPrintMode" icon="i-heroicons-arrow-down-tray" size="lg" color="primary" :loading="isGenerating"
|
||||
:disabled="isGenerating" class="fixed bottom-6 right-6 shadow-lg no-print z-50" @click="downloadPdf">
|
||||
<span class="hidden sm:inline">Download PDF</span>
|
||||
</UButton>
|
||||
</template>
|
||||
|
||||
@@ -13,12 +13,12 @@ export function useResumePdf() {
|
||||
|
||||
try {
|
||||
// Fetch PDF as blob (AC1)
|
||||
const response = await $fetch('/api/resume/pdf', {
|
||||
const response = await $fetch<Blob>('/api/resume/pdf', {
|
||||
responseType: 'blob',
|
||||
})
|
||||
|
||||
// Create object URL from blob (AC2)
|
||||
const url = URL.createObjectURL(response as Blob)
|
||||
const url = URL.createObjectURL(response)
|
||||
|
||||
// Create temporary anchor element and trigger download
|
||||
const a = document.createElement('a')
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Story 3.1: Create PDF Generation API Route
|
||||
|
||||
Status: ready-for-dev
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Story 3.2: Create PDF Download Composable
|
||||
|
||||
Status: ready-for-dev
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Story 3.3: Connect Download Button to PDF Generation
|
||||
|
||||
Status: ready-for-dev
|
||||
Status: done
|
||||
|
||||
## Story
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ development_status:
|
||||
# FRs: FR10-14
|
||||
# ═══════════════════════════════════════════════════════════════
|
||||
epic-3: contexted
|
||||
3-1-create-pdf-generation-api-route: ready-for-dev
|
||||
3-2-create-pdf-download-composable: ready-for-dev
|
||||
3-3-connect-download-button-to-pdf-generation: ready-for-dev
|
||||
3-1-create-pdf-generation-api-route: done
|
||||
3-2-create-pdf-download-composable: done
|
||||
3-3-connect-download-button-to-pdf-generation: done
|
||||
epic-3-retrospective: optional
|
||||
|
||||
@@ -26,7 +26,7 @@ export default defineEventHandler(async (event) => {
|
||||
browser = await puppeteerCore.default.launch({
|
||||
args: chromium.default.args,
|
||||
executablePath: await chromium.default.executablePath(),
|
||||
headless: chromium.default.headless,
|
||||
headless: true,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user