| |
|
|
| 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)'; |
| |
| |
| 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() { |
| |
| 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; |
| |
| |
| 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 = '<i data-feather="copy" class="w-5 h-5"></i>'; |
| |
| block.parentNode.style.position = 'relative'; |
| block.parentNode.appendChild(copyButton); |
| |
| copyButton.addEventListener('click', async () => { |
| const code = block.textContent; |
| try { |
| await navigator.clipboard.writeText(code); |
| |
| |
| const originalIcon = copyButton.innerHTML; |
| copyButton.innerHTML = '<i data-feather="check" class="w-5 h-5 text-green-500"></i>'; |
| |
| 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() { |
| |
| 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, |
| `<span class="keyword-highlight">$1</span>` |
| ); |
| }); |
| } |
|
|
| |
| async fetchTelegramStats() { |
| try { |
| |
| |
| |
| |
| |
| return { |
| dailyUsers: 15000000, |
| retentionRate: 94, |
| revenuePotential: 2.3 |
| }; |
| } catch (error) { |
| console.error('Failed to fetch Telegram stats:', error); |
| return null; |
| } |
| } |
|
|
| |
| 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'; |
| }); |
| }); |
| } |
| } |
|
|
| |
| document.addEventListener('DOMContentLoaded', () => { |
| const researchPage = new TelegramGameResearch(); |
| |
| |
| |
| |
| |
| researchPage.fetchTelegramStats().then(stats => { |
| if (stats) { |
| console.log('Telegram Gaming Stats:', stats); |
| } |
| }); |
| |
| |
| document.addEventListener('keydown', (e) => { |
| |
| if ((e.ctrlKey || e.metaKey) && e.key === 'f') { |
| e.preventDefault(); |
| |
| const searchInput = document.querySelector('input[placeholder*="Search"]'); |
| if (searchInput) searchInput.focus(); |
| } |
| |
| |
| if (e.key === 'Escape') { |
| const searchInput = document.querySelector('input[placeholder*="Search"]'); |
| if (searchInput) searchInput.value = ''; |
| } |
| }); |
| }); |
|
|
| |
| window.dataLayer = window.dataLayer || []; |
| function gtag() { dataLayer.push(arguments); } |
| gtag('js', new Date()); |
| gtag('config', 'G-XXXXX'); |
|
|
| |
| if ('performance' in window) { |
| const timing = performance.timing; |
| const pageLoadTime = timing.loadEventEnd - timing.navigationStart; |
| console.log(`Page loaded in ${pageLoadTime}ms`); |
| |
| |
| gtag('event', 'page_load_time', { |
| value: pageLoadTime, |
| metric_id: 'page_load' |
| }); |
| } |
|
|
| |
| 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)); |
| }); |