Spaces:
Running
Running
File size: 4,727 Bytes
6ee6051 e018666 a20d07c 6ee6051 e018666 6ee6051 e018666 6ee6051 a20d07c 6ee6051 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
// Login Form Handling
document.addEventListener('DOMContentLoaded', function() {
const loginForm = document.getElementById('loginForm');
const loginButton = document.getElementById('loginButton');
const loadingOverlay = document.getElementById('loadingOverlay');
const successAnimation = document.getElementById('successAnimation');
// Add ripple effect to button
loginButton.addEventListener('click', function(e) {
if (loginForm.checkValidity()) {
createRipple(e);
}
});
// Form submission handler
loginForm.addEventListener('submit', function(e) {
e.preventDefault();
if (loginForm.checkValidity()) {
// Show loading animation
loadingOverlay.classList.remove('hidden');
// Simulate API call
setTimeout(() => {
loadingOverlay.classList.add('hidden');
successAnimation.classList.remove('hidden');
// Simulate successful login and redirect
setTimeout(() => {
successAnimation.classList.add('hidden');
// In a real application, you would redirect to the dashboard
console.log('登入成功!正在跳轉到儀表板...');
// window.location.href = '/dashboard';
}, 1500);
}, 2000);
}
});
// Input field animations
const inputs = document.querySelectorAll('input');
inputs.forEach(input => {
input.addEventListener('focus', function() {
this.parentElement.classList.add('input-focused');
});
input.addEventListener('blur', function() {
this.parentElement.classList.remove('input-focused');
});
});
// Add keyboard navigation
document.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && loginForm.checkValidity()) {
loginForm.dispatchEvent(new Event('submit'));
}
});
});
// Ripple Effect Function
function createRipple(event) {
const button = event.currentTarget;
const circle = document.createElement('span');
const diameter = Math.max(button.clientWidth, button.clientHeight);
const radius = diameter / 2;
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - button.getBoundingClientRect().left - radius}px`;
circle.style.top = `${event.clientY - button.getBoundingClientRect().top - radius}px`;
circle.classList.add('ripple');
const ripple = button.getElementsByClassName('ripple')[0];
if (ripple) {
ripple.remove();
}
button.appendChild(circle);
}
// Add ripple styles dynamically
const style = document.createElement('style');
style.textContent = `
.ripple {
position: absolute;
border-radius: 50%;
background: rgba(255, 255, 255, 0.6);
transform: scale(0);
animation: ripple-animation 0.6s linear;
}
@keyframes ripple-animation {
to {
transform: scale(4);
opacity: 0;
}
}
.input-focused .input-highlight {
width: 100%;
}
`;
document.head.appendChild(style);
// Form validation enhancements
function validateForm() {
const username = document.getElementById('username');
const password = document.getElementById('password');
let isValid = true;
if (!username.value.trim()) {
showError(username, '用戶名是必填項');
isValid = false;
}
if (!password.value.trim()) {
showError(password, '密碼是必填項');
isValid = false;
}
return isValid;
}
function showError(input, message) {
const parent = input.parentElement;
const errorDiv = document.createElement('div');
errorDiv.className = 'text-red-300 text-xs mt-1';
errorDiv.textContent = message;
// Remove existing error
const existingError = parent.querySelector('.text-red-300');
if (existingError) {
existingError.remove();
}
parent.appendChild(errorDiv);
// Add shake animation
input.classList.add('animate-shake');
setTimeout(() => {
input.classList.remove('animate-shake');
}, 500);
}
// Add shake animation for errors
const shakeStyle = document.createElement('style');
shakeStyle.textContent = `
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-5px); }
20%, 40%, 60%, 80% { transform: translateX(5px); }
}
.animate-shake {
animation: shake 0.5s ease-in-out;
}
`;
document.head.appendChild(shakeStyle); |