Content Gap Finder

Content Gap Finder

Discover content opportunities your competitors have that you don't.

Content Gap Analysis & Ideas

Your content gap analysis will appear here.
Go to the 'Data Configuration' tab to enter keyword lists.

Could not generate ideas. The AI service may be temporarily unavailable.

`; } finally { showLoadingState(false); } } function parseAndRenderGaps(text) { const pairs = text.split(/\n\s*\n/); // Split by one or more blank lines let html = ''; const structuredGaps = []; pairs.forEach(pair => { const keywordMatch = pair.match(/Keyword:\s*(.*)/); const ideaMatch = pair.match(/Idea:\s*(.*)/); if (keywordMatch && ideaMatch) { const keyword = keywordMatch[1].trim(); const idea = ideaMatch[1].trim(); structuredGaps.push({ keyword, idea }); html += `
${keyword}
${idea}
`; } }); return { structuredGaps, html }; } function renderGaps(text) { const { structuredGaps, html } = parseAndRenderGaps(text); lastGeneratedGaps = structuredGaps; previewPlaceholder.classList.add('hidden'); resultsPreview.innerHTML = html; } function showLoadingState(isLoading) { if (isLoading) { previewPlaceholder.classList.add('hidden'); resultsPreview.innerHTML = '
'; generateBtn.disabled = true; generateBtn.textContent = 'Analyzing...'; showFeedback('Finding gaps and generating ideas...', false, 0); } else { generateBtn.disabled = false; generateBtn.textContent = 'Find Gaps & Generate Ideas'; } } downloadPdfBtn.addEventListener('click', () => { if (!lastGeneratedGaps || lastGeneratedGaps.length === 0) { showFeedback('Please generate an analysis before downloading.', true, 3000); return; } showFeedback('Generating PDF...', false, 2000); try { const { jsPDF } = window.jspdf; const pdf = new jsPDF({ unit: 'pt', format: 'letter' }); const pageMargin = 72; const pageWidth = pdf.internal.pageSize.getWidth(); const textWidth = pageWidth - (pageMargin * 2); let cursorY = pageMargin; // Title pdf.setFont('Helvetica', 'bold'); pdf.setFontSize(20); pdf.text('Content Gap Analysis Report', pageWidth / 2, cursorY, { align: 'center' }); cursorY += 40; lastGeneratedGaps.forEach(gap => { const keywordHeight = pdf.splitTextToSize(gap.keyword, textWidth).length * 16 * 1.2; const ideaHeight = pdf.splitTextToSize(gap.idea, textWidth - 20).length * 12 * 1.2; const totalHeight = keywordHeight + ideaHeight + 20; if (cursorY + totalHeight > pdf.internal.pageSize.getHeight() - pageMargin) { pdf.addPage(); cursorY = pageMargin; } pdf.setFont('Helvetica', 'bold'); pdf.setFontSize(14); const keywordLines = pdf.splitTextToSize(gap.keyword, textWidth); pdf.text(keywordLines, pageMargin, cursorY); cursorY += keywordLines.length * 14 * 1.2 + 5; pdf.setFont('Helvetica', 'normal'); pdf.setFontSize(11); const ideaLines = pdf.splitTextToSize(gap.idea, textWidth - 20); pdf.text(ideaLines, pageMargin + 20, cursorY); cursorY += ideaLines.length * 11 * 1.2 + 25; // Add extra space between items }); pdf.save('content-gap-analysis.pdf'); } catch(err) { console.error("PDF Generation Error: ", err); showFeedback("Error generating PDF.", true, 3000); } }); let feedbackTimeout; function showFeedback(message, isError = false, duration = 3000) { clearTimeout(feedbackTimeout); feedbackMessage.innerHTML = message; feedbackMessage.style.color = isError ? '#ef4444' : '#4a5568'; if (duration !== 0) { // allow indefinite message feedbackTimeout = setTimeout(() => { feedbackMessage.innerHTML = ''; }, duration); } } });
Scroll to Top