Advocacy Campaign Message Frame Builder

Advocacy Campaign Message Frame Builder

State the problem clearly and concisely. What is wrong?

Who does this problem hurt, and how? Be specific.

What is your specific, actionable solution?

What are the positive outcomes of your solution?

Who are you trying to persuade? (e.g., City Council members, suburban voters, local business owners)

What shared values can you appeal to? (e.g., fairness, economic opportunity, community, family)

What specific, immediate action do you want your audience to take?

Who are the most credible people to deliver this message to your target audience?

Review your complete message frame below. Go back to any tab to make edits.

Click "Generate/Refresh Summary" to see your plan here.

${escapeHTML(data.messenger)}

`; }; const downloadPDF = () => { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const data = getPlanData(); const margin = 20; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - (margin * 2); let yPos = 25; // Start position (with 5mm top padding) // Helper function to add text with word-wrap const addWrappedText = (title, text, isTitle) => { if (yPos > 260) { // Check for page break doc.addPage(); yPos = 20; } if (isTitle) { doc.setFontSize(14); doc.setFont(undefined, 'bold'); doc.setTextColor(44, 62, 80); // Dark blue doc.text(title, margin, yPos); yPos += 8; } else { doc.setFontSize(11); doc.setFont(undefined, 'normal'); doc.setTextColor(52, 73, 94); // Dark gray const splitText = doc.splitTextToSize(text, usableWidth); doc.text(splitText, margin, yPos); yPos += (splitText.length * 5) + 5; // 5mm per line + 5mm buffer } }; // --- Build PDF Document --- doc.setFontSize(20); doc.setFont(undefined, 'bold'); doc.setTextColor(0, 123, 255); // Blue doc.text("Advocacy Message Frame", pageWidth / 2, 15, { align: 'center' }); addWrappedText("1. The Problem", "", true); addWrappedText(data.problem, "", false); addWrappedText("1. The Impact", "", true); addWrappedText(data.impact, "", false); addWrappedText("2. The Solution", "", true); addWrappedText(data.solution, "", false); addWrappedText("2. The Benefits", "", true); addWrappedText(data.benefits, "", false); addWrappedText("3. Target Audience", "", true); addWrappedText(data.audience, "", false); addWrappedText("3. Core Values", "", true); addWrappedText(data.values, "", false); addWrappedText("4. The Call to Action", "", true); addWrappedText(data.cta, "", false); addWrappedText("4. The Messenger(s)", "", true); Signature addWrappedText(data.messenger, "", false); doc.save('advocacy-message-frame.pdf'); }; // --- Utility --- const escapeHTML = (str) => { if (typeof str !== 'string') return ''; return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); }; // --- Event Listeners --- // Tab Buttons tabButtons.forEach((btn, index) => { btn.addEventListener('click', () => showTab(index + 1)); }); // Next/Prev Navigation nextBtn.addEventListener('click', () => showTab(currentTab + 1)); prevBtn.addEventListener('click', () => showTab(currentTab - 1)); // Tab 5 Actions generateSummaryBtn.addEventListener('click', generateSummary); downloadPdfBtn.addEventListener('click', downloadPDF); // --- Initialization --- showTab(1); // Set initial state });
Scroll to Top