mirror of
https://github.com/hwanny1128/HGZero.git
synced 2025-12-06 17:16:25 +00:00
- 가파팀 프로토타입 파일 삭제 - 가파팀 유저스토리 삭제 - 실시간 회의록 작성 플로우 설계서 추가 (Mermaid, Markdown) - 백업 및 데이터 디렉토리 추가 - AI 데이터 샘플 생성 도구 추가 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
353 lines
10 KiB
HTML
353 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ko">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>로그인 - 회의록 작성 및 공유 서비스</title>
|
|
<link rel="stylesheet" href="common.css">
|
|
<style>
|
|
/* 페이지 전용 스타일 */
|
|
body {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
min-height: 100vh;
|
|
background: linear-gradient(135deg, #00D9B1 0%, #6366F1 100%);
|
|
}
|
|
|
|
.login-card {
|
|
background-color: var(--color-white);
|
|
border-radius: var(--radius-xl);
|
|
padding: var(--spacing-10);
|
|
box-shadow: var(--shadow-lg);
|
|
width: 100%;
|
|
max-width: 480px;
|
|
margin: var(--spacing-4);
|
|
}
|
|
|
|
.login-header {
|
|
text-align: center;
|
|
margin-bottom: var(--spacing-8);
|
|
}
|
|
|
|
.login-logo {
|
|
width: 64px;
|
|
height: 64px;
|
|
margin: 0 auto var(--spacing-4);
|
|
background-color: var(--color-primary-main);
|
|
border-radius: var(--radius-lg);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 32px;
|
|
color: var(--color-white);
|
|
font-weight: var(--font-weight-bold);
|
|
}
|
|
|
|
.login-title {
|
|
font-size: var(--font-size-h2);
|
|
font-weight: var(--font-weight-bold);
|
|
color: var(--color-gray-900);
|
|
margin-bottom: var(--spacing-2);
|
|
}
|
|
|
|
.login-subtitle {
|
|
font-size: var(--font-size-body);
|
|
color: var(--color-gray-500);
|
|
}
|
|
|
|
#loginForm {
|
|
margin-bottom: var(--spacing-6);
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: var(--spacing-5);
|
|
}
|
|
|
|
.form-footer {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: var(--spacing-5);
|
|
}
|
|
|
|
.checkbox-wrapper {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: var(--spacing-2);
|
|
}
|
|
|
|
.checkbox-wrapper input[type="checkbox"] {
|
|
width: 18px;
|
|
height: 18px;
|
|
cursor: pointer;
|
|
accent-color: var(--color-primary-main);
|
|
}
|
|
|
|
.checkbox-wrapper label {
|
|
font-size: var(--font-size-body-small);
|
|
color: var(--color-gray-600);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.forgot-password {
|
|
font-size: var(--font-size-body-small);
|
|
color: var(--color-primary-main);
|
|
text-decoration: none;
|
|
transition: color var(--transition-fast);
|
|
}
|
|
|
|
.forgot-password:hover {
|
|
color: var(--color-primary-dark);
|
|
}
|
|
|
|
.login-footer {
|
|
text-align: center;
|
|
padding-top: var(--spacing-6);
|
|
border-top: 1px solid var(--color-gray-200);
|
|
}
|
|
|
|
.login-footer-text {
|
|
font-size: var(--font-size-body-small);
|
|
color: var(--color-gray-500);
|
|
}
|
|
|
|
.login-footer a {
|
|
color: var(--color-primary-main);
|
|
font-weight: var(--font-weight-medium);
|
|
text-decoration: none;
|
|
transition: color var(--transition-fast);
|
|
}
|
|
|
|
.login-footer a:hover {
|
|
color: var(--color-primary-dark);
|
|
}
|
|
|
|
/* 예시 크리덴셜 표시 */
|
|
.credential-hint {
|
|
background-color: var(--color-gray-50);
|
|
border: 1px dashed var(--color-gray-300);
|
|
border-radius: var(--radius-md);
|
|
padding: var(--spacing-3);
|
|
margin-bottom: var(--spacing-5);
|
|
font-size: var(--font-size-body-small);
|
|
color: var(--color-gray-600);
|
|
}
|
|
|
|
.credential-hint-title {
|
|
font-weight: var(--font-weight-medium);
|
|
color: var(--color-gray-700);
|
|
margin-bottom: var(--spacing-2);
|
|
}
|
|
|
|
.credential-hint code {
|
|
background-color: var(--color-gray-200);
|
|
padding: 2px 6px;
|
|
border-radius: var(--radius-sm);
|
|
font-family: 'Consolas', monospace;
|
|
font-size: var(--font-size-caption);
|
|
}
|
|
|
|
/* 반응형 */
|
|
@media (max-width: 767px) {
|
|
.login-card {
|
|
padding: var(--spacing-6);
|
|
}
|
|
|
|
.login-title {
|
|
font-size: var(--font-size-h3);
|
|
}
|
|
|
|
.form-footer {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: var(--spacing-3);
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="login-card">
|
|
<!-- 헤더 -->
|
|
<div class="login-header">
|
|
<div class="login-logo">M</div>
|
|
<h1 class="login-title">회의록 서비스</h1>
|
|
<p class="login-subtitle">스마트한 협업의 시작</p>
|
|
</div>
|
|
|
|
<!-- 예시 크리덴셜 (프로토타입용) -->
|
|
<div class="credential-hint">
|
|
<div class="credential-hint-title">📝 테스트 계정</div>
|
|
<div>이메일: <code>test@example.com</code></div>
|
|
<div>비밀번호: <code>password123</code></div>
|
|
</div>
|
|
|
|
<!-- 로그인 폼 -->
|
|
<form id="loginForm">
|
|
<div class="form-group">
|
|
<label for="email" class="form-label">이메일</label>
|
|
<input
|
|
type="email"
|
|
id="email"
|
|
class="form-input"
|
|
placeholder="example@company.com"
|
|
required
|
|
autocomplete="email"
|
|
>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label for="password" class="form-label">비밀번호</label>
|
|
<input
|
|
type="password"
|
|
id="password"
|
|
class="form-input"
|
|
placeholder="비밀번호를 입력하세요"
|
|
required
|
|
autocomplete="current-password"
|
|
>
|
|
</div>
|
|
|
|
<div class="form-footer">
|
|
<div class="checkbox-wrapper">
|
|
<input type="checkbox" id="rememberMe">
|
|
<label for="rememberMe">로그인 상태 유지</label>
|
|
</div>
|
|
<a href="#" class="forgot-password">비밀번호 찾기</a>
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-primary" style="width: 100%;">
|
|
로그인
|
|
</button>
|
|
</form>
|
|
|
|
<!-- 푸터 -->
|
|
<div class="login-footer">
|
|
<p class="login-footer-text">
|
|
아직 계정이 없으신가요? <a href="#">회원가입</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- JavaScript -->
|
|
<script src="common.js"></script>
|
|
<script>
|
|
// 로그인 폼 처리
|
|
const loginForm = document.getElementById('loginForm');
|
|
const emailInput = document.getElementById('email');
|
|
const passwordInput = document.getElementById('password');
|
|
const rememberMeCheckbox = document.getElementById('rememberMe');
|
|
|
|
// 페이지 로드 시 저장된 이메일 불러오기
|
|
MeetingApp.ready(() => {
|
|
const savedEmail = MeetingApp.Storage.get('savedEmail');
|
|
if (savedEmail) {
|
|
emailInput.value = savedEmail;
|
|
rememberMeCheckbox.checked = true;
|
|
}
|
|
});
|
|
|
|
// 폼 제출 핸들러
|
|
loginForm.addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
|
|
// 에러 초기화
|
|
MeetingApp.Validator.clearError(emailInput);
|
|
MeetingApp.Validator.clearError(passwordInput);
|
|
|
|
const email = emailInput.value.trim();
|
|
const password = passwordInput.value.trim();
|
|
|
|
// 유효성 검사
|
|
let isValid = true;
|
|
|
|
if (!MeetingApp.Validator.required(email)) {
|
|
MeetingApp.Validator.showError(emailInput, '이메일을 입력해주세요.');
|
|
isValid = false;
|
|
} else if (!MeetingApp.Validator.isEmail(email)) {
|
|
MeetingApp.Validator.showError(emailInput, '올바른 이메일 형식이 아닙니다.');
|
|
isValid = false;
|
|
}
|
|
|
|
if (!MeetingApp.Validator.required(password)) {
|
|
MeetingApp.Validator.showError(passwordInput, '비밀번호를 입력해주세요.');
|
|
isValid = false;
|
|
} else if (!MeetingApp.Validator.minLength(password, 6)) {
|
|
MeetingApp.Validator.showError(passwordInput, '비밀번호는 최소 6자 이상이어야 합니다.');
|
|
isValid = false;
|
|
}
|
|
|
|
if (!isValid) return;
|
|
|
|
// 로딩 표시
|
|
const submitButton = loginForm.querySelector('button[type="submit"]');
|
|
const originalText = submitButton.textContent;
|
|
submitButton.disabled = true;
|
|
submitButton.innerHTML = '<div class="spinner spinner-sm" style="border-color: white; border-top-color: transparent;"></div>';
|
|
|
|
try {
|
|
// API 호출 시뮬레이션
|
|
await MeetingApp.API.post('/api/auth/login', { email, password });
|
|
|
|
// 로그인 성공 시뮬레이션 (테스트 계정 체크)
|
|
if (email === 'test@example.com' && password === 'password123') {
|
|
// 사용자 정보 저장
|
|
MeetingApp.Storage.set('currentUser', {
|
|
id: 'user-001',
|
|
name: '김민준',
|
|
email: email,
|
|
avatar: 'https://ui-avatars.com/api/?name=김민준&background=00D9B1&color=fff',
|
|
role: 'user'
|
|
});
|
|
|
|
// 로그인 상태 유지 체크
|
|
if (rememberMeCheckbox.checked) {
|
|
MeetingApp.Storage.set('savedEmail', email);
|
|
MeetingApp.Storage.set('rememberMe', true);
|
|
} else {
|
|
MeetingApp.Storage.remove('savedEmail');
|
|
MeetingApp.Storage.remove('rememberMe');
|
|
}
|
|
|
|
// JWT 토큰 시뮬레이션
|
|
MeetingApp.Storage.set('authToken', 'mock-jwt-token-' + Date.now());
|
|
|
|
// 성공 토스트
|
|
MeetingApp.Toast.success('로그인에 성공했습니다!');
|
|
|
|
// 대시보드로 이동
|
|
setTimeout(() => {
|
|
window.location.href = '02-대시보드.html';
|
|
}, 1000);
|
|
|
|
} else {
|
|
// 로그인 실패
|
|
MeetingApp.Toast.error('이메일 또는 비밀번호가 올바르지 않습니다.');
|
|
submitButton.disabled = false;
|
|
submitButton.textContent = originalText;
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('Login error:', error);
|
|
MeetingApp.Toast.error('로그인 중 오류가 발생했습니다. 다시 시도해주세요.');
|
|
submitButton.disabled = false;
|
|
submitButton.textContent = originalText;
|
|
}
|
|
});
|
|
|
|
// 비밀번호 찾기 (프로토타입용)
|
|
document.querySelector('.forgot-password').addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
MeetingApp.Toast.info('비밀번호 찾기 기능은 준비 중입니다.');
|
|
});
|
|
|
|
// 회원가입 (프로토타입용)
|
|
document.querySelector('.login-footer a').addEventListener('click', (e) => {
|
|
e.preventDefault();
|
|
MeetingApp.Toast.info('회원가입 기능은 준비 중입니다.');
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|