Новые правки страницы - Возврат прав

This commit is contained in:
Web-serfer 2026-04-12 19:21:14 +05:00
parent f5669e196f
commit 24be657ac6
20 changed files with 3219 additions and 45 deletions

View file

@ -0,0 +1,28 @@
export function setupScrollAnimations(): void {
if (typeof window === 'undefined') return;
const observerOptions = {
root: null,
rootMargin: '0px 0px -50px 0px',
threshold: 0.1
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const el = entry.target as HTMLElement;
const delay = parseInt(el.dataset.delay || '0');
setTimeout(() => {
el.classList.add('is-visible');
}, delay);
observer.unobserve(el);
}
});
}, observerOptions);
document.querySelectorAll('.animate-on-scroll').forEach((el) => {
observer.observe(el);
});
}

View file

@ -0,0 +1,74 @@
export function setupTabs(): void {
if (typeof window === 'undefined') return;
const tabButtons = document.querySelectorAll('.tab-btn');
const tabPanels = document.querySelectorAll('.tab-panel');
tabButtons.forEach(btn => {
btn.addEventListener('click', () => {
const tabId = btn.getAttribute('data-tab');
// Remove active from all buttons
tabButtons.forEach(b => {
b.classList.remove('active');
b.setAttribute('aria-selected', 'false');
});
// Remove active from all panels
tabPanels.forEach(panel => {
panel.classList.remove('active');
});
// Activate current tab
btn.classList.add('active');
btn.setAttribute('aria-selected', 'true');
const targetPanel = document.getElementById(`tab-${tabId}`);
if (targetPanel) {
targetPanel.classList.add('active');
// Animate counters if stats tab
if (tabId === 'stats') {
animateCounters(targetPanel);
}
}
});
});
}
export function animateCounters(panel: HTMLElement): void {
const counters = panel.querySelectorAll('[data-count]');
counters.forEach(counter => {
const target = parseInt(counter.getAttribute('data-count') || '0');
const suffix = counter.textContent?.replace(/[0-9]/g, '') || '';
const duration = 1500;
const startTime = performance.now();
const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3);
const update = (currentTime: number) => {
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / duration, 1);
const easedProgress = easeOutCubic(progress);
const currentValue = Math.round(easedProgress * target);
counter.textContent = `${currentValue}${suffix}`;
if (progress < 1) {
requestAnimationFrame(update);
}
};
requestAnimationFrame(update);
});
// Animate stat bars
const statBars = panel.querySelectorAll('[data-width]');
statBars.forEach(bar => {
const width = bar.getAttribute('data-width');
setTimeout(() => {
(bar as HTMLElement).style.width = `${width}%`;
}, 200);
});
}