diff --git a/public/index.html b/public/index.html index 0c791a8..523d752 100644 --- a/public/index.html +++ b/public/index.html @@ -541,7 +541,6 @@ - diff --git a/public/js/app.js b/public/js/app.js index 37c6b65..3404cd4 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -31,16 +31,16 @@ document.addEventListener('DOMContentLoaded', () => { const sections = document.querySelectorAll('.section-bg'); - + const observer = new IntersectionObserver((entries) => { - entries.forEach((entry, index) => { - if (entry.isIntersecting) { - entry.target.style.transform = 'translateY(0)'; - entry.target.style.opacity = '1'; - entry.target.style.transitionDelay = `${index * 0.1}s`; - } - }); + entries.forEach((entry, index) => { + if (entry.isIntersecting) { + entry.target.style.transform = 'translateY(0)'; + entry.target.style.opacity = '1'; + entry.target.style.transitionDelay = `${index * 0.1}s`; + } + }); }, { threshold: 0.1 }); sections.forEach(section => { @@ -48,52 +48,105 @@ document.addEventListener('DOMContentLoaded', () => { section.style.opacity = '0'; section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out'; observer.observe(section); -}); + }); + - function throttle(fn, wait) { - let lastTime = 0; - return function (...args) { - const now = Date.now(); - if (now - lastTime >= wait) { - fn.apply(this, args); - lastTime = now; - } - }; + let lastTime = 0; + return function (...args) { + const now = Date.now(); + if (now - lastTime >= wait) { + fn.apply(this, args); + lastTime = now; + } + }; } - + // Hamburger Menu Toggle const hamburger = document.querySelector('.hamburger'); const mobileNav = document.querySelector('[data-mobile-nav]'); const navLinks = mobileNav.querySelectorAll('a'); - - + sections.forEach(section => { + section.style.transform = 'translateY(30px)'; + section.style.opacity = '0'; + section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out'; + observer.observe(section); + }); + + const PARTICLE_POOL_SIZE = 50; + const particlePool = []; + const activeParticles = new Set(); + + function createParticleElement() { + const particle = document.createElement('div'); + particle.classList.add('particle'); + if (Math.random() > 0.6) particle.classList.add('large'); + return particle; + } + + function initializeParticlePool() { + for (let i = 0; i < PARTICLE_POOL_SIZE; i++) { + particlePool.push(createParticleElement()); + } + } + + function resetParticle(particle) { + particle.style.left = `${Math.random() * 100}%`; + particle.style.top = `${Math.random() * 100}%`; + particle.style.animationDelay = `${Math.random() * 8}s`; + particle.style.animationDuration = `${8 + Math.random() * 6}s`; + particle.classList.remove('fade-out'); + return particle; + } + + function spawnParticle() { + if (particlePool.length === 0 || activeParticles.size >= PARTICLE_POOL_SIZE) return; + + const particle = resetParticle(particlePool.pop()); + if (!particle.parentNode) document.body.appendChild(particle); + activeParticles.add(particle); + + setTimeout(() => { + particle.classList.add('fade-out'); + setTimeout(() => { + activeParticles.delete(particle); + particlePool.push(particle); + }, 500); + }, 14000); + } + + function animate() { + if (Math.random() < 0.1) spawnParticle(); // Reduced spawn frequency + requestAnimationFrame(animate); + } + + // Debounce function to prevent rapid clicks function debounce(fn, wait) { - let timeout; - return function (...args) { - clearTimeout(timeout); - timeout = setTimeout(() => fn.apply(this, args), wait); - }; + let timeout; + return function (...args) { + clearTimeout(timeout); + timeout = setTimeout(() => fn.apply(this, args), wait); + }; } - + hamburger.addEventListener('click', debounce(() => { - mobileNav.classList.toggle('active'); - hamburger.classList.toggle('active'); + mobileNav.classList.toggle('active'); + hamburger.classList.toggle('active'); }, 100)); - + navLinks.forEach(link => { - link.addEventListener('click', () => { - mobileNav.classList.remove('active'); - hamburger.classList.remove('active'); - }); + link.addEventListener('click', () => { + mobileNav.classList.remove('active'); + hamburger.classList.remove('active'); + }); }); - + document.addEventListener('click', (e) => { - if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) { - mobileNav.classList.remove('active'); - hamburger.classList.remove('active'); - } + if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) { + mobileNav.classList.remove('active'); + hamburger.classList.remove('active'); + } }); const elements = { loginPage: document.getElementById('loginPage'), @@ -566,176 +619,176 @@ document.addEventListener('DOMContentLoaded', () => { function updateDockerUI(message) { if (message.error) { - console.log('Docker error detected, setting status to Not Running'); - if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running'; - toggleSections('Not Running'); - return; + console.log('Docker error detected, setting status to Not Running'); + if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running'; + toggleSections('Not Running'); + return; } const memoryPercent = parseFloat(message.data?.memory?.percent) || 0; if (state.memoryPercent !== memoryPercent && elements.memoryPercent && memoryMeter) { - memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent]; - memoryMeter.update(); - elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`; - state.memoryPercent = memoryPercent; + memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent]; + memoryMeter.update(); + elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`; + state.memoryPercent = memoryPercent; } const cpuPercent = parseFloat(message.data?.cpu) || 0; if (state.cpuPercent !== cpuPercent && elements.cpuPercent && cpuMeter) { - const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100); - cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent]; - cpuMeter.update(); - elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`; - state.cpuPercent = cpuPercent; + const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100); + cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent]; + cpuMeter.update(); + elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`; + state.cpuPercent = cpuPercent; } const status = message.data?.status || 'Unknown'; if (elements.serverStatus) { - elements.serverStatus.textContent = status; - state.serverStatus = status; - toggleSections(status); + elements.serverStatus.textContent = status; + state.serverStatus = status; + toggleSections(status); } -} - -function toggleSections(status) { - const sections = document.querySelectorAll('.section-bg'); - const serverStatusSection = document.querySelector('.section-bg[data-section="server-status"]'); - const editPropertiesBtn = elements.editPropertiesBtn; - const updateModsBtn = elements.updateModsBtn; - const sftpBtn = elements.sftpBtn; - const startBtn = document.getElementById('startBtn'); - const stopBtn = elements.stopBtn; - const restartBtn = elements.restartBtn; - const sftpBrowserSection = elements.sftpBrowserSection; - // Menu items in desktop and mobile nav - const refreshBtn = elements.refresh || document.getElementById('refresh'); - const mobileRefreshBtn = elements.mobileRefresh || document.getElementById('mobileRefresh'); - const backupBtn = elements.backupBtn; - const mobileBackupBtn = elements.mobileBackupBtn; - const logoutBtn = elements.logoutBtn || document.getElementById('logoutBtn'); - const mobileLogoutBtn = elements.mobileLogoutBtn || document.getElementById('mobileLogoutBtn'); - - if (startBtn) { - if (status.toLowerCase() === 'running') { - startBtn.disabled = true; - startBtn.classList.add('disabled-btn'); - } else { - startBtn.disabled = false; - startBtn.classList.remove('disabled-btn'); - } } - if (status.toLowerCase() !== 'running') { + function toggleSections(status) { + const sections = document.querySelectorAll('.section-bg'); + const serverStatusSection = document.querySelector('.section-bg[data-section="server-status"]'); + const editPropertiesBtn = elements.editPropertiesBtn; + const updateModsBtn = elements.updateModsBtn; + const sftpBtn = elements.sftpBtn; + const startBtn = document.getElementById('startBtn'); + const stopBtn = elements.stopBtn; + const restartBtn = elements.restartBtn; + const sftpBrowserSection = elements.sftpBrowserSection; + // Menu items in desktop and mobile nav + const refreshBtn = elements.refresh || document.getElementById('refresh'); + const mobileRefreshBtn = elements.mobileRefresh || document.getElementById('mobileRefresh'); + const backupBtn = elements.backupBtn; + const mobileBackupBtn = elements.mobileBackupBtn; + const logoutBtn = elements.logoutBtn || document.getElementById('logoutBtn'); + const mobileLogoutBtn = elements.mobileLogoutBtn || document.getElementById('mobileLogoutBtn'); + + if (startBtn) { + if (status.toLowerCase() === 'running') { + startBtn.disabled = true; + startBtn.classList.add('disabled-btn'); + } else { + startBtn.disabled = false; + startBtn.classList.remove('disabled-btn'); + } + } + + if (status.toLowerCase() !== 'running') { // Hide all sections except Server Status sections.forEach(section => { - if (section !== serverStatusSection) { - section.classList.add('hidden'); - } + if (section !== serverStatusSection) { + section.classList.add('hidden'); + } }); // Hide control buttons if (editPropertiesBtn) { - editPropertiesBtn.classList.add('hidden'); - editPropertiesBtn.style.display = 'none'; + editPropertiesBtn.classList.add('hidden'); + editPropertiesBtn.style.display = 'none'; } if (updateModsBtn) { - updateModsBtn.classList.add('hidden'); - updateModsBtn.style.display = 'none'; + updateModsBtn.classList.add('hidden'); + updateModsBtn.style.display = 'none'; } if (sftpBtn) { - sftpBtn.classList.add('hidden'); + sftpBtn.classList.add('hidden'); } if (stopBtn) { - stopBtn.disabled = true; - stopBtn.classList.add('disabled-btn'); + stopBtn.disabled = true; + stopBtn.classList.add('disabled-btn'); } if (restartBtn) { - restartBtn.disabled = true; - restartBtn.classList.add('disabled-btn'); + restartBtn.disabled = true; + restartBtn.classList.add('disabled-btn'); } if (sftpBrowserSection) { - sftpBrowserSection.style.display = 'none'; + sftpBrowserSection.style.display = 'none'; } // Hide Refresh, Backup, and Logout buttons in desktop nav if (refreshBtn) { - refreshBtn.classList.add('hidden'); - refreshBtn.style.display = 'none'; + refreshBtn.classList.add('hidden'); + refreshBtn.style.display = 'none'; } if (backupBtn) { - backupBtn.classList.add('hidden'); - backupBtn.style.display = 'none'; + backupBtn.classList.add('hidden'); + backupBtn.style.display = 'none'; } if (logoutBtn) { - logoutBtn.classList.add('hidden'); - logoutBtn.style.display = 'none'; + logoutBtn.classList.add('hidden'); + logoutBtn.style.display = 'none'; } // Hide Refresh, Backup, and Logout menu items in mobile nav if (mobileRefreshBtn && mobileRefreshBtn.parentElement) { - mobileRefreshBtn.parentElement.classList.add('hidden'); + mobileRefreshBtn.parentElement.classList.add('hidden'); } if (mobileBackupBtn && mobileBackupBtn.parentElement) { - mobileBackupBtn.parentElement.classList.add('hidden'); + mobileBackupBtn.parentElement.classList.add('hidden'); } if (mobileLogoutBtn && mobileLogoutBtn.parentElement) { - mobileLogoutBtn.parentElement.classList.add('hidden'); + mobileLogoutBtn.parentElement.classList.add('hidden'); } if (!state.hasShownStartNotification) { - showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped'); - state.hasShownStartNotification = true; + showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped'); + state.hasShownStartNotification = true; } - } else { + } else { // Show all sections sections.forEach(section => { - section.classList.remove('hidden'); + section.classList.remove('hidden'); }); // Show control buttons if (editPropertiesBtn) { - editPropertiesBtn.classList.remove('hidden'); - editPropertiesBtn.style.display = ''; + editPropertiesBtn.classList.remove('hidden'); + editPropertiesBtn.style.display = ''; } if (updateModsBtn) { - updateModsBtn.classList.remove('hidden'); - updateModsBtn.style.display = ''; + updateModsBtn.classList.remove('hidden'); + updateModsBtn.style.display = ''; } if (sftpBtn) { - sftpBtn.classList.remove('hidden'); + sftpBtn.classList.remove('hidden'); } if (stopBtn) { - stopBtn.disabled = false; - stopBtn.classList.remove('disabled-btn'); + stopBtn.disabled = false; + stopBtn.classList.remove('disabled-btn'); } if (restartBtn) { - restartBtn.disabled = false; - stopBtn.classList.remove('disabled-btn'); + restartBtn.disabled = false; + stopBtn.classList.remove('disabled-btn'); } if (sftpBrowserSection) { - sftpBrowserSection.style.display = 'block'; + sftpBrowserSection.style.display = 'block'; } // Show Refresh, Backup, and Logout buttons in desktop nav if (refreshBtn) { - refreshBtn.classList.remove('hidden'); - refreshBtn.style.display = ''; + refreshBtn.classList.remove('hidden'); + refreshBtn.style.display = ''; } if (backupBtn) { - backupBtn.classList.remove('hidden'); - refreshBtn.style.display = ''; + backupBtn.classList.remove('hidden'); + refreshBtn.style.display = ''; } if (logoutBtn) { - logoutBtn.classList.remove('hidden'); - logoutBtn.style.display = ''; + logoutBtn.classList.remove('hidden'); + logoutBtn.style.display = ''; } // Show Refresh, Backup, and Logout menu items in mobile nav if (mobileRefreshBtn && mobileRefreshBtn.parentElement) { - mobileRefreshBtn.parentElement.classList.remove('hidden'); + mobileRefreshBtn.parentElement.classList.remove('hidden'); } if (mobileBackupBtn && mobileBackupBtn.parentElement) { - mobileBackupBtn.parentElement.classList.remove('hidden'); + mobileBackupBtn.parentElement.classList.remove('hidden'); } if (mobileLogoutBtn && mobileLogoutBtn.parentElement) { - mobileLogoutBtn.parentElement.classList.remove('hidden'); + mobileLogoutBtn.parentElement.classList.remove('hidden'); } state.hasShownStartNotification = false; + } } -} function updateDockerLogsUI(message) { if (message.error) { @@ -925,7 +978,7 @@ function toggleSections(status) { if (state.playerList !== playerListHtml && elements.playerList) { elements.playerList.innerHTML = playerListHtml; state.playerList = playerListHtml; - + // Toggle action buttons document.querySelectorAll('.toggle-actions').forEach(button => { button.addEventListener('click', () => { @@ -937,7 +990,7 @@ function toggleSections(status) { } }); }); - + // Close action buttons document.querySelectorAll('.close-actions').forEach(button => { button.addEventListener('click', () => { @@ -950,7 +1003,7 @@ function toggleSections(status) { } }); }); - + document.querySelectorAll('.tell-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -963,7 +1016,7 @@ function toggleSections(status) { elements.tellModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.give-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -978,7 +1031,7 @@ function toggleSections(status) { elements.giveModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.teleport-player').forEach(button => { if (!button.disabled) { button.addEventListener('click', () => { @@ -996,7 +1049,7 @@ function toggleSections(status) { }); } }); - + document.querySelectorAll('.effect-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1009,7 +1062,7 @@ function toggleSections(status) { elements.effectModal.classList.remove('hidden'); }); }); - + document.querySelectorAll('.kick-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1041,7 +1094,7 @@ function toggleSections(status) { } }); }); - + document.querySelectorAll('.ban-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1073,7 +1126,7 @@ function toggleSections(status) { } }); }); - + document.querySelectorAll('.op-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1105,7 +1158,7 @@ function toggleSections(status) { } }); }); - + document.querySelectorAll('.deop-player').forEach(button => { button.addEventListener('click', () => { const player = button.getAttribute('data-player').trim(); @@ -1250,35 +1303,35 @@ function toggleSections(status) { } elements.loginPage.classList.add('hidden'); elements.mainContent.classList.remove('hidden'); - // Verify buttons exist - const logoutBtn = document.getElementById('logoutBtn'); - const mobileLogoutBtn = document.getElementById('mobileLogoutBtn'); - - if (logoutBtn) { - console.log('Desktop logout button found'); - } else { - console.error('Desktop logout button (#logoutBtn) not found'); - } - - if (mobileLogoutBtn) { - console.log('Mobile logout button found'); - } else { - console.error('Mobile logout button (#mobileLogoutBtn) not found'); - } - - // Remove any existing logout listeners to prevent duplicates - document.removeEventListener('click', handleLogoutClick); - - // Event delegation for logout buttons - function handleLogoutClick(event) { - if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') { - console.log(`Logout button clicked: ${event.target.id}`); - handleLogout(); - } - } - - document.addEventListener('click', handleLogoutClick); - + // Verify buttons exist + const logoutBtn = document.getElementById('logoutBtn'); + const mobileLogoutBtn = document.getElementById('mobileLogoutBtn'); + + if (logoutBtn) { + console.log('Desktop logout button found'); + } else { + console.error('Desktop logout button (#logoutBtn) not found'); + } + + if (mobileLogoutBtn) { + console.log('Mobile logout button found'); + } else { + console.error('Mobile logout button (#mobileLogoutBtn) not found'); + } + + // Remove any existing logout listeners to prevent duplicates + document.removeEventListener('click', handleLogoutClick); + + // Event delegation for logout buttons + function handleLogoutClick(event) { + if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') { + console.log(`Logout button clicked: ${event.target.id}`); + handleLogout(); + } + } + + document.addEventListener('click', handleLogoutClick); + initializeCharts(); initializeTerminal(); } @@ -1315,67 +1368,67 @@ function toggleSections(status) { elements.pagination.innerHTML = ''; const createPageButton = (page, text, disabled = false) => { - const button = document.createElement('button'); - button.textContent = text; - button.className = `nav-btn ${disabled || page === currentPage - ? 'disabled' - : 'active' + const button = document.createElement('button'); + button.textContent = text; + button.className = `nav-btn ${disabled || page === currentPage + ? 'disabled' + : 'active' }`; - if (!disabled && page !== currentPage) { - button.addEventListener('click', () => { - currentPage = page; - searchMods(); - }); - } - elements.pagination.appendChild(button); + if (!disabled && page !== currentPage) { + button.addEventListener('click', () => { + currentPage = page; + searchMods(); + }); + } + elements.pagination.appendChild(button); }; if (totalResults > 0) { - createPageButton(currentPage - 1, 'Previous', currentPage === 1); - const maxButtons = 5; - const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2)); - const endPage = Math.min(totalPages, startPage + maxButtons - 1); - for (let i = startPage; i <= endPage; i++) { - createPageButton(i, i.toString()); - } - createPageButton(currentPage + 1, 'Next', currentPage === totalPages); + createPageButton(currentPage - 1, 'Previous', currentPage === 1); + const maxButtons = 5; + const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2)); + const endPage = Math.min(totalPages, startPage + maxButtons - 1); + for (let i = startPage; i <= endPage; i++) { + createPageButton(i, i.toString()); + } + createPageButton(currentPage + 1, 'Next', currentPage === totalPages); } -} + } -function updateModListPagination() { + function updateModListPagination() { const filteredMods = state.allMods.filter(mod => - mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase()) + mod.name.toLowerCase().includes(modListSearchQuery.toLowerCase()) ); const totalModPages = Math.max(1, Math.ceil(filteredMods.length / resultsPerPage)); elements.modListPagination.innerHTML = ''; const createPageButton = (page, text, disabled = false) => { - const button = document.createElement('button'); - button.textContent = text; - button.className = `nav-btn ${disabled || page === modListCurrentPage - ? 'disabled' - : 'active' + const button = document.createElement('button'); + button.textContent = text; + button.className = `nav-btn ${disabled || page === modListCurrentPage + ? 'disabled' + : 'active' }`; - if (!disabled && page !== modListCurrentPage) { - button.addEventListener('click', () => { - modListCurrentPage = page; - renderModList(); - }); - } - elements.modListPagination.appendChild(button); + if (!disabled && page !== modListCurrentPage) { + button.addEventListener('click', () => { + modListCurrentPage = page; + renderModList(); + }); + } + elements.modListPagination.appendChild(button); }; if (filteredMods.length > 0) { - createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1); - const maxButtons = 5; - const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2)); - const endPage = Math.min(totalModPages, startPage + maxButtons - 1); - for (let i = startPage; i <= endPage; i++) { - createPageButton(i, i.toString()); - } - createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages); + createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1); + const maxButtons = 5; + const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2)); + const endPage = Math.min(totalModPages, startPage + maxButtons - 1); + for (let i = startPage; i <= endPage; i++) { + createPageButton(i, i.toString()); + } + createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages); } -} + } function closeSearch() { elements.modSearch.value = ''; @@ -2178,51 +2231,51 @@ function updateModListPagination() { document.getElementById('startBtn').addEventListener('click', async () => { try { - const key = `action-start`; - const notification = showNotification('Starting server...', 'loading', key); - await wsRequest('/start'); - initializeTerminal(); - if (ws && ws.readyState === WebSocket.OPEN) { - ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] })); - const messageHandler = (event) => { - try { - const message = JSON.parse(event.data); - if (message.type === 'docker') { - state.serverStatus = message.data?.status || 'Unknown'; - elements.serverStatus.textContent = state.serverStatus; - toggleSections(state.serverStatus); - if (message.data?.status.toLowerCase() === 'running') { - updateNotification(notification, 'Server started successfully', 'success', key); - // Ensure restart button is enabled - if (elements.restartBtn) { - elements.restartBtn.disabled = false; - elements.restartBtn.classList.remove('disabled-btn'); - } - ws.removeEventListener('message', messageHandler); - } - } - } catch (error) { - console.error('Error parsing WebSocket message:', error); + const key = `action-start`; + const notification = showNotification('Starting server...', 'loading', key); + await wsRequest('/start'); + initializeTerminal(); + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] })); + const messageHandler = (event) => { + try { + const message = JSON.parse(event.data); + if (message.type === 'docker') { + state.serverStatus = message.data?.status || 'Unknown'; + elements.serverStatus.textContent = state.serverStatus; + toggleSections(state.serverStatus); + if (message.data?.status.toLowerCase() === 'running') { + updateNotification(notification, 'Server started successfully', 'success', key); + // Ensure restart button is enabled + if (elements.restartBtn) { + elements.restartBtn.disabled = false; + elements.restartBtn.classList.remove('disabled-btn'); } - }; - ws.addEventListener('message', messageHandler); - setTimeout(() => { - if (ws && ws.readyState === WebSocket.OPEN) { - ws.removeEventListener('message', messageHandler); - if (state.serverStatus.toLowerCase() !== 'running') { - updateNotification(notification, 'Failed to start server. Please try again.', 'error', key); - toggleSections(state.serverStatus); - } - } - }, 30000); - } else { - updateNotification(notification, 'Not connected to server. Please log in.', 'error', key); - } + ws.removeEventListener('message', messageHandler); + } + } + } catch (error) { + console.error('Error parsing WebSocket message:', error); + } + }; + ws.addEventListener('message', messageHandler); + setTimeout(() => { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.removeEventListener('message', messageHandler); + if (state.serverStatus.toLowerCase() !== 'running') { + updateNotification(notification, 'Failed to start server. Please try again.', 'error', key); + toggleSections(state.serverStatus); + } + } + }, 30000); + } else { + updateNotification(notification, 'Not connected to server. Please log in.', 'error', key); + } } catch (error) { - console.error('Start server error:', error); - showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error'); + console.error('Start server error:', error); + showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error'); } -}); + }); document.getElementById('stopBtn').addEventListener('click', async () => { @@ -2280,7 +2333,7 @@ function updateModListPagination() { } }); - + elements.updateModsBtn.addEventListener('click', updateMods); @@ -2396,40 +2449,40 @@ function updateModListPagination() { window.showNotification = showNotification; // Add this at the end of the document.addEventListener('DOMContentLoaded', ...) block -function applyResponsiveStyles() { - const sections = document.querySelectorAll('.section-bg'); - sections.forEach(section => { - section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem'; - section.style.maxWidth = '100%'; - section.style.overflowX = 'hidden'; - }); + function applyResponsiveStyles() { + const sections = document.querySelectorAll('.section-bg'); + sections.forEach(section => { + section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem'; + section.style.maxWidth = '100%'; + section.style.overflowX = 'hidden'; + }); - const iframes = document.querySelectorAll('#sftpIframe'); - iframes.forEach(iframe => { - iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px'; - iframe.style.minHeight = iframe.style.height; - iframe.style.width = '100%'; - iframe.style.maxWidth = '100%'; - }); + const iframes = document.querySelectorAll('#sftpIframe'); + iframes.forEach(iframe => { + iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px'; + iframe.style.minHeight = iframe.style.height; + iframe.style.width = '100%'; + iframe.style.maxWidth = '100%'; + }); - const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter'); - canvases.forEach(canvas => { - canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px'; - canvas.style.height = canvas.style.width; - }); + const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter'); + canvases.forEach(canvas => { + canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px'; + canvas.style.height = canvas.style.width; + }); - const terminals = document.querySelectorAll('#dockerLogsTerminal'); - terminals.forEach(terminal => { - terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; - }); + const terminals = document.querySelectorAll('#dockerLogsTerminal'); + terminals.forEach(terminal => { + terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; + }); - const consoles = document.querySelectorAll('#consoleOutput'); - consoles.forEach(console => { - console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; - }); -} + const consoles = document.querySelectorAll('#consoleOutput'); + consoles.forEach(console => { + console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem'; + }); + } -window.addEventListener('resize', applyResponsiveStyles); + window.addEventListener('resize', applyResponsiveStyles); }); \ No newline at end of file diff --git a/public/js/main_app.js b/public/js/main_app.js deleted file mode 100644 index d07e5f2..0000000 --- a/public/js/main_app.js +++ /dev/null @@ -1,130 +0,0 @@ -const sections = document.querySelectorAll('.section-bg'); -const observer = new IntersectionObserver((entries) => { - entries.forEach((entry, index) => { - if (entry.isIntersecting) { - entry.target.style.transform = 'translateY(0)'; - entry.target.style.opacity = '1'; - entry.target.style.transitionDelay = `${index * 0.1}s`; - } - }); -}, { threshold: 0.1 }); - -sections.forEach(section => { - section.style.transform = 'translateY(30px)'; - section.style.opacity = '0'; - section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out'; - observer.observe(section); -}); - -const PARTICLE_POOL_SIZE = 50; -const particlePool = []; -const activeParticles = new Set(); - -function createParticleElement() { - const particle = document.createElement('div'); - particle.classList.add('particle'); - if (Math.random() > 0.6) particle.classList.add('large'); - return particle; -} - -function initializeParticlePool() { - for (let i = 0; i < PARTICLE_POOL_SIZE; i++) { - particlePool.push(createParticleElement()); - } -} - -function resetParticle(particle) { - particle.style.left = `${Math.random() * 100}%`; - particle.style.top = `${Math.random() * 100}%`; - particle.style.animationDelay = `${Math.random() * 8}s`; - particle.style.animationDuration = `${8 + Math.random() * 6}s`; - particle.classList.remove('fade-out'); - return particle; -} - -function spawnParticle() { - if (particlePool.length === 0 || activeParticles.size >= PARTICLE_POOL_SIZE) return; - - const particle = resetParticle(particlePool.pop()); - if (!particle.parentNode) document.body.appendChild(particle); - activeParticles.add(particle); - - setTimeout(() => { - particle.classList.add('fade-out'); - setTimeout(() => { - activeParticles.delete(particle); - particlePool.push(particle); - }, 500); - }, 14000); -} - -function animate() { - if (Math.random() < 0.1) spawnParticle(); // Reduced spawn frequency - requestAnimationFrame(animate); -} - -// Initialize and start -setTimeout(() => { - initializeParticlePool(); - animate(); -}, 500); - -function throttle(fn, wait) { - let lastTime = 0; - return function (...args) { - const now = Date.now(); - if (now - lastTime >= wait) { - fn.apply(this, args); - lastTime = now; - } - }; -} - - -const buttons = document.querySelectorAll('.btn-minecraft'); -buttons.forEach(button => { - button.addEventListener('mousemove', (e) => { - const rect = button.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - button.style.setProperty('--x', `${x}px`); - button.style.setProperty('--y', `${y}px`); - }); -}); - -// Hamburger Menu Toggle -const hamburger = document.querySelector('.hamburger'); -const mobileNav = document.querySelector('[data-mobile-nav]'); -const navLinks = mobileNav.querySelectorAll('a'); - -// Debounce function to prevent rapid clicks -function debounce(fn, wait) { - let timeout; - return function (...args) { - clearTimeout(timeout); - timeout = setTimeout(() => fn.apply(this, args), wait); - }; -} - -hamburger.addEventListener('click', debounce(() => { - console.log('Hamburger clicked, toggling menu'); - mobileNav.classList.toggle('active'); - hamburger.classList.toggle('active'); -}, 100)); - -navLinks.forEach(link => { - link.addEventListener('click', () => { - console.log('Nav link clicked, closing menu'); - mobileNav.classList.remove('active'); - hamburger.classList.remove('active'); - }); -}); - -document.addEventListener('click', (e) => { - if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) { - console.log('Clicked outside, closing menu'); - mobileNav.classList.remove('active'); - hamburger.classList.remove('active'); - } -}); -