146 lines
4.6 KiB
JavaScript
146 lines
4.6 KiB
JavaScript
/**
|
|
* Shows a specific form (by ID) and hides others.
|
|
* Also clears any existing success or error messages.
|
|
*/
|
|
function showForm(formId) {
|
|
document.querySelectorAll('.form').forEach(form => {
|
|
form.classList.remove('active');
|
|
});
|
|
|
|
// Clear all existing error/success messages
|
|
document.querySelectorAll('.error, .success').forEach(msg => {
|
|
msg.textContent = '';
|
|
});
|
|
|
|
// Add slight delay for smooth CSS transition
|
|
setTimeout(() => {
|
|
document.getElementById(formId).classList.add('active');
|
|
}, 100);
|
|
}
|
|
|
|
/**
|
|
* Displays a message in a specified element with optional success styling.
|
|
*/
|
|
function showMessage(elementId, message, isSuccess = false) {
|
|
const element = document.getElementById(elementId);
|
|
element.textContent = message;
|
|
element.className = isSuccess ? 'success' : 'error';
|
|
}
|
|
|
|
/**
|
|
* Sets loading state for a button (e.g., during form submission).
|
|
* Disables the button and clears the text when loading, restores after.
|
|
*/
|
|
function setButtonLoading(button, isLoading) {
|
|
if (isLoading) {
|
|
button.classList.add('loading');
|
|
button.disabled = true;
|
|
button.textContent = '';
|
|
} else {
|
|
button.classList.remove('loading');
|
|
button.disabled = false;
|
|
button.textContent = button.getAttribute('data-original-text') || 'Submit';
|
|
}
|
|
}
|
|
|
|
// Initialize when the DOM is fully loaded
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
/**
|
|
* Store original button texts (used to restore text after loading).
|
|
*/
|
|
document.querySelectorAll('button[type="submit"]').forEach(btn => {
|
|
btn.setAttribute('data-original-text', btn.textContent);
|
|
});
|
|
|
|
/**
|
|
* Handles admin login form submission.
|
|
* Sends login data to server and displays result or error messages.
|
|
*/
|
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
const submitBtn = e.target.querySelector('button[type="submit"]');
|
|
setButtonLoading(submitBtn, true);
|
|
|
|
const username = document.getElementById('loginUsername').value;
|
|
const password = document.getElementById('loginPassword').value;
|
|
|
|
try {
|
|
const response = await fetch('/admin/login', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({ username, password })
|
|
});
|
|
|
|
if (response.ok) {
|
|
showMessage('loginMessage', 'Login successful! Redirecting...', true);
|
|
setTimeout(() => {
|
|
window.location.href = '/';
|
|
}, 1500);
|
|
} else {
|
|
const data = await response.json();
|
|
showMessage('loginMessage', data.detail || 'Login failed');
|
|
}
|
|
} catch (error) {
|
|
showMessage('loginMessage', 'An error occurred');
|
|
} finally {
|
|
setButtonLoading(submitBtn, false);
|
|
submitBtn.textContent = 'Login';
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Adds a ripple click effect to all buttons.
|
|
* Creates a circle animation where the button is clicked.
|
|
*/
|
|
document.querySelectorAll('button').forEach(button => {
|
|
button.addEventListener('click', function(e) {
|
|
const ripple = document.createElement('div');
|
|
const rect = this.getBoundingClientRect();
|
|
const size = Math.max(rect.width, rect.height);
|
|
const x = e.clientX - rect.left - size / 2;
|
|
const y = e.clientY - rect.top - size / 2;
|
|
|
|
ripple.style.cssText = `
|
|
position: absolute;
|
|
width: ${size}px;
|
|
height: ${size}px;
|
|
background: rgba(255,255,255,0.3);
|
|
border-radius: 50%;
|
|
transform: scale(0);
|
|
left: ${x}px;
|
|
top: ${y}px;
|
|
animation: ripple 0.6s ease-out;
|
|
pointer-events: none;
|
|
`;
|
|
|
|
this.appendChild(ripple);
|
|
|
|
setTimeout(() => {
|
|
ripple.remove();
|
|
}, 600);
|
|
});
|
|
});
|
|
|
|
/**
|
|
* Injects keyframe animation styles for ripple effect and ensures buttons are styled to allow overflow for the animation.
|
|
*/
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
@keyframes ripple {
|
|
to {
|
|
transform: scale(2);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
|
|
button {
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
`;
|
|
document.head.appendChild(style);
|
|
});
|