// Telegram Mini-Game Development Research Page Interactivity class TelegramGameResearch { constructor() { this.sections = document.querySelectorAll('.research-section'); this.init(); } init() { this.initializeIntersectionObserver(); this.initializeCountUpAnimations(); this.initializeTooltips(); this.initializeCopyCodeBlocks(); this.initializeProgressTracker(); this.initializeKeywordHighlighter(); } initializeIntersectionObserver() { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; // Animate child elements with staggered delay const childElements = entry.target.querySelectorAll('.animate-child'); childElements.forEach((el, index) => { el.style.transitionDelay = `${index * 0.1}s`; el.classList.add('animated'); }); } }); }, { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }); this.sections.forEach(section => { section.style.opacity = '0'; section.style.transform = 'translateY(20px)'; section.style.transition = 'opacity 0.6s ease, transform 0.6s ease'; observer.observe(section); }); } initializeCountUpAnimations() { const stats = [ { element: '.stat-1', value: 15000000, suffix: '+' }, { element: '.stat-2', value: 800000000, suffix: '+' }, { element: '.stat-3', value: 94, suffix: '%' }, { element: '.stat-4', value: 2.3, suffix: 'B' } ]; stats.forEach(stat => { const element = document.querySelector(stat.element); if (!element) return; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { this.animateCountUp(element, stat.value, stat.suffix); observer.unobserve(element); } }); }); observer.observe(element); }); } animateCountUp(element, target, suffix) { const duration = 2000; const startTime = Date.now(); const startValue = 0; const animate = () => { const currentTime = Date.now(); const elapsed = currentTime - startTime; const progress = Math.min(elapsed / duration, 1); let currentValue; if (suffix === '%' || suffix === 'B') { currentValue = startValue + (target - startValue) * progress; element.textContent = currentValue.toFixed(suffix === 'B' ? 1 : 0) + suffix; } else { currentValue = Math.floor(startValue + (target - startValue) * progress); element.textContent = this.formatNumber(currentValue) + suffix; } if (progress < 1) { requestAnimationFrame(animate); } }; requestAnimationFrame(animate); } formatNumber(num) { if (num >= 1000000) { return (num / 1000000).toFixed(1) + 'M'; } else if (num >= 1000) { return (num / 1000).toFixed(1) + 'K'; } return num.toString(); } initializeTooltips() { // Initialize tooltips for technical terms const tooltips = document.querySelectorAll('[data-tooltip]'); tooltips.forEach(element => { const tooltipText = element.getAttribute('data-tooltip'); const tooltip = document.createElement('div'); tooltip.className = 'absolute hidden bg-gray-900 text-white px-3 py-2 rounded-lg text-sm z-50 whitespace-nowrap'; tooltip.textContent = tooltipText; // Position calculation const updatePosition = () => { const rect = element.getBoundingClientRect(); tooltip.style.left = `${rect.left + rect.width / 2 - tooltip.offsetWidth / 2}px`; tooltip.style.top = `${rect.top - tooltip.offsetHeight - 10}px`; }; element.addEventListener('mouseenter', () => { document.body.appendChild(tooltip); tooltip.classList.remove('hidden'); updatePosition(); }); element.addEventListener('mouseleave', () => { tooltip.remove(); }); }); } initializeCopyCodeBlocks() { const codeBlocks = document.querySelectorAll('.code-snippet pre'); codeBlocks.forEach(block => { const copyButton = document.createElement('button'); copyButton.className = 'absolute top-4 right-4 text-gray-400 hover:text-white transition-colors'; copyButton.innerHTML = ''; block.parentNode.style.position = 'relative'; block.parentNode.appendChild(copyButton); copyButton.addEventListener('click', async () => { const code = block.textContent; try { await navigator.clipboard.writeText(code); // Visual feedback const originalIcon = copyButton.innerHTML; copyButton.innerHTML = ''; setTimeout(() => { copyButton.innerHTML = originalIcon; feather.replace(); }, 2000); } catch (err) { console.error('Failed to copy code:', err); } }); }); } initializeProgressTracker() { const progressBar = document.createElement('div'); progressBar.className = 'fixed top-0 left-0 h-1 bg-gradient-to-r from-primary-500 to-secondary-500 z-50 transition-all duration-150'; progressBar.style.width = '0%'; document.body.appendChild(progressBar); window.addEventListener('scroll', () => { const windowHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight; const scrolled = (window.scrollY / windowHeight) * 100; progressBar.style.width = `${scrolled}%`; }); } initializeKeywordHighlighter() { // SEO-related keyword highlighting const keywords = [ 'Telegram Mini-Game', 'Bot API', 'Web App', 'HTML5 Games', 'JavaScript', 'Phaser', 'PixiJS', 'Monetization', 'Telegram Features', 'Gaming SEO', 'Real-time', 'Multiplayer' ]; const content = document.querySelector('.research-content'); if (!content) return; keywords.forEach(keyword => { const regex = new RegExp(`\\b(${keyword})\\b`, 'gi'); content.innerHTML = content.innerHTML.replace(regex, `$1` ); }); } // Utility function for API data fetching (example) async fetchTelegramStats() { try { // This would be a real API call in production // const response = await fetch('https://api.telegram.org/stats'); // return await response.json(); // Mock data for demonstration return { dailyUsers: 15000000, retentionRate: 94, revenuePotential: 2.3 }; } catch (error) { console.error('Failed to fetch Telegram stats:', error); return null; } } // Initialize search functionality initializeSearch() { const searchInput = document.createElement('input'); searchInput.type = 'text'; searchInput.placeholder = 'Search topics (e.g., API, Monetization, SEO)...'; searchInput.className = 'fixed top0 right-4 z-50 bg-white shadow-xl border-gray-300 rounded-lg px-4 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500'; document.body.appendChild(searchInput); searchInput.addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); this.sections.forEach(section => { const text = section.textContent.toLowerCase(); const isMatch = text.includes(searchTerm); section.style.opacity = isMatch ? '1' : '0.3'; section.style.pointerEvents = isMatch ? 'auto' : 'none'; }); }); } } // Initialize when DOM is loaded document.addEventListener('DOMContentLoaded', () => { const researchPage = new TelegramGameResearch(); // Initialize search if needed // researchPage.initializeSearch(); // Update stats from mock API researchPage.fetchTelegramStats().then(stats => { if (stats) { console.log('Telegram Gaming Stats:', stats); } }); // Add keyboard shortcuts document.addEventListener('keydown', (e) => { // Ctrl/Cmd + F focuses search if ((e.ctrlKey || e.metaKey) && e.key === 'f') { e.preventDefault(); // Focus search input if exists const searchInput = document.querySelector('input[placeholder*="Search"]'); if (searchInput) searchInput.focus(); } // Escape to clear search if (e.key === 'Escape') { const searchInput = document.querySelector('input[placeholder*="Search"]'); if (searchInput) searchInput.value = ''; } }); }); // Enhanced analytics tracking window.dataLayer = window.dataLayer || []; function gtag() { dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-XXXXX'); // Replace with actual Analytics ID // Performance monitoring if ('performance' in window) { const timing = performance.timing; const pageLoadTime = timing.loadEventEnd - timing.navigationStart; console.log(`Page loaded in ${pageLoadTime}ms`); // Send to analytics if needed gtag('event', 'page_load_time', { value: pageLoadTime, metric_id: 'page_load' }); } // Lazy loading for images document.addEventListener('DOMContentLoaded', () => { const lazyImages = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.removeAttribute('data-src'); observer.unobserve(img); } }); }); lazyImages.forEach(img => imageObserver.observe(img)); });