combile main-app.js into app.js
This commit is contained in:
@@ -541,7 +541,6 @@
|
|||||||
|
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
<script src="js/tutorial.js"></script>
|
<script src="js/tutorial.js"></script>
|
||||||
<script src="js/main_app.js"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
573
public/js/app.js
573
public/js/app.js
@@ -34,13 +34,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
|
|
||||||
const observer = new IntersectionObserver((entries) => {
|
const observer = new IntersectionObserver((entries) => {
|
||||||
entries.forEach((entry, index) => {
|
entries.forEach((entry, index) => {
|
||||||
if (entry.isIntersecting) {
|
if (entry.isIntersecting) {
|
||||||
entry.target.style.transform = 'translateY(0)';
|
entry.target.style.transform = 'translateY(0)';
|
||||||
entry.target.style.opacity = '1';
|
entry.target.style.opacity = '1';
|
||||||
entry.target.style.transitionDelay = `${index * 0.1}s`;
|
entry.target.style.transitionDelay = `${index * 0.1}s`;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, { threshold: 0.1 });
|
}, { threshold: 0.1 });
|
||||||
|
|
||||||
sections.forEach(section => {
|
sections.forEach(section => {
|
||||||
@@ -48,52 +48,105 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
section.style.opacity = '0';
|
section.style.opacity = '0';
|
||||||
section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out';
|
section.style.transition = 'transform 0.7s ease-out, opacity 0.7s ease-out';
|
||||||
observer.observe(section);
|
observer.observe(section);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function throttle(fn, wait) {
|
function throttle(fn, wait) {
|
||||||
let lastTime = 0;
|
let lastTime = 0;
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
if (now - lastTime >= wait) {
|
if (now - lastTime >= wait) {
|
||||||
fn.apply(this, args);
|
fn.apply(this, args);
|
||||||
lastTime = now;
|
lastTime = now;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hamburger Menu Toggle
|
// Hamburger Menu Toggle
|
||||||
const hamburger = document.querySelector('.hamburger');
|
const hamburger = document.querySelector('.hamburger');
|
||||||
const mobileNav = document.querySelector('[data-mobile-nav]');
|
const mobileNav = document.querySelector('[data-mobile-nav]');
|
||||||
const navLinks = mobileNav.querySelectorAll('a');
|
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
|
// Debounce function to prevent rapid clicks
|
||||||
function debounce(fn, wait) {
|
function debounce(fn, wait) {
|
||||||
let timeout;
|
let timeout;
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
timeout = setTimeout(() => fn.apply(this, args), wait);
|
timeout = setTimeout(() => fn.apply(this, args), wait);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
hamburger.addEventListener('click', debounce(() => {
|
hamburger.addEventListener('click', debounce(() => {
|
||||||
mobileNav.classList.toggle('active');
|
mobileNav.classList.toggle('active');
|
||||||
hamburger.classList.toggle('active');
|
hamburger.classList.toggle('active');
|
||||||
}, 100));
|
}, 100));
|
||||||
|
|
||||||
navLinks.forEach(link => {
|
navLinks.forEach(link => {
|
||||||
link.addEventListener('click', () => {
|
link.addEventListener('click', () => {
|
||||||
mobileNav.classList.remove('active');
|
mobileNav.classList.remove('active');
|
||||||
hamburger.classList.remove('active');
|
hamburger.classList.remove('active');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) {
|
if (!mobileNav.contains(e.target) && !hamburger.contains(e.target) && mobileNav.classList.contains('active')) {
|
||||||
mobileNav.classList.remove('active');
|
mobileNav.classList.remove('active');
|
||||||
hamburger.classList.remove('active');
|
hamburger.classList.remove('active');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const elements = {
|
const elements = {
|
||||||
loginPage: document.getElementById('loginPage'),
|
loginPage: document.getElementById('loginPage'),
|
||||||
@@ -566,176 +619,176 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
function updateDockerUI(message) {
|
function updateDockerUI(message) {
|
||||||
if (message.error) {
|
if (message.error) {
|
||||||
console.log('Docker error detected, setting status to Not Running');
|
console.log('Docker error detected, setting status to Not Running');
|
||||||
if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running';
|
if (elements.serverStatus) elements.serverStatus.textContent = 'Not Running';
|
||||||
toggleSections('Not Running');
|
toggleSections('Not Running');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const memoryPercent = parseFloat(message.data?.memory?.percent) || 0;
|
const memoryPercent = parseFloat(message.data?.memory?.percent) || 0;
|
||||||
if (state.memoryPercent !== memoryPercent && elements.memoryPercent && memoryMeter) {
|
if (state.memoryPercent !== memoryPercent && elements.memoryPercent && memoryMeter) {
|
||||||
memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent];
|
memoryMeter.data.datasets[0].data = [memoryPercent, 100 - memoryPercent];
|
||||||
memoryMeter.update();
|
memoryMeter.update();
|
||||||
elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`;
|
elements.memoryPercent.textContent = `${memoryPercent.toFixed(1)}%`;
|
||||||
state.memoryPercent = memoryPercent;
|
state.memoryPercent = memoryPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const cpuPercent = parseFloat(message.data?.cpu) || 0;
|
const cpuPercent = parseFloat(message.data?.cpu) || 0;
|
||||||
if (state.cpuPercent !== cpuPercent && elements.cpuPercent && cpuMeter) {
|
if (state.cpuPercent !== cpuPercent && elements.cpuPercent && cpuMeter) {
|
||||||
const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100);
|
const scaledCpuPercent = Math.min((cpuPercent / 600) * 100, 100);
|
||||||
cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent];
|
cpuMeter.data.datasets[0].data = [scaledCpuPercent, 100 - scaledCpuPercent];
|
||||||
cpuMeter.update();
|
cpuMeter.update();
|
||||||
elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`;
|
elements.cpuPercent.textContent = `${cpuPercent.toFixed(1)}%`;
|
||||||
state.cpuPercent = cpuPercent;
|
state.cpuPercent = cpuPercent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const status = message.data?.status || 'Unknown';
|
const status = message.data?.status || 'Unknown';
|
||||||
if (elements.serverStatus) {
|
if (elements.serverStatus) {
|
||||||
elements.serverStatus.textContent = status;
|
elements.serverStatus.textContent = status;
|
||||||
state.serverStatus = status;
|
state.serverStatus = status;
|
||||||
toggleSections(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
|
// Hide all sections except Server Status
|
||||||
sections.forEach(section => {
|
sections.forEach(section => {
|
||||||
if (section !== serverStatusSection) {
|
if (section !== serverStatusSection) {
|
||||||
section.classList.add('hidden');
|
section.classList.add('hidden');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// Hide control buttons
|
// Hide control buttons
|
||||||
if (editPropertiesBtn) {
|
if (editPropertiesBtn) {
|
||||||
editPropertiesBtn.classList.add('hidden');
|
editPropertiesBtn.classList.add('hidden');
|
||||||
editPropertiesBtn.style.display = 'none';
|
editPropertiesBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
if (updateModsBtn) {
|
if (updateModsBtn) {
|
||||||
updateModsBtn.classList.add('hidden');
|
updateModsBtn.classList.add('hidden');
|
||||||
updateModsBtn.style.display = 'none';
|
updateModsBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
if (sftpBtn) {
|
if (sftpBtn) {
|
||||||
sftpBtn.classList.add('hidden');
|
sftpBtn.classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (stopBtn) {
|
if (stopBtn) {
|
||||||
stopBtn.disabled = true;
|
stopBtn.disabled = true;
|
||||||
stopBtn.classList.add('disabled-btn');
|
stopBtn.classList.add('disabled-btn');
|
||||||
}
|
}
|
||||||
if (restartBtn) {
|
if (restartBtn) {
|
||||||
restartBtn.disabled = true;
|
restartBtn.disabled = true;
|
||||||
restartBtn.classList.add('disabled-btn');
|
restartBtn.classList.add('disabled-btn');
|
||||||
}
|
}
|
||||||
if (sftpBrowserSection) {
|
if (sftpBrowserSection) {
|
||||||
sftpBrowserSection.style.display = 'none';
|
sftpBrowserSection.style.display = 'none';
|
||||||
}
|
}
|
||||||
// Hide Refresh, Backup, and Logout buttons in desktop nav
|
// Hide Refresh, Backup, and Logout buttons in desktop nav
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
refreshBtn.classList.add('hidden');
|
refreshBtn.classList.add('hidden');
|
||||||
refreshBtn.style.display = 'none';
|
refreshBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
if (backupBtn) {
|
if (backupBtn) {
|
||||||
backupBtn.classList.add('hidden');
|
backupBtn.classList.add('hidden');
|
||||||
backupBtn.style.display = 'none';
|
backupBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
if (logoutBtn) {
|
if (logoutBtn) {
|
||||||
logoutBtn.classList.add('hidden');
|
logoutBtn.classList.add('hidden');
|
||||||
logoutBtn.style.display = 'none';
|
logoutBtn.style.display = 'none';
|
||||||
}
|
}
|
||||||
// Hide Refresh, Backup, and Logout menu items in mobile nav
|
// Hide Refresh, Backup, and Logout menu items in mobile nav
|
||||||
if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
|
if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
|
||||||
mobileRefreshBtn.parentElement.classList.add('hidden');
|
mobileRefreshBtn.parentElement.classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (mobileBackupBtn && mobileBackupBtn.parentElement) {
|
if (mobileBackupBtn && mobileBackupBtn.parentElement) {
|
||||||
mobileBackupBtn.parentElement.classList.add('hidden');
|
mobileBackupBtn.parentElement.classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
|
if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
|
||||||
mobileLogoutBtn.parentElement.classList.add('hidden');
|
mobileLogoutBtn.parentElement.classList.add('hidden');
|
||||||
}
|
}
|
||||||
if (!state.hasShownStartNotification) {
|
if (!state.hasShownStartNotification) {
|
||||||
showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped');
|
showNotification('Server is stopped. Click "Start" to enable all features.', 'error', 'server-stopped');
|
||||||
state.hasShownStartNotification = true;
|
state.hasShownStartNotification = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Show all sections
|
// Show all sections
|
||||||
sections.forEach(section => {
|
sections.forEach(section => {
|
||||||
section.classList.remove('hidden');
|
section.classList.remove('hidden');
|
||||||
});
|
});
|
||||||
// Show control buttons
|
// Show control buttons
|
||||||
if (editPropertiesBtn) {
|
if (editPropertiesBtn) {
|
||||||
editPropertiesBtn.classList.remove('hidden');
|
editPropertiesBtn.classList.remove('hidden');
|
||||||
editPropertiesBtn.style.display = '';
|
editPropertiesBtn.style.display = '';
|
||||||
}
|
}
|
||||||
if (updateModsBtn) {
|
if (updateModsBtn) {
|
||||||
updateModsBtn.classList.remove('hidden');
|
updateModsBtn.classList.remove('hidden');
|
||||||
updateModsBtn.style.display = '';
|
updateModsBtn.style.display = '';
|
||||||
}
|
}
|
||||||
if (sftpBtn) {
|
if (sftpBtn) {
|
||||||
sftpBtn.classList.remove('hidden');
|
sftpBtn.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
if (stopBtn) {
|
if (stopBtn) {
|
||||||
stopBtn.disabled = false;
|
stopBtn.disabled = false;
|
||||||
stopBtn.classList.remove('disabled-btn');
|
stopBtn.classList.remove('disabled-btn');
|
||||||
}
|
}
|
||||||
if (restartBtn) {
|
if (restartBtn) {
|
||||||
restartBtn.disabled = false;
|
restartBtn.disabled = false;
|
||||||
stopBtn.classList.remove('disabled-btn');
|
stopBtn.classList.remove('disabled-btn');
|
||||||
}
|
}
|
||||||
if (sftpBrowserSection) {
|
if (sftpBrowserSection) {
|
||||||
sftpBrowserSection.style.display = 'block';
|
sftpBrowserSection.style.display = 'block';
|
||||||
}
|
}
|
||||||
// Show Refresh, Backup, and Logout buttons in desktop nav
|
// Show Refresh, Backup, and Logout buttons in desktop nav
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
refreshBtn.classList.remove('hidden');
|
refreshBtn.classList.remove('hidden');
|
||||||
refreshBtn.style.display = '';
|
refreshBtn.style.display = '';
|
||||||
}
|
}
|
||||||
if (backupBtn) {
|
if (backupBtn) {
|
||||||
backupBtn.classList.remove('hidden');
|
backupBtn.classList.remove('hidden');
|
||||||
refreshBtn.style.display = '';
|
refreshBtn.style.display = '';
|
||||||
}
|
}
|
||||||
if (logoutBtn) {
|
if (logoutBtn) {
|
||||||
logoutBtn.classList.remove('hidden');
|
logoutBtn.classList.remove('hidden');
|
||||||
logoutBtn.style.display = '';
|
logoutBtn.style.display = '';
|
||||||
}
|
}
|
||||||
// Show Refresh, Backup, and Logout menu items in mobile nav
|
// Show Refresh, Backup, and Logout menu items in mobile nav
|
||||||
if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
|
if (mobileRefreshBtn && mobileRefreshBtn.parentElement) {
|
||||||
mobileRefreshBtn.parentElement.classList.remove('hidden');
|
mobileRefreshBtn.parentElement.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
if (mobileBackupBtn && mobileBackupBtn.parentElement) {
|
if (mobileBackupBtn && mobileBackupBtn.parentElement) {
|
||||||
mobileBackupBtn.parentElement.classList.remove('hidden');
|
mobileBackupBtn.parentElement.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
|
if (mobileLogoutBtn && mobileLogoutBtn.parentElement) {
|
||||||
mobileLogoutBtn.parentElement.classList.remove('hidden');
|
mobileLogoutBtn.parentElement.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
state.hasShownStartNotification = false;
|
state.hasShownStartNotification = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function updateDockerLogsUI(message) {
|
function updateDockerLogsUI(message) {
|
||||||
if (message.error) {
|
if (message.error) {
|
||||||
@@ -1250,34 +1303,34 @@ function toggleSections(status) {
|
|||||||
}
|
}
|
||||||
elements.loginPage.classList.add('hidden');
|
elements.loginPage.classList.add('hidden');
|
||||||
elements.mainContent.classList.remove('hidden');
|
elements.mainContent.classList.remove('hidden');
|
||||||
// Verify buttons exist
|
// Verify buttons exist
|
||||||
const logoutBtn = document.getElementById('logoutBtn');
|
const logoutBtn = document.getElementById('logoutBtn');
|
||||||
const mobileLogoutBtn = document.getElementById('mobileLogoutBtn');
|
const mobileLogoutBtn = document.getElementById('mobileLogoutBtn');
|
||||||
|
|
||||||
if (logoutBtn) {
|
if (logoutBtn) {
|
||||||
console.log('Desktop logout button found');
|
console.log('Desktop logout button found');
|
||||||
} else {
|
} else {
|
||||||
console.error('Desktop logout button (#logoutBtn) not found');
|
console.error('Desktop logout button (#logoutBtn) not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mobileLogoutBtn) {
|
if (mobileLogoutBtn) {
|
||||||
console.log('Mobile logout button found');
|
console.log('Mobile logout button found');
|
||||||
} else {
|
} else {
|
||||||
console.error('Mobile logout button (#mobileLogoutBtn) not found');
|
console.error('Mobile logout button (#mobileLogoutBtn) not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any existing logout listeners to prevent duplicates
|
// Remove any existing logout listeners to prevent duplicates
|
||||||
document.removeEventListener('click', handleLogoutClick);
|
document.removeEventListener('click', handleLogoutClick);
|
||||||
|
|
||||||
// Event delegation for logout buttons
|
// Event delegation for logout buttons
|
||||||
function handleLogoutClick(event) {
|
function handleLogoutClick(event) {
|
||||||
if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') {
|
if (event.target.id === 'logoutBtn' || event.target.id === 'mobileLogoutBtn') {
|
||||||
console.log(`Logout button clicked: ${event.target.id}`);
|
console.log(`Logout button clicked: ${event.target.id}`);
|
||||||
handleLogout();
|
handleLogout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('click', handleLogoutClick);
|
document.addEventListener('click', handleLogoutClick);
|
||||||
|
|
||||||
initializeCharts();
|
initializeCharts();
|
||||||
initializeTerminal();
|
initializeTerminal();
|
||||||
@@ -1315,67 +1368,67 @@ function toggleSections(status) {
|
|||||||
elements.pagination.innerHTML = '';
|
elements.pagination.innerHTML = '';
|
||||||
|
|
||||||
const createPageButton = (page, text, disabled = false) => {
|
const createPageButton = (page, text, disabled = false) => {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.textContent = text;
|
button.textContent = text;
|
||||||
button.className = `nav-btn ${disabled || page === currentPage
|
button.className = `nav-btn ${disabled || page === currentPage
|
||||||
? 'disabled'
|
? 'disabled'
|
||||||
: 'active'
|
: 'active'
|
||||||
}`;
|
}`;
|
||||||
if (!disabled && page !== currentPage) {
|
if (!disabled && page !== currentPage) {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
currentPage = page;
|
currentPage = page;
|
||||||
searchMods();
|
searchMods();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
elements.pagination.appendChild(button);
|
elements.pagination.appendChild(button);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (totalResults > 0) {
|
if (totalResults > 0) {
|
||||||
createPageButton(currentPage - 1, 'Previous', currentPage === 1);
|
createPageButton(currentPage - 1, 'Previous', currentPage === 1);
|
||||||
const maxButtons = 5;
|
const maxButtons = 5;
|
||||||
const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2));
|
const startPage = Math.max(1, currentPage - Math.floor(maxButtons / 2));
|
||||||
const endPage = Math.min(totalPages, startPage + maxButtons - 1);
|
const endPage = Math.min(totalPages, startPage + maxButtons - 1);
|
||||||
for (let i = startPage; i <= endPage; i++) {
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
createPageButton(i, i.toString());
|
createPageButton(i, i.toString());
|
||||||
}
|
}
|
||||||
createPageButton(currentPage + 1, 'Next', currentPage === totalPages);
|
createPageButton(currentPage + 1, 'Next', currentPage === totalPages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateModListPagination() {
|
function updateModListPagination() {
|
||||||
const filteredMods = state.allMods.filter(mod =>
|
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));
|
const totalModPages = Math.max(1, Math.ceil(filteredMods.length / resultsPerPage));
|
||||||
elements.modListPagination.innerHTML = '';
|
elements.modListPagination.innerHTML = '';
|
||||||
|
|
||||||
const createPageButton = (page, text, disabled = false) => {
|
const createPageButton = (page, text, disabled = false) => {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement('button');
|
||||||
button.textContent = text;
|
button.textContent = text;
|
||||||
button.className = `nav-btn ${disabled || page === modListCurrentPage
|
button.className = `nav-btn ${disabled || page === modListCurrentPage
|
||||||
? 'disabled'
|
? 'disabled'
|
||||||
: 'active'
|
: 'active'
|
||||||
}`;
|
}`;
|
||||||
if (!disabled && page !== modListCurrentPage) {
|
if (!disabled && page !== modListCurrentPage) {
|
||||||
button.addEventListener('click', () => {
|
button.addEventListener('click', () => {
|
||||||
modListCurrentPage = page;
|
modListCurrentPage = page;
|
||||||
renderModList();
|
renderModList();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
elements.modListPagination.appendChild(button);
|
elements.modListPagination.appendChild(button);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (filteredMods.length > 0) {
|
if (filteredMods.length > 0) {
|
||||||
createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1);
|
createPageButton(modListCurrentPage - 1, 'Previous', modListCurrentPage === 1);
|
||||||
const maxButtons = 5;
|
const maxButtons = 5;
|
||||||
const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2));
|
const startPage = Math.max(1, modListCurrentPage - Math.floor(maxButtons / 2));
|
||||||
const endPage = Math.min(totalModPages, startPage + maxButtons - 1);
|
const endPage = Math.min(totalModPages, startPage + maxButtons - 1);
|
||||||
for (let i = startPage; i <= endPage; i++) {
|
for (let i = startPage; i <= endPage; i++) {
|
||||||
createPageButton(i, i.toString());
|
createPageButton(i, i.toString());
|
||||||
}
|
}
|
||||||
createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages);
|
createPageButton(modListCurrentPage + 1, 'Next', modListCurrentPage === totalModPages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeSearch() {
|
function closeSearch() {
|
||||||
elements.modSearch.value = '';
|
elements.modSearch.value = '';
|
||||||
@@ -2178,51 +2231,51 @@ function updateModListPagination() {
|
|||||||
|
|
||||||
document.getElementById('startBtn').addEventListener('click', async () => {
|
document.getElementById('startBtn').addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
const key = `action-start`;
|
const key = `action-start`;
|
||||||
const notification = showNotification('Starting server...', 'loading', key);
|
const notification = showNotification('Starting server...', 'loading', key);
|
||||||
await wsRequest('/start');
|
await wsRequest('/start');
|
||||||
initializeTerminal();
|
initializeTerminal();
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] }));
|
ws.send(JSON.stringify({ type: 'subscribe', endpoints: ['docker', 'docker-logs'] }));
|
||||||
const messageHandler = (event) => {
|
const messageHandler = (event) => {
|
||||||
try {
|
try {
|
||||||
const message = JSON.parse(event.data);
|
const message = JSON.parse(event.data);
|
||||||
if (message.type === 'docker') {
|
if (message.type === 'docker') {
|
||||||
state.serverStatus = message.data?.status || 'Unknown';
|
state.serverStatus = message.data?.status || 'Unknown';
|
||||||
elements.serverStatus.textContent = state.serverStatus;
|
elements.serverStatus.textContent = state.serverStatus;
|
||||||
toggleSections(state.serverStatus);
|
toggleSections(state.serverStatus);
|
||||||
if (message.data?.status.toLowerCase() === 'running') {
|
if (message.data?.status.toLowerCase() === 'running') {
|
||||||
updateNotification(notification, 'Server started successfully', 'success', key);
|
updateNotification(notification, 'Server started successfully', 'success', key);
|
||||||
// Ensure restart button is enabled
|
// Ensure restart button is enabled
|
||||||
if (elements.restartBtn) {
|
if (elements.restartBtn) {
|
||||||
elements.restartBtn.disabled = false;
|
elements.restartBtn.disabled = false;
|
||||||
elements.restartBtn.classList.remove('disabled-btn');
|
elements.restartBtn.classList.remove('disabled-btn');
|
||||||
}
|
|
||||||
ws.removeEventListener('message', messageHandler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error parsing WebSocket message:', error);
|
|
||||||
}
|
}
|
||||||
};
|
ws.removeEventListener('message', messageHandler);
|
||||||
ws.addEventListener('message', messageHandler);
|
}
|
||||||
setTimeout(() => {
|
}
|
||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
} catch (error) {
|
||||||
ws.removeEventListener('message', messageHandler);
|
console.error('Error parsing WebSocket message:', error);
|
||||||
if (state.serverStatus.toLowerCase() !== 'running') {
|
}
|
||||||
updateNotification(notification, 'Failed to start server. Please try again.', 'error', key);
|
};
|
||||||
toggleSections(state.serverStatus);
|
ws.addEventListener('message', messageHandler);
|
||||||
}
|
setTimeout(() => {
|
||||||
}
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
}, 30000);
|
ws.removeEventListener('message', messageHandler);
|
||||||
} else {
|
if (state.serverStatus.toLowerCase() !== 'running') {
|
||||||
updateNotification(notification, 'Not connected to server. Please log in.', 'error', key);
|
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) {
|
} catch (error) {
|
||||||
console.error('Start server error:', error);
|
console.error('Start server error:', error);
|
||||||
showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error');
|
showNotification(`Failed to start server: ${error.message}`, 'error', 'start-error');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
document.getElementById('stopBtn').addEventListener('click', async () => {
|
document.getElementById('stopBtn').addEventListener('click', async () => {
|
||||||
@@ -2396,40 +2449,40 @@ function updateModListPagination() {
|
|||||||
window.showNotification = showNotification;
|
window.showNotification = showNotification;
|
||||||
|
|
||||||
// Add this at the end of the document.addEventListener('DOMContentLoaded', ...) block
|
// Add this at the end of the document.addEventListener('DOMContentLoaded', ...) block
|
||||||
function applyResponsiveStyles() {
|
function applyResponsiveStyles() {
|
||||||
const sections = document.querySelectorAll('.section-bg');
|
const sections = document.querySelectorAll('.section-bg');
|
||||||
sections.forEach(section => {
|
sections.forEach(section => {
|
||||||
section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem';
|
section.style.padding = window.innerWidth <= 640 ? '1rem' : window.innerWidth <= 768 ? '1.5rem' : '2rem';
|
||||||
section.style.maxWidth = '100%';
|
section.style.maxWidth = '100%';
|
||||||
section.style.overflowX = 'hidden';
|
section.style.overflowX = 'hidden';
|
||||||
});
|
});
|
||||||
|
|
||||||
const iframes = document.querySelectorAll('#sftpIframe');
|
const iframes = document.querySelectorAll('#sftpIframe');
|
||||||
iframes.forEach(iframe => {
|
iframes.forEach(iframe => {
|
||||||
iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px';
|
iframe.style.height = window.innerWidth <= 640 ? '300px' : window.innerWidth <= 768 ? '400px' : '650px';
|
||||||
iframe.style.minHeight = iframe.style.height;
|
iframe.style.minHeight = iframe.style.height;
|
||||||
iframe.style.width = '100%';
|
iframe.style.width = '100%';
|
||||||
iframe.style.maxWidth = '100%';
|
iframe.style.maxWidth = '100%';
|
||||||
});
|
});
|
||||||
|
|
||||||
const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter');
|
const canvases = document.querySelectorAll('#memoryMeter, #cpuMeter');
|
||||||
canvases.forEach(canvas => {
|
canvases.forEach(canvas => {
|
||||||
canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px';
|
canvas.style.width = window.innerWidth <= 640 ? '80px' : window.innerWidth <= 768 ? '100px' : '150px';
|
||||||
canvas.style.height = canvas.style.width;
|
canvas.style.height = canvas.style.width;
|
||||||
});
|
});
|
||||||
|
|
||||||
const terminals = document.querySelectorAll('#dockerLogsTerminal');
|
const terminals = document.querySelectorAll('#dockerLogsTerminal');
|
||||||
terminals.forEach(terminal => {
|
terminals.forEach(terminal => {
|
||||||
terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
|
terminal.style.maxHeight = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
|
||||||
});
|
});
|
||||||
|
|
||||||
const consoles = document.querySelectorAll('#consoleOutput');
|
const consoles = document.querySelectorAll('#consoleOutput');
|
||||||
consoles.forEach(console => {
|
consoles.forEach(console => {
|
||||||
console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
|
console.style.height = window.innerWidth <= 640 ? '7rem' : window.innerWidth <= 768 ? '8rem' : '12rem';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', applyResponsiveStyles);
|
window.addEventListener('resize', applyResponsiveStyles);
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
@@ -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');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
Reference in New Issue
Block a user