mirror of
https://github.com/mmahdium/portfolio.git
synced 2026-08-16 21:14:31 +03:30
feat(resume): complete Epic 4 - Resume Content Strategy and Guidelines
- Update resume data with comprehensive professional summary and optimized work experience highlights - Add resume content tech-spec and strategy documentation for 2025 best practices - Create resume guidelines reference document for content consistency - Enhance PDF composable with openPdf preview function alongside downloadPdf - Expand CSS banner hiding rules to block certificates.dev promotional content - Add research documentation on resume best practices and ATS optimization - Update i18n translations for resume content in English and Persian - Include sample Ali Arghyani resume PDF template in design assets - Refactor resume.en.ts with improved professional positioning and achievement metrics - Update API route documentation for PDF generation story artifacts - Establish foundation for Epic 4 sprint planning with tech specifications
This commit is contained in:
@@ -1,51 +1,49 @@
|
||||
/**
|
||||
* PDF Download Composable
|
||||
* Handles PDF download logic with loading state and error handling
|
||||
* Handles PDF generation with preview in new tab
|
||||
*/
|
||||
|
||||
export function useResumePdf() {
|
||||
const isGenerating = ref(false)
|
||||
const toast = useToast()
|
||||
const { getPdfFilename } = useResumeData()
|
||||
|
||||
async function downloadPdf() {
|
||||
// Open PDF in new tab for preview (user can download from there)
|
||||
async function openPdf() {
|
||||
if (isGenerating.value) return
|
||||
|
||||
isGenerating.value = true
|
||||
|
||||
try {
|
||||
// Fetch PDF as blob (AC1)
|
||||
const response = await $fetch<Blob>('/api/resume/pdf', {
|
||||
responseType: 'blob',
|
||||
})
|
||||
const filename = getPdfFilename()
|
||||
// Opens PDF in browser's built-in viewer
|
||||
window.open(`/api/resume/pdf?filename=${encodeURIComponent(filename)}`, '_blank')
|
||||
|
||||
// Create object URL from blob (AC2)
|
||||
const url = URL.createObjectURL(response)
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||||
} finally {
|
||||
isGenerating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Create temporary anchor element and trigger download
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = getPdfFilename() // AC3: filename from composable
|
||||
a.click()
|
||||
// Force download PDF directly
|
||||
async function downloadPdf() {
|
||||
if (isGenerating.value) return
|
||||
|
||||
// Revoke object URL to prevent memory leaks (AC8)
|
||||
URL.revokeObjectURL(url)
|
||||
} catch (error) {
|
||||
// Error handling (AC6)
|
||||
console.error('PDF generation failed:', error)
|
||||
isGenerating.value = true
|
||||
|
||||
toast.add({
|
||||
title: 'Error generating PDF',
|
||||
description: 'Please try again',
|
||||
color: 'error',
|
||||
})
|
||||
try {
|
||||
const filename = getPdfFilename()
|
||||
// download=true forces attachment header
|
||||
window.open(`/api/resume/pdf?filename=${encodeURIComponent(filename)}&download=true`, '_blank')
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1500))
|
||||
} finally {
|
||||
// Always reset loading state (AC7)
|
||||
isGenerating.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Return composable interface (AC4, AC5)
|
||||
return {
|
||||
isGenerating,
|
||||
openPdf,
|
||||
downloadPdf,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user