Online Smart Proposal & Presentation Template Manager

Online Smart Proposal & Presentation Template Manager

Select a Template

Modern Template

Modern Corporate

Creative Template

Creative Agency

Minimalist Template

Minimalist

Tech Startup Template

Tech Startup

Live Preview

Edit Proposal Content

Configure Proposal Data

Client Information

Your Information

Pricing ($)

Final Review

${proposalData.yourName}

${proposalData.myCompanyName}

`; // Render for UI previews document.getElementById('live-preview-dashboard').innerHTML = contentHtml; document.getElementById('final-preview').innerHTML = contentHtml; // Render for PDF document.getElementById('pdf-render-area').innerHTML = contentHtml.replace(/class="/g, 'style="'); // Basic class to style conversion }; // --- Template Selection --- templateCards.forEach(card => { card.addEventListener('click', () => { templateCards.forEach(c => c.classList.remove('selected')); card.classList.add('selected'); proposalData.selectedTemplate = card.dataset.template; // In a real app, this would change the CSS/layout. Here we just store it. renderAllPreviews(); }); }); // --- AI Content Generation --- aiButtons.forEach(button => { button.addEventListener('click', async () => { const targetId = button.dataset.target; const promptTemplate = button.dataset.prompt; const targetTextarea = document.getElementById(targetId); if (!targetTextarea) return; const prompt = promptTemplate .replace('[Project Name]', proposalData.projectName || 'this project') .replace('[My Company Name]', proposalData.myCompanyName || 'our company') .replace('[Your Industry]', proposalData.yourIndustry || 'our industry'); button.textContent = 'Generating...'; button.disabled = true; try { let chatHistory = [{ role: "user", parts: [{ text: prompt }] }]; const payload = { contents: chatHistory }; const apiKey = ""; const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`API Error: ${response.status}`); const result = await response.json(); const text = result.candidates[0].content.parts[0].text; targetTextarea.value = text.trim(); // Manually trigger input event to update data and previews targetTextarea.dispatchEvent(new Event('input', { bubbles: true })); } catch (error) { console.error('AI Generation Error:', error); targetTextarea.value = 'Error generating content. Please try again.'; } finally { button.textContent = 'Generate with AI'; button.disabled = false; } }); }); // --- PDF Download --- downloadPdfBtn.addEventListener('click', () => { const { jsPDF } = window.jspdf; const pdfElement = document.getElementById('pdf-render-area'); html2canvas(pdfElement, { scale: 2, useCORS: true }).then(canvas => { const imgData = canvas.toDataURL('image/png'); const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pdfWidth = pdf.internal.pageSize.getWidth(); const pageHeight = pdf.internal.pageSize.getHeight(); const imgHeight = canvas.height * pdfWidth / canvas.width; let heightLeft = imgHeight; let position = 0; pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight); heightLeft -= pageHeight; while (heightLeft >= 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, 'PNG', 0, position, pdfWidth, imgHeight); heightLeft -= pageHeight; } pdf.save(`${proposalData.projectName || 'Proposal'}.pdf`); }); }); // --- Initial Load --- bindData(); updateUI(); });
Scroll to Top