-
Notifications
You must be signed in to change notification settings - Fork 83
Open
Description
<title>SEO Pro - Complete SEO Analysis Suite</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.9.1/chart.min.js"></script>
<style>
* { font-family: 'Inter', sans-serif; }
.gradient-bg {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.glass-panel {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
.metric-card {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.metric-card:hover {
transform: translateY(-4px);
box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.15);
}
.score-ring {
transition: stroke-dashoffset 1s ease-in-out;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.pulse-animation {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .5; }
}
.slide-in {
animation: slideIn 0.5s ease-out forwards;
}
@keyframes slideIn {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
.tab-active {
border-bottom: 3px solid #667eea;
color: #667eea;
font-weight: 600;
}
.progress-bar {
transition: width 1s ease-out;
}
.keyword-tag {
transition: all 0.2s;
}
.keyword-tag:hover {
transform: scale(1.05);
}
.suggestion-item {
transition: all 0.3s;
}
.suggestion-item:hover {
background: #f3f4f6;
padding-left: 1.5rem;
}
.dark .glass-panel {
background: rgba(30, 41, 59, 0.95);
border: 1px solid rgba(255, 255, 255, 0.1);
}
</style>
SEO Pro
Dashboard
Site Analyzer
Keywords
Content Optimizer
<!-- Main Content -->
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<!-- Dashboard View -->
<div id="dashboard-view" class="space-y-6">
<!-- Welcome Header -->
<div class="glass-panel rounded-2xl p-8 shadow-sm slide-in">
<h1 class="text-3xl font-bold text-gray-800 mb-2">SEO Dashboard</h1>
<p class="text-gray-600">Track your website's performance and optimization metrics in real-time.</p>
</div>
<!-- Quick Stats -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
<div class="metric-card glass-panel rounded-xl p-6 shadow-sm bg-white">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Overall Score</p>
<p class="text-3xl font-bold text-gray-900 mt-1" id="overall-score">87</p>
</div>
<div class="w-12 h-12 rounded-full bg-green-100 flex items-center justify-center">
<span class="text-green-600 font-bold">A</span>
</div>
</div>
<div class="mt-4 flex items-center text-sm text-green-600">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
</svg>
<span>+5% from last week</span>
</div>
</div>
<div class="metric-card glass-panel rounded-xl p-6 shadow-sm bg-white">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Indexed Pages</p>
<p class="text-3xl font-bold text-gray-900 mt-1">1,247</p>
</div>
<div class="w-12 h-12 rounded-full bg-blue-100 flex items-center justify-center">
<svg class="w-6 h-6 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</div>
</div>
<div class="mt-4 flex items-center text-sm text-blue-600">
<span>42 new this month</span>
</div>
</div>
<div class="metric-card glass-panel rounded-xl p-6 shadow-sm bg-white">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Backlinks</p>
<p class="text-3xl font-bold text-gray-900 mt-1">3,856</p>
</div>
<div class="w-12 h-12 rounded-full bg-purple-100 flex items-center justify-center">
<svg class="w-6 h-6 text-purple-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"></path>
</svg>
</div>
</div>
<div class="mt-4 flex items-center text-sm text-green-600">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
</svg>
<span>+128 this week</span>
</div>
</div>
<div class="metric-card glass-panel rounded-xl p-6 shadow-sm bg-white">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-medium text-gray-600">Avg. Position</p>
<p class="text-3xl font-bold text-gray-900 mt-1">12.4</p>
</div>
<div class="w-12 h-12 rounded-full bg-orange-100 flex items-center justify-center">
<svg class="w-6 h-6 text-orange-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4"></path>
</svg>
</div>
</div>
<div class="mt-4 flex items-center text-sm text-green-600">
<svg class="w-4 h-4 mr-1" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"></path>
</svg>
<span>Improved by 3.2</span>
</div>
</div>
</div>
<!-- Charts Section -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div class="glass-panel rounded-xl p-6 shadow-sm bg-white">
<h3 class="text-lg font-semibold text-gray-800 mb-4">Traffic Overview</h3>
<canvas id="trafficChart" height="250"></canvas>
</div>
<div class="glass-panel rounded-xl p-6 shadow-sm bg-white">
<h3 class="text-lg font-semibold text-gray-800 mb-4">Keyword Rankings</h3>
<canvas id="keywordChart" height="250"></canvas>
</div>
</div>
</div>
<!-- Site Analyzer View -->
<div id="analyzer-view" class="hidden space-y-6">
<div class="glass-panel rounded-2xl p-8 shadow-sm">
<h2 class="text-2xl font-bold text-gray-800 mb-6">Website SEO Analyzer</h2>
<!-- URL Input -->
<div class="flex gap-4 mb-8">
<input type="url" id="analyze-url" placeholder="Enter website URL (e.g., https://example.com)"
class="flex-1 px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 focus:border-transparent outline-none transition">
<button onclick="analyzeSite()"
class="px-8 py-3 gradient-bg text-white rounded-lg font-semibold hover:opacity-90 transition flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
</svg>
Analyze
</button>
</div>
<!-- Analysis Results -->
<div id="analysis-results" class="hidden space-y-6">
<!-- Score Circle -->
<div class="flex justify-center mb-8">
<div class="relative w-48 h-48">
<svg class="w-full h-full transform -rotate-90">
<circle cx="96" cy="96" r="88" stroke="#e5e7eb" stroke-width="12" fill="none"></circle>
<circle id="score-circle" cx="96" cy="96" r="88" stroke="url(#gradient)" stroke-width="12" fill="none"
stroke-dasharray="553" stroke-dashoffset="553" stroke-linecap="round" class="score-ring"></circle>
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#667eea"></stop>
<stop offset="100%" stop-color="#764ba2"></stop>
</linearGradient>
</defs>
</svg>
<div class="absolute inset-0 flex flex-col items-center justify-center">
<span id="analysis-score" class="text-5xl font-bold text-gray-800">0</span>
<span class="text-sm text-gray-500 mt-1">SEO Score</span>
</div>
</div>
</div>
<!-- Detailed Metrics -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- On-Page SEO -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-800 mb-4 flex items-center gap-2">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"></path>
</svg>
On-Page SEO
</h3>
<div class="space-y-3" id="onpage-metrics">
<!-- Dynamic content -->
</div>
</div>
<!-- Technical SEO -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-800 mb-4 flex items-center gap-2">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
Technical SEO
</h3>
<div class="space-y-3" id="technical-metrics">
<!-- Dynamic content -->
</div>
</div>
<!-- Performance -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-800 mb-4 flex items-center gap-2">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
</svg>
Performance
</h3>
<div class="space-y-3" id="performance-metrics">
<!-- Dynamic content -->
</div>
</div>
<!-- Security -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-800 mb-4 flex items-center gap-2">
<svg class="w-5 h-5 text-indigo-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
</svg>
Security & SSL
</h3>
<div class="space-y-3" id="security-metrics">
<!-- Dynamic content -->
</div>
</div>
</div>
<!-- Recommendations -->
<div class="bg-indigo-50 rounded-xl p-6 mt-6">
<h3 class="font-semibold text-indigo-900 mb-4">Recommendations</h3>
<ul id="recommendations-list" class="space-y-2">
<!-- Dynamic content -->
</ul>
</div>
</div>
</div>
</div>
<!-- Keywords View -->
<div id="keywords-view" class="hidden space-y-6">
<div class="glass-panel rounded-2xl p-8 shadow-sm">
<div class="flex justify-between items-center mb-6">
<h2 class="text-2xl font-bold text-gray-800">Keyword Research & Tracking</h2>
<button onclick="addKeyword()" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition flex items-center gap-2">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
</svg>
Add Keyword
</button>
</div>
<!-- Keyword Input -->
<div class="flex gap-4 mb-6">
<input type="text" id="keyword-input" placeholder="Enter keyword to research..."
class="flex-1 px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 outline-none">
<button onclick="researchKeyword()" class="px-6 py-3 gradient-bg text-white rounded-lg hover:opacity-90 transition">
Research
</button>
</div>
<!-- Keyword Stats -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-blue-50 rounded-lg p-4">
<p class="text-sm text-blue-600 font-medium">Total Keywords</p>
<p class="text-2xl font-bold text-blue-900" id="total-keywords">24</p>
</div>
<div class="bg-green-50 rounded-lg p-4">
<p class="text-sm text-green-600 font-medium">Top 10 Rankings</p>
<p class="text-2xl font-bold text-green-900" id="top-rankings">8</p>
</div>
<div class="bg-purple-50 rounded-lg p-4">
<p class="text-sm text-purple-600 font-medium">Avg. Monthly Volume</p>
<p class="text-2xl font-bold text-purple-900" id="avg-volume">12.5K</p>
</div>
</div>
<!-- Keywords Table -->
<div class="overflow-x-auto">
<table class="w-full text-left">
<thead class="bg-gray-50">
<tr>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Keyword</th>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Position</th>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Volume</th>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Difficulty</th>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Trend</th>
<th class="px-4 py-3 text-sm font-semibold text-gray-600">Actions</th>
</tr>
</thead>
<tbody id="keywords-table" class="divide-y divide-gray-200">
<!-- Dynamic rows -->
</tbody>
</table>
</div>
</div>
</div>
<!-- Content Optimizer View -->
<div id="content-view" class="hidden space-y-6">
<div class="glass-panel rounded-2xl p-8 shadow-sm">
<h2 class="text-2xl font-bold text-gray-800 mb-6">Content Optimizer</h2>
<!-- Content Input -->
<div class="mb-6">
<label class="block text-sm font-medium text-gray-700 mb-2">Target Keyword</label>
<input type="text" id="target-keyword" placeholder="Enter your target keyword..."
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 outline-none mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Your Content</label>
<textarea id="content-text" rows="8" placeholder="Paste your content here to analyze..."
class="w-full px-4 py-3 rounded-lg border border-gray-300 focus:ring-2 focus:ring-indigo-500 outline-none resize-none"></textarea>
</div>
<button onclick="optimizeContent()" class="w-full py-3 gradient-bg text-white rounded-lg font-semibold hover:opacity-90 transition mb-6">
Analyze Content
</button>
<!-- Content Analysis Results -->
<div id="content-results" class="hidden space-y-6">
<!-- Readability Score -->
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="bg-white border rounded-xl p-4 text-center">
<div class="text-3xl font-bold text-indigo-600 mb-1" id="readability-score">72</div>
<div class="text-sm text-gray-600">Readability Score</div>
<div class="text-xs text-gray-500 mt-1">Good</div>
</div>
<div class="bg-white border rounded-xl p-4 text-center">
<div class="text-3xl font-bold text-green-600 mb-1" id="word-count">1,247</div>
<div class="text-sm text-gray-600">Word Count</div>
<div class="text-xs text-gray-500 mt-1">Optimal length</div>
</div>
<div class="bg-white border rounded-xl p-4 text-center">
<div class="text-3xl font-bold text-blue-600 mb-1" id="keyword-density">1.8%</div>
<div class="text-sm text-gray-600">Keyword Density</div>
<div class="text-xs text-gray-500 mt-1">Perfect</div>
</div>
</div>
<!-- SEO Suggestions -->
<div class="bg-gray-50 rounded-xl p-6">
<h3 class="font-semibold text-gray-800 mb-4">Optimization Suggestions</h3>
<div id="seo-suggestions" class="space-y-3">
<!-- Dynamic suggestions -->
</div>
</div>
<!-- Related Keywords -->
<div class="bg-indigo-50 rounded-xl p-6">
<h3 class="font-semibold text-indigo-900 mb-4">Suggested Related Keywords</h3>
<div id="related-keywords" class="flex flex-wrap gap-2">
<!-- Dynamic tags -->
</div>
</div>
</div>
</div>
</div>
</main>
<script>
// Initialize Charts
function initCharts() {
const trafficCtx = document.getElementById('trafficChart').getContext('2d');
new Chart(trafficCtx, {
type: 'line',
data: {
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
datasets: [{
label: 'Organic Traffic',
data: [12000, 19000, 15000, 25000, 22000, 30000],
borderColor: '#667eea',
backgroundColor: 'rgba(102, 126, 234, 0.1)',
tension: 0.4,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, grid: { display: false } },
x: { grid: { display: false } }
}
}
});
const keywordCtx = document.getElementById('keywordChart').getContext('2d');
new Chart(keywordCtx, {
type: 'bar',
data: {
labels: ['Top 3', 'Top 10', 'Top 20', 'Top 50', 'Top 100'],
datasets: [{
label: 'Keywords',
data: [12, 28, 45, 67, 89],
backgroundColor: ['#10b981', '#34d399', '#6ee7b7', '#a7f3d0', '#d1fae5'],
borderRadius: 6
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true, grid: { display: false } },
x: { grid: { display: false } }
}
}
});
}
// Tab Switching
function switchTab(tab) {
// Hide all views
document.getElementById('dashboard-view').classList.add('hidden');
document.getElementById('analyzer-view').classList.add('hidden');
document.getElementById('keywords-view').classList.add('hidden');
document.getElementById('content-view').classList.add('hidden');
// Show selected view
document.getElementById(tab + '-view').classList.remove('hidden');
// Update nav styles
document.querySelectorAll('nav button').forEach(btn => {
btn.classList.remove('text-white', 'font-semibold');
btn.classList.add('text-gray-200');
});
event.target.classList.remove('text-gray-200');
event.target.classList.add('text-white', 'font-semibold');
}
// Site Analyzer
function analyzeSite() {
const url = document.getElementById('analyze-url').value;
if (!url) {
alert('Please enter a URL');
return;
}
const btn = event.target;
btn.innerHTML = '<span class="pulse-animation">Analyzing...</span>';
btn.disabled = true;
setTimeout(() => {
btn.innerHTML = `<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg> Analyze`;
btn.disabled = false;
document.getElementById('analysis-results').classList.remove('hidden');
// Animate score
const score = Math.floor(Math.random() * (95 - 60) + 60);
animateScore(score);
// Populate metrics
populateMetrics();
}, 2000);
}
function animateScore(targetScore) {
const circle = document.getElementById('score-circle');
const scoreText = document.getElementById('analysis-score');
const circumference = 2 * Math.PI * 88;
const offset = circumference - (targetScore / 100) * circumference;
circle.style.strokeDashoffset = offset;
let current = 0;
const timer = setInterval(() => {
if (current >= targetScore) clearInterval(timer);
scoreText.textContent = current;
current++;
}, 20);
}
function populateMetrics() {
const onPageMetrics = [
{ name: 'Title Tag', status: 'good', value: 'Optimal length (58 chars)' },
{ name: 'Meta Description', status: 'warning', value: 'Too short (120 chars)' },
{ name: 'H1 Tags', status: 'good', value: '1 found - Perfect' },
{ name: 'Image Alt Text', status: 'error', value: '3 images missing alt' }
];
const technicalMetrics = [
{ name: 'XML Sitemap', status: 'good', value: 'Found & Valid' },
{ name: 'Robots.txt', status: 'good', value: 'Found' },
{ name: 'Schema Markup', status: 'warning', value: 'Partial implementation' },
{ name: 'Canonical URLs', status: 'good', value: 'Properly set' }
];
const performanceMetrics = [
{ name: 'Page Speed', status: 'good', value: '1.2s load time' },
{ name: 'Mobile Friendly', status: 'good', value: 'Responsive' },
{ name: 'Core Web Vitals', status: 'warning', value: 'LCP needs improvement' },
{ name: 'Server Response', status: 'good', value: '200ms' }
];
const securityMetrics = [
{ name: 'SSL Certificate', status: 'good', value: 'Valid (HTTPS)' },
{ name: 'Security Headers', status: 'warning', value: 'Missing 2 headers' },
{ name: 'Mixed Content', status: 'good', value: 'None found' }
];
renderMetrics('onpage-metrics', onPageMetrics);
renderMetrics('technical-metrics', technicalMetrics);
renderMetrics('performance-metrics', performanceMetrics);
renderMetrics('security-metrics', securityMetrics);
// Recommendations
const recs = [
'Add alt text to 3 images for better accessibility',
'Extend meta description to 150-160 characters',
'Implement missing security headers (CSP, X-Frame-Options)',
'Optimize Largest Contentful Paint by compressing images'
];
const recList = document.getElementById('recommendations-list');
recList.innerHTML = recs.map(rec => `
<li class="flex items-start gap-2 text-gray-700 suggestion-item p-2 rounded cursor-pointer">
<svg class="w-5 h-5 text-indigo-600 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"></path>
</svg>
<span>${rec}</span>
</li>
`).join('');
}
function renderMetrics(containerId, metrics) {
const container = document.getElementById(containerId);
container.innerHTML = metrics.map(m => {
const colors = {
good: 'text-green-600 bg-green-100',
warning: 'text-yellow-600 bg-yellow-100',
error: 'text-red-600 bg-red-100'
};
const icons = {
good: '✓',
warning: '!',
error: '✕'
};
return `
<div class="flex items-center justify-between p-3 bg-white rounded-lg shadow-sm">
<div class="flex items-center gap-3">
<span class="w-6 h-6 rounded-full ${colors[m.status]} flex items-center justify-center text-xs font-bold">
${icons[m.status]}
</span>
<span class="font-medium text-gray-700">${m.name}</span>
</div>
<span class="text-sm text-gray-500">${m.value}</span>
</div>
`;
}).join('');
}
// Keywords functionality
const keywordsData = [
{ keyword: 'seo tools', position: 3, volume: '14,000', difficulty: 'Medium', trend: 'up' },
{ keyword: 'website analyzer', position: 5, volume: '8,100', difficulty: 'Low', trend: 'up' },
{ keyword: 'keyword research', position: 12, volume: '22,000', difficulty: 'High', trend: 'down' },
{ keyword: 'backlink checker', position: 8, volume: '6,600', difficulty: 'Medium', trend: 'stable' },
{ keyword: 'site audit', position: 4, volume: '4,400', difficulty: 'Low', trend: 'up' }
];
function renderKeywords() {
const tbody = document.getElementById('keywords-table');
tbody.innerHTML = keywordsData.map((k, i) => `
<tr class="hover:bg-gray-50 transition">
<td class="px-4 py-3 font-medium text-gray-900">${k.keyword}</td>
<td class="px-4 py-3">
<span class="px-2 py-1 rounded-full text-xs font-semibold ${k.position <= 3 ? 'bg-green-100 text-green-800' : k.position <= 10 ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'}">
#${k.position}
</span>
</td>
<td class="px-4 py-3 text-gray-600">${k.volume}</td>
<td class="px-4 py-3">
<span class="text-sm ${k.difficulty === 'High' ? 'text-red-600' : k.difficulty === 'Medium' ? 'text-yellow-600' : 'text-green-600'}">
${k.difficulty}
</span>
</td>
<td class="px-4 py-3">
${k.trend === 'up' ? '<span class="text-green-600">↑</span>' : k.trend === 'down' ? '<span class="text-red-600">↓</span>' : '<span class="text-gray-600">→</span>'}
</td>
<td class="px-4 py-3">
<button onclick="trackKeyword(${i})" class="text-indigo-600 hover:text-indigo-800 text-sm font-medium">Track</button>
</td>
</tr>
`).join('');
}
function researchKeyword() {
const keyword = document.getElementById('keyword-input').value;
if (!keyword) return;
// Add to table
keywordsData.unshift({
keyword: keyword,
position: Math.floor(Math.random() * 50) + 1,
volume: Math.floor(Math.random() * 50000).toLocaleString(),
difficulty: ['Low', 'Medium', 'High'][Math.floor(Math.random() * 3)],
trend: ['up', 'down', 'stable'][Math.floor(Math.random() * 3)]
});
renderKeywords();
document.getElementById('keyword-input').value = '';
}
function trackKeyword(index) {
alert(`Now tracking "${keywordsData[index].keyword}" with daily updates!`);
}
// Content Optimizer
function optimizeContent() {
const content = document.getElementById('content-text').value;
const keyword = document.getElementById('target-keyword').value;
if (!content || !keyword) {
alert('Please enter both content and target keyword');
return;
}
document.getElementById('content-results').classList.remove('hidden');
// Simulate analysis
const words = content.split(/\s+/).length;
const density = ((content.toLowerCase().match(new RegExp(keyword.toLowerCase(), 'g')) || []).length / words * 100).toFixed(1);
document.getElementById('word-count').textContent = words.toLocaleString();
document.getElementById('keyword-density').textContent = density + '%';
document.getElementById('readability-score').textContent = Math.floor(Math.random() * (90 - 60) + 60);
// Suggestions
const suggestions = [
{ type: 'good', text: 'Good use of headings structure' },
{ type: 'warning', text: 'Add more internal links (found 2, recommend 5+)' },
{ type: 'warning', text: 'Increase keyword density slightly (target: 2%)' },
{ type: 'error', text: 'Add target keyword to first 100 words' },
{ type: 'good', text: 'Content length is optimal for SEO' }
];
const suggContainer = document.getElementById('seo-suggestions');
suggContainer.innerHTML = suggestions.map(s => `
<div class="flex items-start gap-3 p-3 rounded-lg ${s.type === 'good' ? 'bg-green-50' : s.type === 'warning' ? 'bg-yellow-50' : 'bg-red-50'}">
<span class="mt-0.5 ${s.type === 'good' ? 'text-green-600' : s.type === 'warning' ? 'text-yellow-600' : 'text-red-600'}">
${s.type === 'good' ? '✓' : s.type === 'warning' ? '!' : '✕'}
</span>
<span class="text-sm ${s.type === 'good' ? 'text-green-800' : s.type === 'warning' ? 'text-yellow-800' : 'text-red-800'}">${s.text}</span>
</div>
`).join('');
// Related keywords
const related = ['seo optimization', 'search engine ranking', 'organic traffic', 'content strategy', 'keyword research', 'on-page seo'];
document.getElementById('related-keywords').innerHTML = related.map(k => `
<span class="keyword-tag px-3 py-1 bg-white border border-indigo-200 rounded-full text-sm text-indigo-700 cursor-pointer hover:bg-indigo-50 hover:border-indigo-300">
${k}
</span>
`).join('');
}
// Theme Toggle
function toggleTheme() {
document.documentElement.classList.toggle('dark');
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
initCharts();
renderKeywords();
});
</script>
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels