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);