modeser/modeser-ai-seo-content-wizardry
0
1// Shared JavaScript across all pages2 3// API Configuration4const API_BASE_URL = 'https://api.modeser.ai/v1';5 6// Utility Functions7class ModeserUtils {8 static formatDate(date) {9 return new Date(date).toLocaleDateString('en-US', {10 year: 'numeric',11 month: 'long',12 day: 'numeric'13 });14 }15 16 static truncateText(text, maxLength = 100) {17 if (text.length <= maxLength) return text;18 return text.substring(0, maxLength) + '...';19 }20 21 static debounce(func, wait) {22 let timeout;23 return function executedFunction(...args) {24 const later = () => {25 clearTimeout(timeout);26 func(...args);27 };28 clearTimeout(timeout);29 timeout = setTimeout(later, wait);30 };31 }32 33 static async fetchWithAuth(endpoint, options = {}) {34 const token = localStorage.getItem('modeser_token');35 const headers = {36 'Content-Type': 'application/json',37 ...options.headers38 };39 40 if (token) {41 headers['Authorization'] = `Bearer ${token}`;42 }43 44 const response = await fetch(`${API_BASE_URL}${endpoint}`, {45 ...options,46 headers47 });48 49 if (!response.ok) {50 throw new Error(`API Error: ${response.status}`);51 }52 53 return response.json();54 }55}56 57// Theme Management58class ThemeManager {59 constructor() {60 this.currentTheme = localStorage.getItem('modeser_theme') || 'light';61 this.init();62 }63 64 init() {65 this.applyTheme(this.currentTheme);66 this.setupEventListeners();67 }68 69 applyTheme(theme) {70 document.documentElement.setAttribute('data-theme', theme);71 localStorage.setItem('modeser_theme', theme);72 }73 74 toggleTheme() {75 this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';76 this.applyTheme(this.currentTheme);77 }78 79 setupEventListeners() {80 // Theme toggle will be handled by components81 }82}83 84// Notification System85class NotificationSystem {86 static show(message, type = 'info', duration = 5000) {87 const notification = document.createElement('div');88 notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 transform transition-all duration-300 ${89 type === 'success' ? 'bg-green-500 text-white' :90 type === 'error' ? 'bg-red-500 text-white' :91 type === 'warning' ? 'bg-yellow-500 text-white' :92 'bg-blue-500 text-white'93 }`;94 95 notification.innerHTML = `96 <div class="flex items-center">97 <i data-feather="${98 type === 'success' ? 'check-circle' :99 type === 'error' ? 'alert-circle' :100 type === 'warning' ? 'alert-triangle' :101 'info'102 }" class="w-5 h-5 mr-2"></i>103 <span>${message}</span>104 </div>105 `;106 107 document.body.appendChild(notification);108 109 // Animate in110 setTimeout(() => {111 notification.classList.add('translate-x-0', 'opacity-100');112 notification.classList.remove('translate-x-full', 'opacity-0');113 }, 100);114 115 // Remove after duration116 setTimeout(() => {117 notification.classList.add('translate-x-full', 'opacity-0');118 setTimeout(() => {119 if (notification.parentNode) {120 notification.parentNode.removeChild(notification);121 }122 }, 300);123 }, duration);124 125 feather.replace();126 }127}128 129// SEO Score Calculator130class SEOScoreCalculator {131 static calculateScore(content) {132 let score = 100;133 134 // Keyword density check135 const keywordDensity = this.calculateKeywordDensity(content);136 if (keywordDensity < 1 || keywordDensity > 3) {137 score -= 10;138 }139 140 // Content length check141 if (content.length < 300) {142 score -= 20;143 } else if (content.length > 2000) {144 score += 5;145 }146 147 // Readability check (simplified)148 const readability = this.calculateReadability(content);149 if (readability < 60) {150 score -= 15;151 }152 153 return Math.max(0, Math.min(100, score));154 }155 156 static calculateKeywordDensity(content) {157 // Simplified keyword density calculation158 const words = content.toLowerCase().split(/\s+/);159 const totalWords = words.length;160 const keywordCount = words.filter(word => 161 ['seo', 'content', 'ai', 'optimization', 'search'].includes(word)162 ).length;163 164 return (keywordCount / totalWords) * 100;165 }166 167 static calculateReadability(content) {168 // Simplified readability score169 const words = content.split(/\s+/);170 const sentences = content.split(/[.!?]+/);171 172 const avgWordsPerSentence = words.length / sentences.length;173 const avgSyllablesPerWord = this.estimateSyllables(content);174 175 return Math.max(0, 100 - (avgWordsPerSentence + avgSyllablesPerWord));176 }177 178 static estimateSyllables(text) {179 // Very simplified syllable estimation180 return text.length / 5;181 }182}183 184// Content Generator185class ContentGenerator {186 static async generateArticle(topic, keywords, tone = 'professional') {187 try {188 const response = await ModeserUtils.fetchWithAuth('/articles/generate', {189 method: 'POST',190 body: JSON.stringify({191 topic,192 keywords,193 tone,194 length: 'medium'195 })196 });197 198 return response;199 } catch (error) {200 console.error('Content generation failed:', error);201 NotificationSystem.show('Failed to generate content. Please try again.', 'error');202 throw error;203 }204 }205}206 207// Initialize app when DOM is loaded208document.addEventListener('DOMContentLoaded', function() {209 console.log('Modeser AI App loaded');210 211 // Initialize theme manager212 window.themeManager = new ThemeManager();213 214 // Check authentication status215 const token = localStorage.getItem('modeser_token');216 if (token) {217 document.body.setAttribute('data-authenticated', 'true');218 }219});