DashX / public /index.js
HerzaJ's picture
Update public/index.js
9d9ec01 verified
const navToggle = document.getElementById('navToggle');
const navMenu = document.getElementById('navMenu');
const navOverlay = document.getElementById('navOverlay');
const body = document.body;
const html = document.documentElement;
let touchStartX = 0;
let touchEndX = 0;
let isAnimating = false;
function preventHorizontalScroll() {
html.style.overflowX = 'hidden';
html.style.width = '100%';
html.style.position = 'relative';
body.style.overflowX = 'hidden';
body.style.maxWidth = '100%';
body.style.width = '100%';
body.style.position = 'relative';
body.style.margin = '0';
body.style.padding = '0';
const existingStyle = document.getElementById('prevent-scroll-style');
if (existingStyle) {
existingStyle.remove();
}
const style = document.createElement('style');
style.id = 'prevent-scroll-style';
style.textContent = `
* {
box-sizing: border-box !important;
}
html, body {
overflow-x: hidden !important;
max-width: 100% !important;
width: 100% !important;
margin: 0 !important;
padding: 0 !important;
}
body.menu-open {
overflow: hidden !important;
position: fixed !important;
width: 100% !important;
height: 100% !important;
top: 0 !important;
left: 0 !important;
}
section, .container, .nav-container, .hero, .features, .stats, .footer {
max-width: 100% !important;
overflow-x: hidden !important;
}
.nav-menu {
position: fixed !important;
top: 0 !important;
right: -100% !important;
width: 280px !important;
height: 100vh !important;
background: rgba(44, 62, 80, 0.98) !important;
backdrop-filter: blur(20px) !important;
flex-direction: column !important;
padding: 5rem 2rem 2rem !important;
gap: 0.5rem !important;
box-shadow: -5px 0 20px rgba(0, 0, 0, 0.5) !important;
overflow-y: auto !important;
overflow-x: hidden !important;
border-left: 1px solid rgba(255, 255, 255, 0.1) !important;
align-items: stretch !important;
z-index: 10001 !important;
transition: right 0.4s cubic-bezier(0.4, 0, 0.2, 1) !important;
display: flex !important;
}
.nav-menu.active {
right: 0 !important;
}
.nav-overlay {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
background: rgba(0, 0, 0, 0.7) !important;
z-index: 10000 !important;
opacity: 0 !important;
visibility: hidden !important;
transition: opacity 0.4s cubic-bezier(0.4, 0, 0.2, 1), visibility 0.4s cubic-bezier(0.4, 0, 0.2, 1) !important;
pointer-events: none !important;
}
.nav-overlay.active {
opacity: 1 !important;
visibility: visible !important;
pointer-events: auto !important;
}
.nav-toggle {
z-index: 10002 !important;
cursor: pointer !important;
transition: transform 0.3s ease !important;
position: relative !important;
}
.nav-toggle.active {
transform: rotate(90deg) !important;
}
img, video, iframe {
max-width: 100% !important;
height: auto !important;
}
@media (max-width: 768px) {
.hero-buttons, .cta-buttons, .hero-features {
flex-wrap: wrap !important;
justify-content: center !important;
}
.feature-card, .stat-card {
width: 100% !important;
max-width: 100% !important;
}
.nav-menu {
width: 280px !important;
}
}
`;
document.head.appendChild(style);
}
function toggleMenu(e) {
if (e) {
e.preventDefault();
e.stopPropagation();
}
if (isAnimating) return;
const isActive = navMenu.classList.contains('active');
if (isActive) {
closeMenu();
} else {
openMenu();
}
}
function openMenu() {
if (isAnimating) return;
isAnimating = true;
const scrollY = window.scrollY;
body.style.top = `-${scrollY}px`;
navToggle.classList.add('active');
navOverlay.classList.add('active');
body.classList.add('menu-open');
setTimeout(() => {
navMenu.classList.add('active');
setTimeout(() => {
isAnimating = false;
}, 400);
}, 10);
}
function closeMenu() {
if (isAnimating) return;
isAnimating = true;
navToggle.classList.remove('active');
navMenu.classList.remove('active');
navOverlay.classList.remove('active');
setTimeout(() => {
body.classList.remove('menu-open');
const scrollY = body.style.top;
body.style.top = '';
if (scrollY) {
window.scrollTo(0, parseInt(scrollY || '0') * -1);
}
isAnimating = false;
}, 400);
}
if (navToggle) {
navToggle.addEventListener('click', toggleMenu);
navToggle.addEventListener('touchstart', (e) => {
e.stopPropagation();
}, { passive: true });
}
if (navOverlay) {
navOverlay.addEventListener('click', (e) => {
e.preventDefault();
e.stopPropagation();
closeMenu();
});
}
if (navMenu) {
navMenu.addEventListener('click', (e) => {
e.stopPropagation();
});
navMenu.addEventListener('touchstart', (e) => {
touchStartX = e.changedTouches[0].screenX;
e.stopPropagation();
}, { passive: true });
navMenu.addEventListener('touchend', (e) => {
touchEndX = e.changedTouches[0].screenX;
if (touchStartX - touchEndX > 50) {
closeMenu();
}
e.stopPropagation();
}, { passive: true });
}
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', handleNavLinkClick);
});
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
if (!anchor.classList.contains('nav-link')) {
anchor.addEventListener('click', function (e) {
const href = this.getAttribute('href');
if (!href || href === '#') return;
e.preventDefault();
const target = document.querySelector(href);
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
}
});
window.addEventListener('load', () => {
preventHorizontalScroll();
});
window.addEventListener('resize', () => {
preventHorizontalScroll();
if (window.innerWidth > 768) {
if (navMenu.classList.contains('active')) {
closeMenu();
}
}
});
document.addEventListener('touchmove', (e) => {
if (body.classList.contains('menu-open')) {
if (!navMenu.contains(e.target)) {
e.preventDefault();
}
}
}, { passive: false });
function checkAuthStatus() {
const token = localStorage.getItem('dashx_token');
if (token) {
const navMenuEl = document.querySelector('.nav-menu');
if (navMenuEl) {
navMenuEl.innerHTML = `
<a href="/dashboard" class="nav-link"><i class="fas fa-chart-line"></i> Dashboard</a>
<a href="/profile" class="nav-link"><i class="fas fa-user"></i> Profile</a>
<a href="#" class="nav-link" id="logoutBtn"><i class="fas fa-sign-out-alt"></i> Logout</a>
`;
attachNavLinkListeners();
}
} else {
attachNavLinkListeners();
}
}
function attachNavLinkListeners() {
document.querySelectorAll('.nav-link').forEach(link => {
link.removeEventListener('click', handleNavLinkClick);
link.addEventListener('click', handleNavLinkClick);
});
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) {
logoutBtn.addEventListener('click', (e) => {
e.preventDefault();
closeMenu();
setTimeout(() => {
logout();
}, 400);
});
}
}
function handleNavLinkClick(e) {
const href = this.getAttribute('href');
if (!href || href === '#' || this.id === 'logoutBtn') {
return;
}
if (href.startsWith('#')) {
e.preventDefault();
const target = document.querySelector(href);
if (target) {
closeMenu();
setTimeout(() => {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 400);
}
} else {
e.preventDefault();
closeMenu();
setTimeout(() => {
window.location.href = href;
}, 400);
}
}
async function loadStats() {
try {
const totalUsersEl = document.getElementById('totalUsers');
const totalRequestsEl = document.getElementById('totalRequests');
const todayRequestsEl = document.getElementById('todayRequests');
if (totalUsersEl) {
totalUsersEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
}
if (totalRequestsEl) {
totalRequestsEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
}
if (todayRequestsEl) {
todayRequestsEl.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
}
const response = await fetch('/api/stats', {
method: 'GET',
headers: {
'Content-Type': 'application/json'
}
});
if (response.ok) {
const data = await response.json();
if (data.success && data.stats) {
const stats = data.stats;
if (totalUsersEl) {
totalUsersEl.textContent = formatNumber(stats.totalUsers) || '0';
}
if (totalRequestsEl) {
totalRequestsEl.textContent = formatNumber(stats.totalRequests) || '0';
}
if (todayRequestsEl) {
todayRequestsEl.textContent = formatNumber(stats.todayRequests) || '0';
}
animateNumbers();
} else {
throw new Error(data.error || 'Failed to load stats');
}
} else {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
} catch (error) {
console.error('Error loading stats:', error);
const totalUsersEl = document.getElementById('totalUsers');
const totalRequestsEl = document.getElementById('totalRequests');
const todayRequestsEl = document.getElementById('todayRequests');
if (totalUsersEl) totalUsersEl.textContent = '0';
if (totalRequestsEl) totalRequestsEl.textContent = '0';
if (todayRequestsEl) todayRequestsEl.textContent = '0';
}
}
function formatNumber(num) {
if (typeof num !== 'number') return '0';
if (num >= 1000000) {
return (num / 1000000).toFixed(1) + 'M';
} else if (num >= 1000) {
return (num / 1000).toFixed(1) + 'K';
}
return num.toLocaleString();
}
function animateNumbers() {
const numbers = document.querySelectorAll('.stat-number');
numbers.forEach(number => {
if (number.textContent.includes('Error') || number.textContent.includes('fa-spin')) {
return;
}
const finalText = number.textContent;
let targetValue = 0;
if (finalText.includes('K')) {
targetValue = parseFloat(finalText) * 1000;
} else if (finalText.includes('M')) {
targetValue = parseFloat(finalText) * 1000000;
} else {
targetValue = parseInt(finalText.replace(/,/g, '')) || 0;
}
if (targetValue === 0) return;
let current = 0;
const increment = Math.max(1, Math.ceil(targetValue / 50));
number.textContent = '0';
const timer = setInterval(() => {
current += increment;
if (current >= targetValue) {
current = targetValue;
clearInterval(timer);
number.textContent = finalText;
} else {
if (targetValue >= 1000000) {
number.textContent = (current / 1000000).toFixed(1) + 'M';
} else if (targetValue >= 1000) {
number.textContent = (current / 1000).toFixed(1) + 'K';
} else {
number.textContent = current.toLocaleString();
}
}
}, 30);
});
}
function logout() {
localStorage.removeItem('dashx_token');
localStorage.removeItem('dashx_user');
window.location.href = '/';
}
function addLiveUpdates() {
const statsCards = document.querySelectorAll('.stat-card');
statsCards.forEach(card => {
card.addEventListener('mouseenter', () => {
card.style.transform = 'translateY(-5px)';
card.style.boxShadow = '0 8px 25px rgba(0,0,0,0.15)';
});
card.addEventListener('mouseleave', () => {
card.style.transform = 'translateY(0)';
card.style.boxShadow = '0 4px 12px rgba(0,0,0,0.1)';
});
});
}
function addRefreshButton() {
const refreshBtn = document.createElement('button');
refreshBtn.innerHTML = '<i class="fas fa-sync-alt"></i>';
refreshBtn.title = 'Refresh Statistics';
refreshBtn.style.cssText = `
position: fixed;
bottom: 20px;
right: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
border: none;
background: linear-gradient(45deg, #853030, #a64545);
color: white;
font-size: 1.2rem;
cursor: pointer;
box-shadow: 0 4px 12px rgba(133, 48, 48, 0.3);
transition: all 0.3s ease;
z-index: 1000;
`;
refreshBtn.addEventListener('click', () => {
refreshBtn.style.transform = 'rotate(360deg)';
loadStats();
setTimeout(() => {
refreshBtn.style.transform = 'rotate(0deg)';
}, 500);
});
refreshBtn.addEventListener('mouseenter', () => {
refreshBtn.style.transform = 'scale(1.1)';
refreshBtn.style.boxShadow = '0 6px 20px rgba(133, 48, 48, 0.4)';
});
refreshBtn.addEventListener('mouseleave', () => {
refreshBtn.style.transform = 'scale(1)';
refreshBtn.style.boxShadow = '0 4px 12px rgba(133, 48, 48, 0.3)';
});
document.body.appendChild(refreshBtn);
}
function initializeEnhancements() {
addLiveUpdates();
addRefreshButton();
}
function addLoadingStates() {
const style = document.createElement('style');
style.textContent = `
.loading-pulse {
animation: pulse 1.5s ease-in-out infinite;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.stat-card:hover .stat-number {
transform: scale(1.05);
transition: transform 0.2s ease;
}
`;
document.head.appendChild(style);
}
function addKeyboardShortcuts() {
document.addEventListener('keydown', (event) => {
if (event.ctrlKey || event.metaKey) {
switch (event.key) {
case 'r':
event.preventDefault();
loadStats();
break;
case 'd':
event.preventDefault();
if (localStorage.getItem('dashx_token')) {
window.location.href = '/dashboard';
}
break;
}
}
if (event.key === 'F5') {
event.preventDefault();
loadStats();
}
if (event.key === 'Escape') {
closeMenu();
}
});
}
document.addEventListener('DOMContentLoaded', function() {
preventHorizontalScroll();
loadStats();
checkAuthStatus();
attachNavLinkListeners();
setInterval(loadStats, 30000);
setTimeout(() => {
initializeEnhancements();
addLoadingStates();
addKeyboardShortcuts();
}, 1000);
});