dramaling-vocab-learning/docs/02_design/component-library/pages/login-page.html

411 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登入頁面 - Drama Ling</title>
<link rel="stylesheet" href="../../design-system/tokens/design-tokens.css">
<link rel="stylesheet" href="../assets/styles/base.css">
<link rel="stylesheet" href="../assets/styles/components.css">
<style>
body {
background: linear-gradient(135deg, var(--background-primary), var(--background-secondary));
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: var(--space-4);
}
.login-container {
width: 100%;
max-width: 420px;
}
.login-card {
background: var(--card-background);
border-radius: var(--radius-2xl);
padding: var(--space-10);
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
border: 1px solid var(--divider);
}
.login-logo {
text-align: center;
margin-bottom: var(--space-8);
}
.login-logo-icon {
font-size: 48px;
margin-bottom: var(--space-4);
}
.login-title {
font-size: var(--text-2xl);
font-weight: 700;
color: var(--text-primary);
margin: 0 0 var(--space-2) 0;
}
.login-subtitle {
font-size: var(--text-sm);
color: var(--text-secondary);
}
.login-form {
margin-bottom: var(--space-6);
}
.login-divider {
display: flex;
align-items: center;
margin: var(--space-6) 0;
color: var(--text-tertiary);
font-size: var(--text-sm);
}
.login-divider::before,
.login-divider::after {
content: '';
flex: 1;
height: 1px;
background: var(--divider);
}
.login-divider span {
padding: 0 var(--space-4);
}
.social-login {
display: flex;
gap: var(--space-3);
margin-bottom: var(--space-6);
}
.social-button {
flex: 1;
padding: var(--space-3);
background: var(--background-secondary);
border: 1px solid var(--divider);
border-radius: var(--radius-lg);
color: var(--text-primary);
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
gap: var(--space-2);
font-size: var(--text-sm);
font-weight: 500;
}
.social-button:hover {
background: var(--background-primary);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.remember-forgot {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-6);
font-size: var(--text-sm);
}
.checkbox-wrapper {
display: flex;
align-items: center;
gap: var(--space-2);
}
.checkbox-wrapper input {
width: 18px;
height: 18px;
cursor: pointer;
}
.forgot-link {
color: var(--primary-teal);
text-decoration: none;
transition: color 0.2s ease;
}
.forgot-link:hover {
color: var(--primary-teal-light);
text-decoration: underline;
}
.login-button {
width: 100%;
padding: var(--space-4);
font-size: var(--text-base);
}
.signup-prompt {
text-align: center;
font-size: var(--text-sm);
color: var(--text-secondary);
}
.signup-link {
color: var(--primary-teal);
text-decoration: none;
font-weight: 600;
transition: color 0.2s ease;
}
.signup-link:hover {
color: var(--primary-teal-light);
text-decoration: underline;
}
.back-link {
position: absolute;
top: var(--space-4);
left: var(--space-4);
color: var(--text-secondary);
text-decoration: none;
display: flex;
align-items: center;
gap: var(--space-2);
font-size: var(--text-sm);
transition: color 0.2s ease;
}
.back-link:hover {
color: var(--text-primary);
}
/* 響應式調整 */
@media (max-width: 480px) {
.login-card {
padding: var(--space-6);
}
.social-login {
flex-direction: column;
}
}
/* 錯誤訊息動畫 */
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-2px); }
20%, 40%, 60%, 80% { transform: translateX(2px); }
}
.shake {
animation: shake 0.5s ease;
}
</style>
</head>
<body>
<!-- 返回連結 -->
<a href="../index.html" class="back-link">
← 返回元件庫
</a>
<!-- 登入容器 -->
<div class="login-container">
<div class="login-card">
<!-- Logo 和標題 -->
<div class="login-logo">
<div class="login-logo-icon">🎭</div>
<h1 class="login-title">歡迎回來</h1>
<p class="login-subtitle">登入以繼續你的學習旅程</p>
</div>
<!-- 登入表單 -->
<form class="login-form" onsubmit="handleLogin(event)">
<div class="input-group">
<label class="input-label" for="email">電子郵件</label>
<input
type="email"
id="email"
class="input-field"
placeholder="example@email.com"
required
>
</div>
<div class="input-group">
<label class="input-label" for="password">密碼</label>
<input
type="password"
id="password"
class="input-field"
placeholder="請輸入密碼"
required
>
</div>
<div class="remember-forgot">
<div class="checkbox-wrapper">
<input type="checkbox" id="remember">
<label for="remember">記住我</label>
</div>
<a href="#" class="forgot-link">忘記密碼?</a>
</div>
<button type="submit" class="btn btn-primary login-button">
登入
</button>
</form>
<!-- 分隔線 -->
<div class="login-divider">
<span>或使用其他方式登入</span>
</div>
<!-- 社交登入 -->
<div class="social-login">
<button class="social-button" onclick="socialLogin('google')">
<span>🔍</span>
Google
</button>
<button class="social-button" onclick="socialLogin('facebook')">
<span>📘</span>
Facebook
</button>
<button class="social-button" onclick="socialLogin('apple')">
<span>🍎</span>
Apple
</button>
</div>
<!-- 註冊提示 -->
<div class="signup-prompt">
還沒有帳戶?
<a href="#" class="signup-link">立即註冊</a>
</div>
</div>
<!-- 成功訊息(預設隱藏) -->
<div id="successAlert" class="alert alert-success" style="display: none; position: fixed; top: 20px; right: 20px; min-width: 300px;">
<span class="alert-icon"></span>
<div class="alert-content">
<div class="alert-title">登入成功!</div>
<div class="alert-message">正在跳轉到學習頁面...</div>
</div>
</div>
<!-- 錯誤訊息(預設隱藏) -->
<div id="errorAlert" class="alert alert-error" style="display: none; position: fixed; top: 20px; right: 20px; min-width: 300px;">
<span class="alert-icon"></span>
<div class="alert-content">
<div class="alert-title">登入失敗</div>
<div class="alert-message">請檢查你的電子郵件和密碼</div>
</div>
</div>
</div>
<script>
// 處理登入
function handleLogin(event) {
event.preventDefault();
const email = document.getElementById('email').value;
const password = document.getElementById('password').value;
// 模擬登入驗證
if (email && password) {
// 顯示成功訊息
const successAlert = document.getElementById('successAlert');
successAlert.style.display = 'flex';
successAlert.classList.add('alert');
// 2秒後隱藏訊息
setTimeout(() => {
successAlert.style.display = 'none';
// 這裡可以跳轉到其他頁面
// window.location.href = '/dashboard';
}, 2000);
} else {
// 顯示錯誤訊息
const errorAlert = document.getElementById('errorAlert');
const loginCard = document.querySelector('.login-card');
errorAlert.style.display = 'flex';
loginCard.classList.add('shake');
// 標記錯誤的輸入框
if (!email) {
document.getElementById('email').classList.add('error');
}
if (!password) {
document.getElementById('password').classList.add('error');
}
// 3秒後隱藏錯誤訊息
setTimeout(() => {
errorAlert.style.display = 'none';
loginCard.classList.remove('shake');
}, 3000);
}
}
// 處理社交登入
function socialLogin(provider) {
console.log('Logging in with:', provider);
// 顯示載入狀態
const button = event.target.closest('.social-button');
const originalContent = button.innerHTML;
button.innerHTML = '<div class="spinner spinner-sm" style="margin: 0 auto;"></div>';
button.disabled = true;
// 模擬登入過程
setTimeout(() => {
button.innerHTML = originalContent;
button.disabled = false;
// 顯示成功訊息
const successAlert = document.getElementById('successAlert');
successAlert.style.display = 'flex';
setTimeout(() => {
successAlert.style.display = 'none';
}, 2000);
}, 1500);
}
// 清除錯誤狀態
document.querySelectorAll('.input-field').forEach(input => {
input.addEventListener('focus', function() {
this.classList.remove('error');
});
});
// 密碼顯示/隱藏切換(可選功能)
const passwordInput = document.getElementById('password');
const togglePassword = document.createElement('button');
togglePassword.type = 'button';
togglePassword.style.cssText = `
position: absolute;
right: var(--space-4);
top: 38px;
background: transparent;
border: none;
color: var(--text-tertiary);
cursor: pointer;
padding: var(--space-1);
`;
togglePassword.innerHTML = '👁️';
togglePassword.onclick = function() {
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
this.innerHTML = '🙈';
} else {
passwordInput.type = 'password';
this.innerHTML = '👁️';
}
};
// 將切換按鈕加入密碼輸入框
const passwordGroup = passwordInput.parentElement;
passwordGroup.style.position = 'relative';
passwordGroup.appendChild(togglePassword);
</script>
</body>
</html>