Fix: 업로드 및 API 연결 문제 해결

- FastAPI 라우터에서 슬래시 문제로 인한 307 리다이렉트 수정
- Nginx 프록시 설정에서 경로 중복 문제 해결
- 계정 관리 시스템 구현 (로그인, 사용자 관리, 권한 설정)
- 노트북 연결 기능 수정 (notebook_id 필드 추가)
- 메모 트리 UI 개선 (수평 레이아웃, 드래그 기능 제거)
- 헤더 UI 개선 및 고정 위치 설정
- 백업/복원 스크립트 추가
- PDF 미리보기 토큰 인증 지원
This commit is contained in:
Hyungi Ahn
2025-09-03 15:58:10 +09:00
parent d4b10b16b1
commit 6e01dbdeb3
47 changed files with 3672 additions and 398 deletions

View File

@@ -1,5 +1,5 @@
<!-- 공통 헤더 컴포넌트 -->
<header class="header-modern fade-in">
<header class="header-modern fade-in fixed top-0 left-0 right-0 z-50">
<div class="max-w-full mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between items-center h-16">
<!-- 로고 -->
@@ -8,107 +8,230 @@
<h1 class="text-xl font-bold text-gray-900">Document Server</h1>
</div>
<!-- 메인 네비게이션 - 3가지 기능 -->
<nav class="flex space-x-6">
<!-- 문서 관리 시스템 -->
<!-- 메인 네비게이션 -->
<nav class="hidden md:flex items-center space-x-1 relative">
<!-- 문서 관리 -->
<div class="relative" x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false">
<a href="index.html" class="nav-link" id="doc-nav-link">
<i class="fas fa-folder-open"></i>
<button class="nav-link-modern" id="doc-nav-link">
<i class="fas fa-folder-open text-blue-600"></i>
<span>문서 관리</span>
<i class="fas fa-chevron-down text-xs ml-1"></i>
</a>
<div x-show="open" x-transition class="nav-dropdown">
<a href="index.html" class="nav-dropdown-item" id="index-nav-item">
<i class="fas fa-th-large mr-2 text-blue-500"></i>문서 관리
</a>
<a href="pdf-manager.html" class="nav-dropdown-item" id="pdf-manager-nav-item">
<i class="fas fa-file-pdf mr-2 text-red-500"></i>PDF 관리
</a>
<i class="fas fa-chevron-down text-xs ml-1 transition-transform duration-200" :class="{ 'rotate-180': open }"></i>
</button>
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0 transform scale-95" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-95" class="nav-dropdown-wide">
<div class="grid grid-cols-2 gap-2">
<a href="index.html" class="nav-dropdown-card" id="index-nav-item">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
<i class="fas fa-th-large text-blue-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900">문서 관리</div>
<div class="text-xs text-gray-500">HTML 문서 관리</div>
</div>
</div>
</a>
<a href="pdf-manager.html" class="nav-dropdown-card" id="pdf-manager-nav-item">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-red-100 rounded-lg flex items-center justify-center">
<i class="fas fa-file-pdf text-red-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900">PDF 관리</div>
<div class="text-xs text-gray-500">PDF 파일 관리</div>
</div>
</div>
</a>
</div>
</div>
</div>
<!-- 통합 검색 -->
<a href="search.html" class="nav-link" id="search-nav-link">
<i class="fas fa-search"></i>
<a href="search.html" class="nav-link-modern" id="search-nav-link">
<i class="fas fa-search text-green-600"></i>
<span>통합 검색</span>
</a>
<!-- 소설 관리 시스템 -->
<!-- 소설 관리 -->
<div class="relative" x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false">
<a href="memo-tree.html" class="nav-link" id="novel-nav-link">
<i class="fas fa-feather-alt"></i>
<button class="nav-link-modern" id="novel-nav-link">
<i class="fas fa-feather-alt text-purple-600"></i>
<span>소설 관리</span>
<i class="fas fa-chevron-down text-xs ml-1"></i>
</a>
<div x-show="open" x-transition class="nav-dropdown">
<a href="memo-tree.html" class="nav-dropdown-item" id="memo-tree-nav-item">
<i class="fas fa-sitemap mr-2 text-purple-500"></i>트리 뷰
</a>
<a href="story-view.html" class="nav-dropdown-item" id="story-view-nav-item">
<i class="fas fa-book-open mr-2 text-orange-500"></i>스토리 뷰
</a>
<i class="fas fa-chevron-down text-xs ml-1 transition-transform duration-200" :class="{ 'rotate-180': open }"></i>
</button>
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0 transform scale-95" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-95" class="nav-dropdown-wide">
<div class="grid grid-cols-2 gap-2">
<a href="memo-tree.html" class="nav-dropdown-card" id="memo-tree-nav-item">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
<i class="fas fa-sitemap text-purple-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900">트리 뷰</div>
<div class="text-xs text-gray-500">계층형 메모 관리</div>
</div>
</div>
</a>
<a href="story-view.html" class="nav-dropdown-card" id="story-view-nav-item">
<div class="flex items-center space-x-3">
<div class="w-10 h-10 bg-orange-100 rounded-lg flex items-center justify-center">
<i class="fas fa-book-open text-orange-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900">스토리 뷰</div>
<div class="text-xs text-gray-500">스토리 읽기 모드</div>
</div>
</div>
</a>
</div>
</div>
</div>
<!-- 노트 관리 시스템 -->
<!-- 노트 관리 -->
<div class="relative" x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false">
<a href="notes.html" class="nav-link" id="notes-nav-link">
<i class="fas fa-sticky-note"></i>
<button class="nav-link-modern" id="notes-nav-link">
<i class="fas fa-sticky-note text-yellow-600"></i>
<span>노트 관리</span>
<i class="fas fa-chevron-down text-xs ml-1"></i>
</a>
<div x-show="open" x-transition class="nav-dropdown">
<a href="notebooks.html" class="nav-dropdown-item" id="notebooks-nav-item">
<i class="fas fa-book mr-2 text-blue-500"></i>노트북 관리
</a>
<a href="notes.html" class="nav-dropdown-item" id="notes-list-nav-item">
<i class="fas fa-list mr-2 text-green-500"></i>노트 목록
</a>
<a href="note-editor.html" class="nav-dropdown-item" id="note-editor-nav-item">
<i class="fas fa-edit mr-2 text-purple-500"></i>새 노트 작성
</a>
<i class="fas fa-chevron-down text-xs ml-1 transition-transform duration-200" :class="{ 'rotate-180': open }"></i>
</button>
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0 transform scale-95" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-95" class="nav-dropdown-wide">
<div class="grid grid-cols-3 gap-2">
<a href="notebooks.html" class="nav-dropdown-card" id="notebooks-nav-item">
<div class="flex flex-col items-center text-center space-y-2">
<div class="w-10 h-10 bg-blue-100 rounded-lg flex items-center justify-center">
<i class="fas fa-book text-blue-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900 text-sm">노트북 관리</div>
<div class="text-xs text-gray-500">그룹 관리</div>
</div>
</div>
</a>
<a href="notes.html" class="nav-dropdown-card" id="notes-list-nav-item">
<div class="flex flex-col items-center text-center space-y-2">
<div class="w-10 h-10 bg-green-100 rounded-lg flex items-center justify-center">
<i class="fas fa-list text-green-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900 text-sm">노트 목록</div>
<div class="text-xs text-gray-500">전체 보기</div>
</div>
</div>
</a>
<a href="note-editor.html" class="nav-dropdown-card" id="note-editor-nav-item">
<div class="flex flex-col items-center text-center space-y-2">
<div class="w-10 h-10 bg-purple-100 rounded-lg flex items-center justify-center">
<i class="fas fa-edit text-purple-600"></i>
</div>
<div>
<div class="font-semibold text-gray-900 text-sm">새 노트 작성</div>
<div class="text-xs text-gray-500">노트 만들기</div>
</div>
</div>
</a>
</div>
</div>
</div>
</nav>
<!-- 모바일 메뉴 버튼 -->
<div class="md:hidden">
<button x-data="{ open: false }" @click="open = !open" class="mobile-menu-btn">
<i class="fas fa-bars"></i>
</button>
</div>
<!-- 사용자 메뉴 -->
<div class="flex items-center space-x-4">
<!-- PDF 관리 버튼 -->
<a href="pdf-manager.html" class="nav-link" title="PDF 관리">
<i class="fas fa-file-pdf text-red-500"></i>
<span class="hidden sm:inline">PDF</span>
</a>
<!-- 언어 전환 버튼 -->
<div class="relative" x-data="{ open: false }" @mouseenter="open = true" @mouseleave="open = false">
<button class="nav-link" title="언어 설정">
<i class="fas fa-globe"></i>
<span class="hidden sm:inline">한국어</span>
<i class="fas fa-chevron-down text-xs ml-1"></i>
</button>
<div x-show="open" x-transition class="nav-dropdown">
<button class="nav-dropdown-item" onclick="handleLanguageChange('ko')">
<i class="fas fa-flag mr-2 text-blue-500"></i>한국어
</button>
<button class="nav-dropdown-item" onclick="handleLanguageChange('en')">
<i class="fas fa-flag mr-2 text-red-500"></i>English
</button>
</div>
</div>
<!-- 로그인/로그아웃 -->
<!-- 사용자 계정 메뉴 -->
<div class="flex items-center space-x-3" id="user-menu">
<!-- 로그인된 사용자 -->
<div class="hidden" id="logged-in-menu">
<span class="text-sm text-gray-600" id="user-name">User</span>
<button onclick="handleLogout()" class="btn-improved btn-secondary-improved text-sm">
<i class="fas fa-sign-out-alt"></i> 로그아웃
<!-- 로그인된 사용자 드롭다운 -->
<div class="hidden relative" id="logged-in-menu" x-data="{ open: false }" @click.away="open = false">
<button @click="open = !open" class="user-menu-btn">
<div class="w-9 h-9 bg-gradient-to-br from-blue-500 to-blue-600 rounded-full flex items-center justify-center shadow-sm">
<i class="fas fa-user text-white text-sm"></i>
</div>
<div class="hidden sm:block text-left">
<div class="text-sm font-semibold text-gray-900" id="user-name">User</div>
<div class="text-xs text-gray-500" id="user-role">사용자</div>
</div>
<i class="fas fa-chevron-down text-xs ml-1 transition-transform duration-200" :class="{ 'rotate-180': open }"></i>
</button>
<!-- 드롭다운 메뉴 -->
<div x-show="open" x-transition:enter="transition ease-out duration-150" x-transition:enter-start="opacity-0 transform scale-95" x-transition:enter-end="opacity-100 transform scale-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="opacity-100 transform scale-100" x-transition:leave-end="opacity-0 transform scale-95" class="user-dropdown">
<!-- 사용자 정보 -->
<div class="px-4 py-4 border-b border-gray-100 bg-gradient-to-r from-blue-50 to-indigo-50">
<div class="flex items-center space-x-3">
<div class="w-12 h-12 bg-gradient-to-br from-blue-500 to-blue-600 rounded-full flex items-center justify-center shadow-md">
<i class="fas fa-user text-white"></i>
</div>
<div>
<div class="font-semibold text-gray-900" id="dropdown-user-name">User</div>
<div class="text-sm text-gray-600" id="dropdown-user-email">user@example.com</div>
<div class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800 mt-1" id="dropdown-user-role">사용자</div>
</div>
</div>
</div>
<!-- 메뉴 항목들 -->
<div class="py-2">
<a href="profile.html" class="user-menu-item">
<i class="fas fa-user-edit text-blue-500"></i>
<div>
<div class="font-medium">프로필 관리</div>
<div class="text-xs text-gray-500">개인 정보 수정</div>
</div>
</a>
<a href="account-settings.html" class="user-menu-item">
<i class="fas fa-cog text-gray-500"></i>
<div>
<div class="font-medium">계정 설정</div>
<div class="text-xs text-gray-500">환경 설정 및 보안</div>
</div>
</a>
<!-- 관리자 메뉴 (관리자만 표시) -->
<div class="hidden" id="admin-menu-section">
<div class="border-t border-gray-100 my-2"></div>
<div class="px-4 py-2">
<div class="text-xs font-semibold text-gray-500 uppercase tracking-wider">관리자 메뉴</div>
</div>
<a href="user-management.html" class="user-menu-item">
<i class="fas fa-users text-indigo-500"></i>
<div>
<div class="font-medium">사용자 관리</div>
<div class="text-xs text-gray-500">계정 및 권한 관리</div>
</div>
</a>
<a href="system-settings.html" class="user-menu-item">
<i class="fas fa-server text-green-500"></i>
<div>
<div class="font-medium">시스템 설정</div>
<div class="text-xs text-gray-500">시스템 전체 설정</div>
</div>
</a>
</div>
<!-- 로그아웃 -->
<div class="border-t border-gray-100 my-2"></div>
<button onclick="handleLogout()" class="user-menu-item text-red-600 hover:bg-red-50 w-full">
<i class="fas fa-sign-out-alt text-red-500"></i>
<div>
<div class="font-medium">로그아웃</div>
<div class="text-xs text-gray-500">계정에서 로그아웃</div>
</div>
</button>
</div>
</div>
</div>
<!-- 로그인 버튼 -->
<div class="hidden" id="login-button">
<button onclick="handleLogin()" class="btn-improved btn-primary-improved">
<i class="fas fa-sign-in-alt"></i> 로그인
<div class="" id="login-button">
<button id="login-btn" class="login-btn-modern">
<i class="fas fa-sign-in-alt"></i>
<span>로그인</span>
</button>
</div>
</div>
@@ -119,35 +242,128 @@
<!-- 헤더 관련 스타일 -->
<style>
/* 네비게이션 링크 스타일 */
.nav-link {
@apply text-gray-600 hover:text-blue-600 flex items-center space-x-1 py-2 px-3 rounded-lg transition-all duration-200;
/* 모던 네비게이션 링크 스타일 */
.nav-link-modern {
@apply flex items-center space-x-2 px-4 py-2 text-sm font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50 rounded-lg transition-all duration-200 cursor-pointer;
border: 1px solid transparent;
}
.nav-link.active {
@apply text-blue-600 bg-blue-50 font-medium;
.nav-link-modern:hover {
@apply bg-gradient-to-r from-gray-50 to-gray-100 shadow-sm;
border-color: rgba(0, 0, 0, 0.05);
}
.nav-link:hover {
@apply bg-gray-50;
.nav-link-modern.active {
@apply text-blue-700 bg-blue-50 border-blue-200;
box-shadow: 0 1px 3px rgba(59, 130, 246, 0.1);
}
/* 드롭다운 메뉴 스타일 */
.nav-dropdown {
@apply absolute top-full left-0 mt-1 bg-white border border-gray-200 rounded-lg shadow-lg py-2 min-w-44 z-50;
/* 와이드 드롭다운 메뉴 스타일 */
.nav-dropdown-wide {
position: absolute !important;
top: 100% !important;
left: 50% !important;
transform: translateX(-50%) !important;
margin-top: 0.5rem !important;
z-index: 9999 !important;
min-width: 400px;
background: rgba(255, 255, 255, 0.98);
backdrop-filter: blur(15px);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: 0.75rem;
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
padding: 1rem;
pointer-events: auto;
}
.nav-dropdown-item {
@apply block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 transition-colors duration-150;
.nav-dropdown-card {
@apply block p-4 bg-white border border-gray-100 rounded-lg hover:border-gray-200 hover:shadow-md transition-all duration-200 cursor-pointer;
}
.nav-dropdown-item.active {
@apply text-blue-600 bg-blue-50 font-medium;
.nav-dropdown-card:hover {
@apply bg-gradient-to-br from-gray-50 to-blue-50 transform -translate-y-1;
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
}
.nav-dropdown-card.active {
@apply border-blue-200 bg-blue-50;
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.15);
}
/* 드롭다운 컨테이너 안정성 */
nav > div.relative {
position: relative !important;
display: inline-block !important;
}
/* 애니메이션 중 위치 고정 */
.nav-dropdown-wide[x-show] {
position: absolute !important;
top: 100% !important;
left: 50% !important;
transform: translateX(-50%) !important;
}
/* 모바일 메뉴 버튼 */
.mobile-menu-btn {
@apply p-2 text-gray-600 hover:text-gray-900 hover:bg-gray-100 rounded-lg transition-colors duration-200;
}
/* 사용자 메뉴 스타일 */
.user-menu-btn {
@apply flex items-center space-x-3 px-3 py-2 text-gray-700 hover:text-gray-900 hover:bg-gray-50 rounded-lg transition-all duration-200 cursor-pointer;
border: 1px solid transparent;
}
.user-menu-btn:hover {
@apply shadow-sm;
border-color: rgba(0, 0, 0, 0.05);
}
.user-dropdown {
@apply absolute right-0 mt-2 w-80 bg-white border border-gray-200 rounded-xl shadow-xl py-0 z-50;
backdrop-filter: blur(10px);
background: rgba(255, 255, 255, 0.98);
border: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.user-menu-item {
@apply flex items-center space-x-3 px-4 py-3 text-sm text-gray-700 hover:bg-gray-50 transition-all duration-150 cursor-pointer;
}
.user-menu-item:hover {
@apply bg-gradient-to-r from-gray-50 to-blue-50 text-gray-900;
transform: translateX(2px);
}
.user-menu-item i {
@apply w-5 h-5 flex items-center justify-center;
}
/* 로그인 버튼 모던 스타일 */
.login-btn-modern {
@apply flex items-center space-x-2 px-4 py-2 bg-gradient-to-r from-blue-600 to-blue-700 text-white font-medium rounded-lg shadow-sm hover:shadow-md transition-all duration-200;
}
.login-btn-modern:hover {
@apply from-blue-700 to-blue-800 transform -translate-y-0.5;
box-shadow: 0 10px 25px rgba(59, 130, 246, 0.3);
}
.login-btn-modern:active {
@apply transform translate-y-0;
}
/* 헤더 모던 스타일 */
.header-modern {
@apply bg-white border-b border-gray-200 shadow-sm;
@apply bg-white/95 backdrop-blur-md border-b border-gray-200/50 shadow-lg;
transition: all 0.3s ease;
}
/* 헤더 호버 효과 */
.header-modern:hover {
@apply bg-white shadow-xl;
}
/* 언어 전환 스타일 */
@@ -218,34 +434,9 @@
// 로그인 관련 함수들
window.handleLogin = () => {
console.log('🔐 handleLogin 호출됨');
// Alpine.js 컨텍스트에서 함수 찾기
const bodyElement = document.querySelector('body');
if (bodyElement && bodyElement._x_dataStack) {
const alpineData = bodyElement._x_dataStack[0];
if (alpineData && typeof alpineData.openLoginModal === 'function') {
console.log('✅ Alpine 컨텍스트에서 openLoginModal 호출');
alpineData.openLoginModal();
return;
}
if (alpineData && alpineData.showLoginModal !== undefined) {
console.log('✅ Alpine 컨텍스트에서 showLoginModal 설정');
alpineData.showLoginModal = true;
return;
}
}
// 전역 함수로 시도
if (typeof window.openLoginModal === 'function') {
console.log('✅ 전역 openLoginModal 호출');
window.openLoginModal();
return;
}
// 직접 이벤트 발생
console.log('🔄 커스텀 이벤트로 로그인 모달 열기');
document.dispatchEvent(new CustomEvent('open-login-modal'));
console.log('🔐 handleLogin 호출됨 - 로그인 페이지로 이동');
const currentUrl = encodeURIComponent(window.location.href);
window.location.href = `login.html?redirect=${currentUrl}`;
};
window.handleLogout = () => {
@@ -259,22 +450,73 @@
// 사용자 상태 업데이트 함수
window.updateUserMenu = (user) => {
console.log('🔄 updateUserMenu 호출됨:', user);
const loggedInMenu = document.getElementById('logged-in-menu');
const loginButton = document.getElementById('login-button');
const adminMenuSection = document.getElementById('admin-menu-section');
console.log('🔍 요소 찾기:', {
loggedInMenu: !!loggedInMenu,
loginButton: !!loginButton,
adminMenuSection: !!adminMenuSection
});
// 사용자 정보 요소들
const userName = document.getElementById('user-name');
const userRole = document.getElementById('user-role');
const dropdownUserName = document.getElementById('dropdown-user-name');
const dropdownUserEmail = document.getElementById('dropdown-user-email');
const dropdownUserRole = document.getElementById('dropdown-user-role');
if (user) {
// 로그인된 상태
if (loggedInMenu) loggedInMenu.classList.remove('hidden');
if (loginButton) loginButton.classList.add('hidden');
if (userName) userName.textContent = user.username || user.full_name || user.email || 'User';
console.log('✅ 사용자 로그인 상태 - UI 업데이트 시작');
if (loggedInMenu) {
loggedInMenu.classList.remove('hidden');
console.log('✅ 로그인 메뉴 표시');
}
if (loginButton) {
loginButton.classList.add('hidden');
console.log('✅ 로그인 버튼 숨김');
}
// 사용자 정보 업데이트
const displayName = user.full_name || user.email || 'User';
const roleText = getRoleText(user.role);
if (userName) userName.textContent = displayName;
if (userRole) userRole.textContent = roleText;
if (dropdownUserName) dropdownUserName.textContent = displayName;
if (dropdownUserEmail) dropdownUserEmail.textContent = user.email || '';
if (dropdownUserRole) dropdownUserRole.textContent = roleText;
// 관리자 메뉴 표시/숨김
if (adminMenuSection) {
if (user.role === 'root' || user.role === 'admin' || user.is_admin) {
adminMenuSection.classList.remove('hidden');
} else {
adminMenuSection.classList.add('hidden');
}
}
} else {
// 로그아웃된 상태
if (loggedInMenu) loggedInMenu.classList.add('hidden');
if (loginButton) loginButton.classList.remove('hidden');
if (adminMenuSection) adminMenuSection.classList.add('hidden');
}
};
// 역할 텍스트 변환 함수
function getRoleText(role) {
const roleMap = {
'root': '시스템 관리자',
'admin': '관리자',
'user': '사용자'
};
return roleMap[role] || '사용자';
}
// 언어 토글 함수 (전역)
// 통합 언어 변경 함수
window.handleLanguageChange = (lang) => {
@@ -335,9 +577,27 @@
// 향후 다국어 지원 시 구현
};
// 헤더 로드 완료 후 언어 설정 적용
// 헤더 로드 완료 후 이벤트 바인딩
document.addEventListener('headerLoaded', () => {
console.log('🔧 헤더 로드 완료 - 언어 전환 함수 등록');
console.log('🔧 헤더 로드 완료 - 이벤트 바인딩 시작');
// 로그인 버튼 이벤트 리스너 추가
const loginBtn = document.getElementById('login-btn');
if (loginBtn) {
loginBtn.addEventListener('click', () => {
console.log('🔐 로그인 버튼 클릭됨');
if (typeof window.handleLogin === 'function') {
window.handleLogin();
} else {
console.error('❌ handleLogin 함수를 찾을 수 없습니다');
}
});
console.log('✅ 로그인 버튼 이벤트 리스너 등록 완료');
}
// 언어 설정 적용
const savedLang = localStorage.getItem('preferred_language') || 'ko';
console.log('💾 저장된 언어 설정 적용:', savedLang);