// 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));
});