|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Resume Tailor Pro</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.12.313/pdf.min.js"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mammoth/1.4.0/mammoth.browser.min.js"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script> |
|
|
<style> |
|
|
.dropzone { |
|
|
border: 2px dashed #3b82f6; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.dropzone.active { |
|
|
border-color: #10b981; |
|
|
background-color: #f0f9ff; |
|
|
} |
|
|
.progress-bar { |
|
|
transition: width 0.3s ease; |
|
|
} |
|
|
.resume-point { |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
.resume-point.highlight { |
|
|
background-color: #fef08a; |
|
|
border-left: 4px solid #f59e0b; |
|
|
} |
|
|
.keyword-chip { |
|
|
animation: pulse 1.5s infinite; |
|
|
} |
|
|
@keyframes pulse { |
|
|
0% { transform: scale(1); } |
|
|
50% { transform: scale(1.05); } |
|
|
100% { transform: scale(1); } |
|
|
} |
|
|
.fade-in { |
|
|
animation: fadeIn 0.5s ease-in; |
|
|
} |
|
|
@keyframes fadeIn { |
|
|
from { opacity: 0; transform: translateY(10px); } |
|
|
to { opacity: 1; transform: translateY(0); } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 min-h-screen"> |
|
|
<div class="container mx-auto px-4 py-8 max-w-6xl"> |
|
|
|
|
|
<header class="text-center mb-12"> |
|
|
<h1 class="text-4xl font-bold text-blue-600 mb-2">Resume Tailor Pro</h1> |
|
|
<p class="text-lg text-gray-600">Transform your generic resume into a job-winning document in minutes</p> |
|
|
<div class="w-24 h-1 bg-blue-500 mx-auto mt-4 rounded-full"></div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-lg overflow-hidden"> |
|
|
|
|
|
<div class="flex justify-between px-8 py-4 bg-gray-100"> |
|
|
<div class="step flex flex-col items-center relative w-1/4"> |
|
|
<div class="w-10 h-10 rounded-full bg-blue-600 text-white flex items-center justify-center font-bold mb-2 z-10">1</div> |
|
|
<span class="text-sm font-medium text-blue-600">Upload Resume</span> |
|
|
<div class="absolute top-5 left-1/2 h-1 w-full bg-gray-300 -z-1"></div> |
|
|
</div> |
|
|
<div class="step flex flex-col items-center relative w-1/4"> |
|
|
<div class="w-10 h-10 rounded-full bg-gray-300 text-white flex items-center justify-center font-bold mb-2 z-10">2</div> |
|
|
<span class="text-sm font-medium text-gray-500">Job Description</span> |
|
|
<div class="absolute top-5 left-1/2 h-1 w-full bg-gray-300 -z-1"></div> |
|
|
</div> |
|
|
<div class="step flex flex-col items-center relative w-1/4"> |
|
|
<div class="w-10 h-10 rounded-full bg-gray-300 text-white flex items-center justify-center font-bold mb-2 z-10">3</div> |
|
|
<span class="text-sm font-medium text-gray-500">Tailor Resume</span> |
|
|
<div class="absolute top-5 left-1/2 h-1 w-full bg-gray-300 -z-1"></div> |
|
|
</div> |
|
|
<div class="step flex flex-col items-center relative w-1/4"> |
|
|
<div class="w-10 h-10 rounded-full bg-gray-300 text-white flex items-center justify-center font-bold mb-2 z-10">4</div> |
|
|
<span class="text-sm font-medium text-gray-500">Download</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step1" class="p-8"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Upload Your Resume</h2> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> |
|
|
<div> |
|
|
<div id="dropzone" class="dropzone rounded-lg p-8 text-center cursor-pointer h-64 flex flex-col items-center justify-center"> |
|
|
<i class="fas fa-cloud-upload-alt text-4xl text-blue-500 mb-4"></i> |
|
|
<p class="text-lg font-medium text-gray-700 mb-2">Drag & drop your resume here</p> |
|
|
<p class="text-sm text-gray-500 mb-4">or</p> |
|
|
<label for="fileInput" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition cursor-pointer"> |
|
|
Browse Files |
|
|
</label> |
|
|
<input type="file" id="fileInput" class="hidden" accept=".pdf,.doc,.docx"> |
|
|
<p class="text-xs text-gray-500 mt-4">Supports: PDF, DOC, DOCX</p> |
|
|
</div> |
|
|
<div id="fileInfo" class="mt-4 hidden"> |
|
|
<div class="flex items-center justify-between mb-2"> |
|
|
<span class="font-medium text-gray-700 truncate max-w-xs" id="fileName"></span> |
|
|
<button id="removeFile" class="text-red-500 hover:text-red-700"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="w-full bg-gray-200 rounded-full h-2.5"> |
|
|
<div id="uploadProgress" class="progress-bar bg-blue-600 h-2.5 rounded-full" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bg-blue-50 p-6 rounded-lg border border-blue-100"> |
|
|
<h3 class="text-lg font-semibold text-blue-800 mb-3">Tips for Best Results</h3> |
|
|
<ul class="space-y-3"> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> |
|
|
<span class="text-gray-700">Use a recent resume with clear section headings</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> |
|
|
<span class="text-gray-700">Ensure your document is readable (not scanned)</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> |
|
|
<span class="text-gray-700">Include measurable achievements in bullet points</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-green-500 mt-1 mr-2"></i> |
|
|
<span class="text-gray-700">Remove personal information if concerned about privacy</span> |
|
|
</li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-end mt-8"> |
|
|
<button id="nextStep1" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition disabled:opacity-50 disabled:cursor-not-allowed" disabled> |
|
|
Next: Job Description <i class="fas fa-arrow-right ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step2" class="p-8 hidden"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Enter Job Description</h2> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> |
|
|
<div> |
|
|
<div class="mb-4"> |
|
|
<label for="jobTitle" class="block text-sm font-medium text-gray-700 mb-1">Job Title</label> |
|
|
<input type="text" id="jobTitle" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" placeholder="e.g. Senior Software Engineer"> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label for="jobDescription" class="block text-sm font-medium text-gray-700 mb-1">Paste Job Description</label> |
|
|
<textarea id="jobDescription" rows="10" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500" placeholder="Paste the full job description here..."></textarea> |
|
|
</div> |
|
|
<div class="flex space-x-3"> |
|
|
<button id="analyzeJD" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition"> |
|
|
Analyze Keywords <i class="fas fa-search ml-2"></i> |
|
|
</button> |
|
|
<button id="sampleJD" class="px-4 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition"> |
|
|
Load Sample <i class="fas fa-lightbulb ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<div class="bg-yellow-50 p-6 rounded-lg border border-yellow-200"> |
|
|
<h3 class="text-lg font-semibold text-yellow-800 mb-3">Extracted Keywords</h3> |
|
|
<div id="keywordsContainer" class="flex flex-wrap gap-2 mb-4"> |
|
|
|
|
|
</div> |
|
|
<div class="space-y-3"> |
|
|
<div> |
|
|
<label class="flex items-center"> |
|
|
<input type="checkbox" id="highlightKeywords" class="rounded text-blue-600 mr-2" checked> |
|
|
<span class="text-gray-700">Highlight keywords in resume</span> |
|
|
</label> |
|
|
</div> |
|
|
<div> |
|
|
<label class="flex items-center"> |
|
|
<input type="checkbox" id="addMissingKeywords" class="rounded text-blue-600 mr-2" checked> |
|
|
<span class="text-gray-700">Add missing keywords to resume</span> |
|
|
</label> |
|
|
</div> |
|
|
<div> |
|
|
<label class="flex items-center"> |
|
|
<input type="checkbox" id="reorderBullets" class="rounded text-blue-600 mr-2" checked> |
|
|
<span class="text-gray-700">Reorder bullet points by relevance</span> |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mt-4 bg-green-50 p-6 rounded-lg border border-green-200"> |
|
|
<h3 class="text-lg font-semibold text-green-800 mb-3">Keyword Optimization Score</h3> |
|
|
<div class="flex items-center mb-2"> |
|
|
<div class="w-full bg-gray-200 rounded-full h-4"> |
|
|
<div id="matchScoreBar" class="bg-green-600 h-4 rounded-full" style="width: 0%"></div> |
|
|
</div> |
|
|
<span id="matchScoreText" class="ml-3 font-bold text-green-700">0%</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600">This score shows how well your current resume matches the job description keywords.</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-between mt-8"> |
|
|
<button id="prevStep2" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition"> |
|
|
<i class="fas fa-arrow-left mr-2"></i> Back |
|
|
</button> |
|
|
<button id="nextStep2" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition disabled:opacity-50 disabled:cursor-not-allowed" disabled> |
|
|
Next: Tailor Resume <i class="fas fa-arrow-right ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step3" class="p-8 hidden"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Tailor Your Resume</h2> |
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
|
|
<div class="lg:col-span-2"> |
|
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm overflow-hidden"> |
|
|
<div class="bg-gray-50 px-4 py-3 border-b border-gray-200"> |
|
|
<h3 class="text-lg font-medium text-gray-800">Resume Preview</h3> |
|
|
</div> |
|
|
<div id="resumePreview" class="p-6 overflow-auto max-h-[600px]"> |
|
|
|
|
|
<div class="text-center py-12 text-gray-500"> |
|
|
<i class="fas fa-file-alt text-4xl mb-4"></i> |
|
|
<p>Your tailored resume will appear here</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div> |
|
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm overflow-hidden mb-6"> |
|
|
<div class="bg-gray-50 px-4 py-3 border-b border-gray-200"> |
|
|
<h3 class="text-lg font-medium text-gray-800">Suggested Edits</h3> |
|
|
</div> |
|
|
<div id="suggestionsContainer" class="p-4 overflow-auto max-h-[300px]"> |
|
|
|
|
|
<div class="text-center py-8 text-gray-500"> |
|
|
<i class="fas fa-lightbulb text-2xl mb-3"></i> |
|
|
<p>AI-powered suggestions will appear here</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="bg-white border border-gray-200 rounded-lg shadow-sm overflow-hidden"> |
|
|
<div class="bg-gray-50 px-4 py-3 border-b border-gray-200"> |
|
|
<h3 class="text-lg font-medium text-gray-800">Customize Output</h3> |
|
|
</div> |
|
|
<div class="p-4"> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Output Format</label> |
|
|
<div class="flex space-x-4"> |
|
|
<label class="inline-flex items-center"> |
|
|
<input type="radio" name="outputFormat" class="text-blue-600" value="pdf" checked> |
|
|
<span class="ml-2 text-gray-700">PDF</span> |
|
|
</label> |
|
|
<label class="inline-flex items-center"> |
|
|
<input type="radio" name="outputFormat" class="text-blue-600" value="docx"> |
|
|
<span class="ml-2 text-gray-700">Word (DOCX)</span> |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
<div class="mb-4"> |
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">Resume Style</label> |
|
|
<select id="resumeStyle" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:ring-blue-500 focus:border-blue-500"> |
|
|
<option value="modern">Modern</option> |
|
|
<option value="professional">Professional</option> |
|
|
<option value="creative">Creative</option> |
|
|
<option value="minimal">Minimal</option> |
|
|
</select> |
|
|
</div> |
|
|
<button id="generateResume" class="w-full px-4 py-3 bg-green-600 text-white rounded-md hover:bg-green-700 transition font-medium"> |
|
|
Generate Tailored Resume <i class="fas fa-magic ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-between mt-8"> |
|
|
<button id="prevStep3" class="px-6 py-2 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition"> |
|
|
<i class="fas fa-arrow-left mr-2"></i> Back |
|
|
</button> |
|
|
<button id="nextStep3" class="px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition hidden"> |
|
|
Next: Download <i class="fas fa-arrow-right ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step4" class="p-8 hidden"> |
|
|
<div class="text-center py-12"> |
|
|
<div class="mx-auto w-24 h-24 bg-green-100 rounded-full flex items-center justify-center mb-6"> |
|
|
<i class="fas fa-check text-4xl text-green-600"></i> |
|
|
</div> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-3">Your Tailored Resume is Ready!</h2> |
|
|
<p class="text-gray-600 mb-8 max-w-2xl mx-auto">We've optimized your resume to match the job description with relevant keywords and impactful bullet points.</p> |
|
|
|
|
|
<div class="flex flex-col sm:flex-row justify-center gap-4 mb-12"> |
|
|
<button id="downloadResume" class="px-6 py-3 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition font-medium"> |
|
|
<i class="fas fa-download mr-2"></i> Download Resume |
|
|
</button> |
|
|
<button id="viewChanges" class="px-6 py-3 bg-gray-200 text-gray-700 rounded-md hover:bg-gray-300 transition font-medium"> |
|
|
<i class="fas fa-file-diff mr-2"></i> View Changes Summary |
|
|
</button> |
|
|
<button id="newResume" class="px-6 py-3 bg-white border border-gray-300 text-gray-700 rounded-md hover:bg-gray-50 transition font-medium"> |
|
|
<i class="fas fa-redo mr-2"></i> Tailor Another Resume |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="bg-blue-50 p-6 rounded-lg border border-blue-200 max-w-2xl mx-auto text-left"> |
|
|
<h3 class="text-lg font-semibold text-blue-800 mb-3">Next Steps</h3> |
|
|
<ul class="space-y-2 text-gray-700"> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i> |
|
|
<span>Review your resume for accuracy and personal touch</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i> |
|
|
<span>Save with a descriptive filename (e.g., "JohnDoe_UX_Designer_Resume.pdf")</span> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-check-circle text-blue-500 mt-1 mr-2"></i> |
|
|
<span>Combine with a tailored cover letter for best results</span> |
|
|
</li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<footer class="mt-16 text-center text-gray-500 text-sm"> |
|
|
<p>Resume Tailor Pro uses AI to help you create job-winning resumes. We don't store your personal data.</p> |
|
|
<p class="mt-2">© 2023 Resume Tailor Pro. All rights reserved.</p> |
|
|
</footer> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
let resumeFile = null; |
|
|
let resumeText = ''; |
|
|
let jobDescriptionText = ''; |
|
|
let extractedKeywords = []; |
|
|
let tailoredResumeHTML = ''; |
|
|
|
|
|
|
|
|
const dropzone = document.getElementById('dropzone'); |
|
|
const fileInput = document.getElementById('fileInput'); |
|
|
const fileInfo = document.getElementById('fileInfo'); |
|
|
const fileName = document.getElementById('fileName'); |
|
|
const removeFile = document.getElementById('removeFile'); |
|
|
const uploadProgress = document.getElementById('uploadProgress'); |
|
|
const nextStep1 = document.getElementById('nextStep1'); |
|
|
|
|
|
const step1 = document.getElementById('step1'); |
|
|
const step2 = document.getElementById('step2'); |
|
|
const step3 = document.getElementById('step3'); |
|
|
const step4 = document.getElementById('step4'); |
|
|
|
|
|
const prevStep2 = document.getElementById('prevStep2'); |
|
|
const nextStep2 = document.getElementById('nextStep2'); |
|
|
|
|
|
const prevStep3 = document.getElementById('prevStep3'); |
|
|
const nextStep3 = document.getElementById('nextStep3'); |
|
|
|
|
|
const jobTitle = document.getElementById('jobTitle'); |
|
|
const jobDescription = document.getElementById('jobDescription'); |
|
|
const analyzeJD = document.getElementById('analyzeJD'); |
|
|
const sampleJD = document.getElementById('sampleJD'); |
|
|
const keywordsContainer = document.getElementById('keywordsContainer'); |
|
|
const matchScoreBar = document.getElementById('matchScoreBar'); |
|
|
const matchScoreText = document.getElementById('matchScoreText'); |
|
|
|
|
|
const resumePreview = document.getElementById('resumePreview'); |
|
|
const suggestionsContainer = document.getElementById('suggestionsContainer'); |
|
|
const generateResume = document.getElementById('generateResume'); |
|
|
|
|
|
const downloadResume = document.getElementById('downloadResume'); |
|
|
const viewChanges = document.getElementById('viewChanges'); |
|
|
const newResume = document.getElementById('newResume'); |
|
|
|
|
|
|
|
|
dropzone.addEventListener('click', () => fileInput.click()); |
|
|
dropzone.addEventListener('dragover', (e) => { |
|
|
e.preventDefault(); |
|
|
dropzone.classList.add('active'); |
|
|
}); |
|
|
dropzone.addEventListener('dragleave', () => { |
|
|
dropzone.classList.remove('active'); |
|
|
}); |
|
|
dropzone.addEventListener('drop', (e) => { |
|
|
e.preventDefault(); |
|
|
dropzone.classList.remove('active'); |
|
|
if (e.dataTransfer.files.length) { |
|
|
handleFileUpload(e.dataTransfer.files[0]); |
|
|
} |
|
|
}); |
|
|
|
|
|
fileInput.addEventListener('change', () => { |
|
|
if (fileInput.files.length) { |
|
|
handleFileUpload(fileInput.files[0]); |
|
|
} |
|
|
}); |
|
|
|
|
|
removeFile.addEventListener('click', (e) => { |
|
|
e.stopPropagation(); |
|
|
resetFileUpload(); |
|
|
}); |
|
|
|
|
|
nextStep1.addEventListener('click', () => { |
|
|
step1.classList.add('hidden'); |
|
|
step2.classList.remove('hidden'); |
|
|
updateStepProgress(2); |
|
|
}); |
|
|
|
|
|
prevStep2.addEventListener('click', () => { |
|
|
step2.classList.add('hidden'); |
|
|
step1.classList.remove('hidden'); |
|
|
updateStepProgress(1); |
|
|
}); |
|
|
|
|
|
nextStep2.addEventListener('click', () => { |
|
|
step2.classList.add('hidden'); |
|
|
step3.classList.remove('hidden'); |
|
|
updateStepProgress(3); |
|
|
|
|
|
displayResumePreview(); |
|
|
}); |
|
|
|
|
|
prevStep3.addEventListener('click', () => { |
|
|
step3.classList.add('hidden'); |
|
|
step2.classList.remove('hidden'); |
|
|
updateStepProgress(2); |
|
|
}); |
|
|
|
|
|
nextStep3.addEventListener('click', () => { |
|
|
step3.classList.add('hidden'); |
|
|
step4.classList.remove('hidden'); |
|
|
updateStepProgress(4); |
|
|
}); |
|
|
|
|
|
analyzeJD.addEventListener('click', analyzeJobDescription); |
|
|
sampleJD.addEventListener('click', loadSampleJobDescription); |
|
|
generateResume.addEventListener('click', generateTailoredResume); |
|
|
downloadResume.addEventListener('click', downloadTailoredResume); |
|
|
viewChanges.addEventListener('click', showChangesSummary); |
|
|
newResume.addEventListener('click', resetApplication); |
|
|
|
|
|
|
|
|
function handleFileUpload(file) { |
|
|
const validTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document']; |
|
|
|
|
|
if (!validTypes.includes(file.type) && !file.name.match(/\.(pdf|doc|docx)$/i)) { |
|
|
alert('Please upload a PDF or Word document'); |
|
|
return; |
|
|
} |
|
|
|
|
|
resumeFile = file; |
|
|
fileName.textContent = file.name; |
|
|
fileInfo.classList.remove('hidden'); |
|
|
nextStep1.disabled = false; |
|
|
|
|
|
|
|
|
let progress = 0; |
|
|
const interval = setInterval(() => { |
|
|
progress += Math.random() * 10; |
|
|
if (progress >= 100) { |
|
|
progress = 100; |
|
|
clearInterval(interval); |
|
|
} |
|
|
uploadProgress.style.width = `${progress}%`; |
|
|
}, 200); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
function resetFileUpload() { |
|
|
resumeFile = null; |
|
|
fileInput.value = ''; |
|
|
fileInfo.classList.add('hidden'); |
|
|
uploadProgress.style.width = '0%'; |
|
|
nextStep1.disabled = true; |
|
|
} |
|
|
|
|
|
function updateStepProgress(stepNumber) { |
|
|
const steps = document.querySelectorAll('.step'); |
|
|
|
|
|
steps.forEach((step, index) => { |
|
|
const number = step.querySelector('div:first-child'); |
|
|
const text = step.querySelector('span'); |
|
|
const line = step.querySelector('div:last-child'); |
|
|
|
|
|
if (index + 1 < stepNumber) { |
|
|
|
|
|
number.classList.remove('bg-gray-300'); |
|
|
number.classList.add('bg-green-500'); |
|
|
text.classList.remove('text-gray-500'); |
|
|
text.classList.add('text-green-600'); |
|
|
if (line) line.classList.remove('bg-gray-300'); |
|
|
if (line) line.classList.add('bg-green-500'); |
|
|
} else if (index + 1 === stepNumber) { |
|
|
|
|
|
number.classList.remove('bg-gray-300'); |
|
|
number.classList.remove('bg-green-500'); |
|
|
number.classList.add('bg-blue-600'); |
|
|
text.classList.remove('text-gray-500'); |
|
|
text.classList.remove('text-green-600'); |
|
|
text.classList.add('text-blue-600'); |
|
|
} else { |
|
|
|
|
|
number.classList.remove('bg-blue-600'); |
|
|
number.classList.remove('bg-green-500'); |
|
|
number.classList.add('bg-gray-300'); |
|
|
text.classList.remove('text-blue-600'); |
|
|
text.classList.remove('text-green-600'); |
|
|
text.classList.add('text-gray-500'); |
|
|
if (line) line.classList.remove('bg-green-500'); |
|
|
if (line) line.classList.add('bg-gray-300'); |
|
|
} |
|
|
}); |
|
|
} |
|
|
|
|
|
function analyzeJobDescription() { |
|
|
jobDescriptionText = jobDescription.value.trim(); |
|
|
|
|
|
if (!jobDescriptionText) { |
|
|
alert('Please enter a job description'); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
const words = jobDescriptionText.toLowerCase() |
|
|
.replace(/[^\w\s]|_/g, '') |
|
|
.replace(/\s+/g, ' ') |
|
|
.split(' '); |
|
|
|
|
|
|
|
|
const commonWords = ['the', 'and', 'a', 'an', 'in', 'on', 'at', 'to', 'for', 'with', 'of', 'as', 'is', 'are', 'be', 'this', 'that']; |
|
|
const wordCounts = {}; |
|
|
|
|
|
words.forEach(word => { |
|
|
if (word.length > 3 && !commonWords.includes(word)) { |
|
|
wordCounts[word] = (wordCounts[word] || 0) + 1; |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
extractedKeywords = Object.entries(wordCounts) |
|
|
.sort((a, b) => b[1] - a[1]) |
|
|
.slice(0, 15) |
|
|
.map(item => item[0]); |
|
|
|
|
|
displayKeywords(); |
|
|
calculateMatchScore(); |
|
|
nextStep2.disabled = false; |
|
|
} |
|
|
|
|
|
function displayKeywords() { |
|
|
keywordsContainer.innerHTML = ''; |
|
|
|
|
|
extractedKeywords.forEach(keyword => { |
|
|
const chip = document.createElement('div'); |
|
|
chip.className = 'keyword-chip px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm font-medium'; |
|
|
chip.textContent = keyword; |
|
|
keywordsContainer.appendChild(chip); |
|
|
}); |
|
|
} |
|
|
|
|
|
function calculateMatchScore() { |
|
|
|
|
|
|
|
|
const score = Math.floor(Math.random() * 30) + 20; |
|
|
matchScoreBar.style.width = `${score}%`; |
|
|
matchScoreText.textContent = `${score}%`; |
|
|
|
|
|
|
|
|
if (score < 30) { |
|
|
matchScoreBar.classList.remove('bg-green-600', 'bg-yellow-500'); |
|
|
matchScoreBar.classList.add('bg-red-500'); |
|
|
} else if (score < 60) { |
|
|
matchScoreBar.classList.remove('bg-green-600', 'bg-red-500'); |
|
|
matchScoreBar.classList.add('bg-yellow-500'); |
|
|
} else { |
|
|
matchScoreBar.classList.remove('bg-yellow-500', 'bg-red-500'); |
|
|
matchScoreBar.classList.add('bg-green-600'); |
|
|
} |
|
|
} |
|
|
|
|
|
function loadSampleJobDescription() { |
|
|
const sample = `Senior Software Engineer - Web Development |
|
|
|
|
|
We are looking for an experienced Senior Software Engineer to join our web development team. The ideal candidate will have strong expertise in JavaScript frameworks, cloud technologies, and agile methodologies. |
|
|
|
|
|
Responsibilities: |
|
|
- Develop and maintain high-performance web applications using React.js and Node.js |
|
|
- Design and implement RESTful APIs and microservices architecture |
|
|
- Collaborate with cross-functional teams to define, design, and ship new features |
|
|
- Optimize applications for maximum speed and scalability |
|
|
- Implement automated testing platforms and unit tests |
|
|
- Stay up-to-date with emerging technologies and industry trends |
|
|
|
|
|
Requirements: |
|
|
- 5+ years of professional software development experience |
|
|
- Strong proficiency in JavaScript, including DOM manipulation and JS object model |
|
|
- Thorough understanding of React.js and its core principles |
|
|
- Experience with popular React.js workflows (such as Redux or Context API) |
|
|
- Familiarity with modern front-end build pipelines and tools |
|
|
- Experience with cloud platforms (AWS, Azure, or GCP) |
|
|
- Knowledge of modern authorization mechanisms (JWT, OAuth) |
|
|
- Familiarity with code versioning tools (Git) |
|
|
- Excellent problem-solving skills and attention to detail |
|
|
|
|
|
Preferred Qualifications: |
|
|
- Experience with TypeScript |
|
|
- Knowledge of server-side rendering and Next.js |
|
|
- Familiarity with Docker and Kubernetes |
|
|
- Understanding of CI/CD pipelines`; |
|
|
|
|
|
jobTitle.value = 'Senior Software Engineer'; |
|
|
jobDescription.value = sample; |
|
|
} |
|
|
|
|
|
function displayResumePreview() { |
|
|
|
|
|
|
|
|
|
|
|
const sampleResumeHTML = ` |
|
|
<div class="font-sans"> |
|
|
<div class="text-center mb-6"> |
|
|
<h1 class="text-2xl font-bold text-gray-800">John Doe</h1> |
|
|
<p class="text-gray-600">Senior Software Engineer | john.doe@example.com | (123) 456-7890</p> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<h2 class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-3">Professional Summary</h2> |
|
|
<p class="text-gray-700">Experienced software engineer with 7+ years in web development. Skilled in JavaScript, React, and Node.js. Passionate about building scalable web applications and mentoring junior developers.</p> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<h2 class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-3">Technical Skills</h2> |
|
|
<div class="flex flex-wrap gap-2"> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">JavaScript</span> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">React</span> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">Node.js</span> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">HTML/CSS</span> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">Git</span> |
|
|
<span class="px-3 py-1 bg-gray-100 text-gray-800 rounded-full text-sm">REST APIs</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mb-6"> |
|
|
<h2 class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-3">Work Experience</h2> |
|
|
|
|
|
<div class="mb-4"> |
|
|
<div class="flex justify-between"> |
|
|
<h3 class="font-medium text-gray-800">Senior Software Engineer</h3> |
|
|
<span class="text-gray-600">2019 - Present</span> |
|
|
</div> |
|
|
<p class="text-gray-600 mb-2">Tech Solutions Inc., San Francisco, CA</p> |
|
|
<ul class="list-disc list-inside space-y-1 text-gray-700"> |
|
|
<li class="resume-point">Led a team of 5 developers to build a React-based customer portal</li> |
|
|
<li class="resume-point">Improved application performance by 40% through code optimization</li> |
|
|
<li class="resume-point">Implemented CI/CD pipeline reducing deployment time by 60%</li> |
|
|
<li class="resume-point">Mentored junior developers in JavaScript best practices</li> |
|
|
</ul> |
|
|
</div> |
|
|
|
|
|
<div class="mb-4"> |
|
|
<div class="flex justify-between"> |
|
|
<h3 class="font-medium text-gray-800">Software Engineer</h3> |
|
|
<span class="text-gray-600">2016 - 2019</span> |
|
|
</div> |
|
|
<p class="text-gray-600 mb-2">Digital Innovations LLC, Austin, TX</p> |
|
|
<ul class="list-disc list-inside space-y-1 text-gray-700"> |
|
|
<li class="resume-point">Developed Node.js microservices for e-commerce platform</li> |
|
|
<li class="resume-point">Reduced server costs by 30% through AWS optimization</li> |
|
|
<li class="resume-point">Collaborated with UX team to implement responsive designs</li> |
|
|
</ul> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h2 class="text-xl font-semibold text-gray-800 border-b border-gray-200 pb-1 mb-3">Education</h2> |
|
|
<div class="flex justify-between"> |
|
|
<h3 class="font-medium text-gray-800">B.S. in Computer Science</h3> |
|
|
<span class="text-gray-600">2012 - 2016</span> |
|
|
</div> |
|
|
<p class="text-gray-600">University of Texas at Austin</p> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
resumePreview.innerHTML = sampleResumeHTML; |
|
|
|
|
|
|
|
|
generateSuggestions(); |
|
|
} |
|
|
|
|
|
function generateSuggestions() { |
|
|
|
|
|
|
|
|
|
|
|
const suggestions = [ |
|
|
{ |
|
|
section: "Professional Summary", |
|
|
suggestion: "Add mention of cloud technologies and agile methodologies to better match the job description." |
|
|
}, |
|
|
{ |
|
|
section: "Technical Skills", |
|
|
suggestion: "Include keywords: TypeScript, AWS, Docker, Kubernetes, CI/CD to improve ATS compatibility." |
|
|
}, |
|
|
{ |
|
|
section: "Senior Software Engineer", |
|
|
suggestion: "Modify bullet points to emphasize React workflows and API development experience." |
|
|
}, |
|
|
{ |
|
|
section: "All Experience", |
|
|
suggestion: "Add metrics to achievements where possible (e.g., 'Improved performance by X%')." |
|
|
} |
|
|
]; |
|
|
|
|
|
suggestionsContainer.innerHTML = ''; |
|
|
|
|
|
suggestions.forEach((item, index) => { |
|
|
const suggestionDiv = document.createElement('div'); |
|
|
suggestionDiv.className = `mb-4 pb-4 ${index < suggestions.length - 1 ? 'border-b border-gray-200' : ''}`; |
|
|
suggestionDiv.innerHTML = ` |
|
|
<div class="flex items-start"> |
|
|
<div class="bg-blue-100 p-2 rounded-full mr-3"> |
|
|
<i class="fas fa-lightbulb text-blue-600 text-sm"></i> |
|
|
</div> |
|
|
<div> |
|
|
<h4 class="font-medium text-gray-800">${item.section}</h4> |
|
|
<p class="text-gray-600 text-sm">${item.suggestion}</p> |
|
|
<button class="mt-2 text-sm text-blue-600 hover:text-blue-800 font-medium"> |
|
|
Apply Suggestion <i class="fas fa-check ml-1"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
suggestionsContainer.appendChild(suggestionDiv); |
|
|
}); |
|
|
} |
|
|
|
|
|
function generateTailoredResume() { |
|
|
|
|
|
generateResume.disabled = true; |
|
|
generateResume.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Processing...'; |
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const resumePoints = document.querySelectorAll('.resume-point'); |
|
|
resumePoints.forEach(point => { |
|
|
extractedKeywords.forEach(keyword => { |
|
|
if (point.textContent.toLowerCase().includes(keyword)) { |
|
|
point.classList.add('highlight'); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
const skillsSection = resumePreview.querySelector('.flex.flex-wrap.gap-2'); |
|
|
if (skillsSection) { |
|
|
const additionalSkills = ['TypeScript', 'AWS', 'Docker', 'CI/CD']; |
|
|
additionalSkills.forEach(skill => { |
|
|
const skillSpan = document.createElement('span'); |
|
|
skillSpan.className = 'px-3 py-1 bg-blue-100 text-blue-800 rounded-full text-sm'; |
|
|
skillSpan.textContent = skill; |
|
|
skillsSection.appendChild(skillSpan); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
const summary = resumePreview.querySelector('p.text-gray-700'); |
|
|
if (summary) { |
|
|
summary.textContent = "Experienced software engineer with 7+ years in web development. Skilled in JavaScript, React, Node.js and cloud technologies. Strong expertise in agile methodologies and building scalable web applications. Passionate about mentoring junior developers and implementing CI/CD pipelines."; |
|
|
} |
|
|
|
|
|
|
|
|
const successDiv = document.createElement('div'); |
|
|
successDiv.className = 'mt-4 p-4 bg-green-50 text-green-800 rounded-lg fade-in'; |
|
|
successDiv.innerHTML = ` |
|
|
<div class="flex items-center"> |
|
|
<i class="fas fa-check-circle mr-2"></i> |
|
|
<span>Your resume has been successfully tailored to match the job description!</span> |
|
|
</div> |
|
|
`; |
|
|
resumePreview.appendChild(successDiv); |
|
|
|
|
|
|
|
|
nextStep3.classList.remove('hidden'); |
|
|
generateResume.disabled = false; |
|
|
generateResume.innerHTML = 'Generate Tailored Resume <i class="fas fa-magic ml-2"></i>'; |
|
|
|
|
|
|
|
|
tailoredResumeHTML = resumePreview.innerHTML; |
|
|
}, 2000); |
|
|
} |
|
|
|
|
|
function downloadTailoredResume() { |
|
|
|
|
|
|
|
|
|
|
|
const format = document.querySelector('input[name="outputFormat"]:checked').value; |
|
|
|
|
|
|
|
|
const link = document.createElement('a'); |
|
|
link.href = format === 'pdf' ? |
|
|
'data:application/pdf;base64,JVBERi0xLjUK...' : |
|
|
'data:application/vnd.openxmlformats-officedocument.wordprocessingml.document;base64,UEsDBBQ...'; |
|
|
|
|
|
link.download = `Tailored_Resume_${jobTitle.value || 'Job'}.${format}`; |
|
|
document.body.appendChild(link); |
|
|
link.click(); |
|
|
document.body.removeChild(link); |
|
|
|
|
|
|
|
|
const downloadDiv = document.createElement('div'); |
|
|
downloadDiv.className = 'mt-4 p-4 bg-blue-50 text-blue-800 rounded-lg fade-in'; |
|
|
downloadDiv.innerHTML = ` |
|
|
<div class="flex items-center"> |
|
|
<i class="fas fa-check-circle mr-2"></i> |
|
|
<span>Your ${format.toUpperCase()} file has been downloaded!</span> |
|
|
</div> |
|
|
`; |
|
|
document.querySelector('#step4 .text-center').insertBefore(downloadDiv, document.querySelector('#step4 .flex.flex-col')); |
|
|
} |
|
|
|
|
|
function showChangesSummary() { |
|
|
|
|
|
|
|
|
|
|
|
const modalHTML = ` |
|
|
<div class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4"> |
|
|
<div class="bg-white rounded-lg shadow-xl max-w-2xl w-full max-h-[90vh] overflow-auto"> |
|
|
<div class="p-6"> |
|
|
<div class="flex justify-between items-center mb-4"> |
|
|
<h3 class="text-xl font-semibold text-gray-800">Resume Changes Summary</h3> |
|
|
<button id="closeModal" class="text-gray-500 hover:text-gray-700"> |
|
|
<i class="fas fa-times"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
<div class="space-y-4"> |
|
|
<div class="border-b border-gray-200 pb-4"> |
|
|
<h4 class="font-medium text-gray-800 mb-2">Added Keywords</h4> |
|
|
<div class="flex flex-wrap gap-2"> |
|
|
<span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">TypeScript</span> |
|
|
<span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">AWS</span> |
|
|
<span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">Docker</span> |
|
|
<span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">CI/CD</span> |
|
|
<span class="px-3 py-1 bg-green-100 text-green-800 rounded-full text-sm">Agile</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="border-b border-gray-200 pb-4"> |
|
|
<h4 class="font-medium text-gray-800 mb-2">Modified Sections</h4> |
|
|
<ul class="space-y-3"> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-pen text-blue-500 mt-1 mr-2"></i> |
|
|
<div> |
|
|
<span class="font-medium">Professional Summary</span> |
|
|
<p class="text-sm text-gray-600">Added cloud technologies and agile methodologies</p> |
|
|
</div> |
|
|
</li> |
|
|
<li class="flex items-start"> |
|
|
<i class="fas fa-pen text-blue-500 mt-1 mr-2"></i> |
|
|
<div> |
|
|
<span class="font-medium">Technical Skills</span> |
|
|
<p class="text-sm text-gray-600">Added 4 new relevant skills</p> |
|
|
</div> |
|
|
</li> |
|
|
</ul> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h4 class="font-medium text-gray-800 mb-2">Optimization Score</h4> |
|
|
<div class="flex items-center"> |
|
|
<div class="w-full bg-gray-200 rounded-full h-4 mr-3"> |
|
|
<div class="bg-green-600 h-4 rounded-full" style="width: 78%"></div> |
|
|
</div> |
|
|
<span class="font-bold text-green-700">78%</span> |
|
|
</div> |
|
|
<p class="text-sm text-gray-600 mt-2">Your resume now matches 78% of the job description keywords (up from 32%).</p> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="mt-6 flex justify-end"> |
|
|
<button id="closeModalBtn" class="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition"> |
|
|
Close |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
const modal = document.createElement('div'); |
|
|
modal.innerHTML = modalHTML; |
|
|
document.body.appendChild(modal); |
|
|
|
|
|
const closeModal = document.getElementById('closeModal'); |
|
|
const closeModalBtn = document.getElementById('closeModalBtn'); |
|
|
|
|
|
closeModal.addEventListener('click', () => modal.remove()); |
|
|
closeModalBtn.addEventListener('click', () => modal.remove()); |
|
|
} |
|
|
|
|
|
function resetApplication() { |
|
|
|
|
|
resetFileUpload(); |
|
|
jobTitle.value = ''; |
|
|
jobDescription.value = ''; |
|
|
keywordsContainer.innerHTML = ''; |
|
|
matchScoreBar.style.width = '0%'; |
|
|
matchScoreText.textContent = '0%'; |
|
|
resumePreview.innerHTML = ` |
|
|
<div class="text-center py-12 text-gray-500"> |
|
|
<i class="fas fa-file-alt text-4xl mb-4"></i> |
|
|
<p>Your tailored resume will appear here</p> |
|
|
</div> |
|
|
`; |
|
|
suggestionsContainer.innerHTML = ` |
|
|
<div class="text-center py-8 text-gray-500"> |
|
|
<i class="fas fa-lightbulb text-2xl mb-3"></i> |
|
|
<p>AI-powered suggestions will appear here</p> |
|
|
</div> |
|
|
`; |
|
|
|
|
|
|
|
|
step4.classList.add('hidden'); |
|
|
step1.classList.remove('hidden'); |
|
|
updateStepProgress(1); |
|
|
nextStep2.disabled = true; |
|
|
nextStep3.classList.add('hidden'); |
|
|
} |
|
|
</script> |
|
|
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=illumnati/test" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
|
|
</html> |