Email: ${email}
` : ''}
${linkedin ? `
LinkedIn: ${linkedin}
` : ''}
`;
// HTML structure for different layouts
let finalHtml = '';
const headerHtml = `
`;
switch (layout) {
case 'modern':
finalHtml = `
${headerHtml}
About Me
${about || "A brief description about you..."}
Projects
${projectsHtml}
`;
break;
case 'minimalist':
case 'classic':
default:
finalHtml = `
${headerHtml}
About Me
${about || "A brief description about you..."}
Skills
${skillsHtml}
Projects
${projectsHtml}
Contact
${contactHtml}
`;
break;
}
previewArea.innerHTML = finalHtml;
}
function renderProjectControls() {
controls.projectsList.innerHTML = portfolioData.projects.map((p, index) => `
`).join('');
}
// --- DATA UPDATE FUNCTIONS ---
function updateData() {
portfolioData.name = controls.name.value;
portfolioData.tagline = controls.tagline.value;
portfolioData.about = controls.about.value;
portfolioData.email = controls.email.value;
portfolioData.linkedin = controls.linkedin.value;
portfolioData.skills = controls.skills.value.split('\n').map(s => s.trim()).filter(Boolean);
renderPortfolio();
}
function handleProjectUpdate(e) {
const target = e.target;
if (target.matches('[data-field]')) {
const card = target.closest('.plg-project-card');
const id = parseInt(card.dataset.id);
const field = target.dataset.field;
const project = portfolioData.projects.find(p => p.id === id);
if (project) {
project[field] = target.value;
renderPortfolio();
}
}
}
function addProject() {
portfolioData.projects.push({
id: nextProjectId++,
title: '',
description: '',
link: ''
});
renderProjectControls();
}
function removeProject(e) {
if (e.target.dataset.action === 'remove-project') {
const card = e.target.closest('.plg-project-card');
const id = parseInt(card.dataset.id);
portfolioData.projects = portfolioData.projects.filter(p => p.id !== id);
renderProjectControls();
renderPortfolio();
}
}
// 7. USA-relevant sample data
function loadSampleData() {
nextProjectId = 0;
portfolioData = {
name: "John Doe",
tagline: "Creative UX/UI Designer & Frontend Developer",
about: "A passionate and detail-oriented designer with 5+ years of experience creating intuitive and user-friendly web applications. Proficient in bridging the gap between design and development to deliver seamless digital experiences.",
email: "john.doe@email.com",
linkedin: "https://linkedin.com/in/johndoe-sample",
skills: ["UX Research", "Figma & Sketch", "HTML & CSS", "JavaScript", "React.js", "Agile Methodologies"],
projects: [
{ id: nextProjectId++, title: "E-Commerce Platform Redesign", description: "Led the UX redesign for a major online retailer, resulting in a 20% increase in conversion rates.", link: "https://example.com/project1" },
{ id: nextProjectId++, title: "SaaS Dashboard UI Kit", description: "Designed and developed a comprehensive UI kit for a data analytics SaaS product, improving development speed and UI consistency.", link: "https://example.com/project2" }
]
};
// Update control panel inputs
controls.name.value = portfolioData.name;
controls.tagline.value = portfolioData.tagline;
controls.about.value = portfolioData.about;
controls.email.value = portfolioData.email;
controls.linkedin.value = portfolioData.linkedin;
controls.skills.value = portfolioData.skills.join('\n');
renderProjectControls();
renderPortfolio();
}
async function handleDownloadPDF() {
const originalBtnText = controls.pdfDownloadBtn.textContent;
controls.pdfDownloadBtn.textContent = "Generating...";
controls.pdfDownloadBtn.disabled = true;
try {
const { jsPDF } = window.jspdf;
container.classList.add("plg-pdf-export-mode");
const canvas = await html2canvas(previewArea, { scale: 2 });
container.classList.remove("plg-pdf-export-mode");
const imgData = canvas.toDataURL("image/png");
const pdf = new jsPDF({ orientation: "p", unit: "mm", format: "a4" });
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
const canvasWidth = canvas.width;
const canvasHeight = canvas.height;
const ratio = canvasWidth / canvasHeight;
const imgWidth = pdfWidth;
const imgHeight = imgWidth / ratio;
pdf.addImage(imgData, "PNG", 0, 0, imgWidth, imgHeight);
pdf.save(`${(portfolioData.name || "Portfolio").replace(/ /g, "_")}.pdf`);
} catch (error) {
console.error("PDF Generation Error:", error);
alert("An error occurred while creating the PDF.");
} finally {
controls.pdfDownloadBtn.textContent = originalBtnText;
controls.pdfDownloadBtn.disabled = false;
}
}
// --- Initial Setup & Event Listeners ---
Object.values(controls).forEach(el => {
if (el && (el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.tagName === 'SELECT')) {
el.addEventListener('input', updateData);
}
});
controls.layout.addEventListener('change', renderPortfolio);
controls.theme.addEventListener('change', renderPortfolio);
controls.addProjectBtn.addEventListener('click', addProject);
controls.projectsList.addEventListener('input', handleProjectUpdate);
controls.projectsList.addEventListener('click', removeProject);
controls.loadSampleBtn.addEventListener('click', loadSampleData);
controls.pdfDownloadBtn.addEventListener('click', handleDownloadPDF);
// Initial render on load
loadSampleData();
});