feat: 모든 페이지에 부드러운 단계적 로딩 애니메이션 적용 완료
🎨 Universal Smooth Animation System: - 6개 모든 페이지에 통일된 애니메이션 적용 - 헤더 우선 표시 → 본문 부드러운 페이드인 - 일관성 있는 사용자 경험 제공 📱 Applied Pages: ✅ index.html (메인 페이지) ✅ issues-inbox.html (수신함) ✅ issue-view.html (부적합 조회) ✅ daily-work.html (일일공수) ✅ project-management.html (프로젝트 관리) ✅ admin.html (관리자) 🎯 Animation Flow (모든 페이지 동일): Step 1: 헤더 빠른 페이드인 (0.4s, -10px → 0) Step 2: 본문 지연 페이드인 (0.8s, +30px → 0, 0.2s delay) Step 3: 컨텐츠 순차 표시 (100ms 간격) 🔧 Unified Implementation: - 동일한 CSS 애니메이션 클래스 (.header-fade-in, .content-fade-in) - 통일된 JavaScript 함수 (animateHeaderAppearance, animateContentAppearance) - 헤더 초기화 후 자동 애니메이션 시작 - 에러 상황에서도 애니메이션 적용 🎨 Enhanced UX Features: - 헤더 우선 표시로 즉시 네비게이션 가능 - 부드러운 전환으로 시각적 만족감 증대 - 브랜드 일관성을 위한 통일된 애니메이션 - 성능 최적화된 애니메이션 시스템 🎯 Visual Improvements: - 헤더: 위에서 부드럽게 등장 (빠름) - 본문: 아래에서 부드럽게 등장 (느림) - 컨텐츠: 순차적 페이드인 (리듬감) - 매끄러운 페이지 전환 Expected Result: ✨ 모든 페이지에서 동일한 부드러운 로딩 경험 ✨ 헤더 우선 표시로 즉시 네비게이션 가능 ✨ 통일된 브랜드 경험 및 사용자 만족도 증대 ✨ 성능 최적화와 시각적 완성도 양립
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
backend/routers/__pycache__/inbox.cpython-311.pyc
Normal file
BIN
backend/routers/__pycache__/inbox.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
backend/routers/__pycache__/page_permissions.cpython-311.pyc
Normal file
BIN
backend/routers/__pycache__/page_permissions.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -56,13 +56,50 @@
|
||||
border-color: #60a5fa;
|
||||
box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.1);
|
||||
}
|
||||
|
||||
/* 부드러운 페이드인 애니메이션 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 헤더 전용 빠른 페이드인 */
|
||||
.header-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
||||
}
|
||||
|
||||
.header-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 본문 컨텐츠 지연 페이드인 */
|
||||
.content-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.content-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="container mx-auto px-4 py-8 max-w-6xl" style="padding-top: 120px;">
|
||||
<main class="container mx-auto px-4 py-8 max-w-6xl content-fade-in" style="padding-top: 120px;">
|
||||
<div class="grid md:grid-cols-2 gap-6">
|
||||
<!-- 사용자 추가 섹션 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6">
|
||||
@@ -228,6 +265,46 @@
|
||||
let currentUser = null;
|
||||
let users = [];
|
||||
|
||||
// 애니메이션 함수들
|
||||
function animateHeaderAppearance() {
|
||||
console.log('🎨 헤더 애니메이션 시작');
|
||||
|
||||
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
||||
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
||||
|
||||
if (headerElement) {
|
||||
headerElement.classList.add('header-fade-in');
|
||||
setTimeout(() => {
|
||||
headerElement.classList.add('visible');
|
||||
console.log('✨ 헤더 페이드인 완료');
|
||||
|
||||
// 헤더 애니메이션 완료 후 본문 애니메이션
|
||||
setTimeout(() => {
|
||||
animateContentAppearance();
|
||||
}, 200);
|
||||
}, 50);
|
||||
} else {
|
||||
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
||||
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
||||
animateContentAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
// 본문 컨텐츠 애니메이션
|
||||
function animateContentAppearance() {
|
||||
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
||||
|
||||
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
||||
const contentElements = document.querySelectorAll('.content-fade-in');
|
||||
|
||||
contentElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('visible');
|
||||
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
||||
}, index * 100); // 100ms씩 지연
|
||||
});
|
||||
}
|
||||
|
||||
// API 로드 후 초기화 함수
|
||||
async function initializeAdmin() {
|
||||
const token = localStorage.getItem('access_token');
|
||||
@@ -244,6 +321,11 @@
|
||||
// 공통 헤더 초기화
|
||||
await window.commonHeader.init(user, 'users_manage');
|
||||
|
||||
// 헤더 초기화 후 부드러운 애니메이션 시작
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
|
||||
// 페이지 접근 권한 체크
|
||||
setTimeout(() => {
|
||||
if (!canAccessPage('users_manage')) {
|
||||
|
||||
@@ -89,6 +89,43 @@
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 부드러운 페이드인 애니메이션 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 헤더 전용 빠른 페이드인 */
|
||||
.header-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
||||
}
|
||||
|
||||
.header-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 본문 컨텐츠 지연 페이드인 */
|
||||
.content-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.content-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
@@ -96,7 +133,7 @@
|
||||
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
||||
|
||||
<!-- 메인 컨텐츠 -->
|
||||
<main class="container mx-auto px-4 py-6 max-w-2xl">
|
||||
<main class="container mx-auto px-4 py-6 max-w-2xl content-fade-in">
|
||||
<!-- 입력 카드 -->
|
||||
<div class="work-card p-6 mb-6">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-6">
|
||||
@@ -195,6 +232,46 @@
|
||||
let dailyWorkData = [];
|
||||
let projectEntryCounter = 0;
|
||||
|
||||
// 애니메이션 함수들
|
||||
function animateHeaderAppearance() {
|
||||
console.log('🎨 헤더 애니메이션 시작');
|
||||
|
||||
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
||||
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
||||
|
||||
if (headerElement) {
|
||||
headerElement.classList.add('header-fade-in');
|
||||
setTimeout(() => {
|
||||
headerElement.classList.add('visible');
|
||||
console.log('✨ 헤더 페이드인 완료');
|
||||
|
||||
// 헤더 애니메이션 완료 후 본문 애니메이션
|
||||
setTimeout(() => {
|
||||
animateContentAppearance();
|
||||
}, 200);
|
||||
}, 50);
|
||||
} else {
|
||||
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
||||
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
||||
animateContentAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
// 본문 컨텐츠 애니메이션
|
||||
function animateContentAppearance() {
|
||||
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
||||
|
||||
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
||||
const contentElements = document.querySelectorAll('.content-fade-in');
|
||||
|
||||
contentElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('visible');
|
||||
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
||||
}, index * 100); // 100ms씩 지연
|
||||
});
|
||||
}
|
||||
|
||||
// API 로드 후 초기화 함수
|
||||
async function initializeDailyWork() {
|
||||
const token = localStorage.getItem('access_token');
|
||||
@@ -211,6 +288,11 @@
|
||||
// 공통 헤더 초기화
|
||||
await window.commonHeader.init(user, 'daily_work');
|
||||
|
||||
// 헤더 초기화 후 부드러운 애니메이션 시작
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
|
||||
// 페이지 접근 권한 체크 (일일 공수 페이지)
|
||||
setTimeout(() => {
|
||||
if (!canAccessPage('daily_work')) {
|
||||
|
||||
@@ -66,13 +66,50 @@
|
||||
background-color: #3b82f6;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 부드러운 페이드인 애니메이션 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 헤더 전용 빠른 페이드인 */
|
||||
.header-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
||||
}
|
||||
|
||||
.header-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 본문 컨텐츠 지연 페이드인 */
|
||||
.content-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.content-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="container mx-auto px-4 py-8">
|
||||
<main class="container mx-auto px-4 py-8 content-fade-in">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-4 mb-6">
|
||||
<div class="mb-4">
|
||||
@@ -162,6 +199,46 @@
|
||||
let selectedStartDate = null;
|
||||
let selectedEndDate = null;
|
||||
|
||||
// 애니메이션 함수들
|
||||
function animateHeaderAppearance() {
|
||||
console.log('🎨 헤더 애니메이션 시작');
|
||||
|
||||
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
||||
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
||||
|
||||
if (headerElement) {
|
||||
headerElement.classList.add('header-fade-in');
|
||||
setTimeout(() => {
|
||||
headerElement.classList.add('visible');
|
||||
console.log('✨ 헤더 페이드인 완료');
|
||||
|
||||
// 헤더 애니메이션 완료 후 본문 애니메이션
|
||||
setTimeout(() => {
|
||||
animateContentAppearance();
|
||||
}, 200);
|
||||
}, 50);
|
||||
} else {
|
||||
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
||||
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
||||
animateContentAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
// 본문 컨텐츠 애니메이션
|
||||
function animateContentAppearance() {
|
||||
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
||||
|
||||
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
||||
const contentElements = document.querySelectorAll('.content-fade-in');
|
||||
|
||||
contentElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('visible');
|
||||
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
||||
}, index * 100); // 100ms씩 지연
|
||||
});
|
||||
}
|
||||
|
||||
// API 로드 후 초기화 함수
|
||||
async function initializeIssueView() {
|
||||
const token = localStorage.getItem('access_token');
|
||||
@@ -178,6 +255,11 @@
|
||||
// 공통 헤더 초기화
|
||||
await window.commonHeader.init(user, 'issues_view');
|
||||
|
||||
// 헤더 초기화 후 부드러운 애니메이션 시작
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
|
||||
// 사용자 역할에 따른 페이지 제목 설정
|
||||
updatePageTitle(user);
|
||||
|
||||
|
||||
@@ -74,6 +74,43 @@
|
||||
.badge-new { background: #dbeafe; color: #1e40af; }
|
||||
.badge-processing { background: #fef3c7; color: #92400e; }
|
||||
.badge-completed { background: #d1fae5; color: #065f46; }
|
||||
|
||||
/* 부드러운 페이드인 애니메이션 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 헤더 전용 빠른 페이드인 */
|
||||
.header-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
||||
}
|
||||
|
||||
.header-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 본문 컨텐츠 지연 페이드인 */
|
||||
.content-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.content-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 min-h-screen">
|
||||
@@ -88,7 +125,7 @@
|
||||
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="container mx-auto px-4 py-8" style="padding-top: 120px;">
|
||||
<main class="container mx-auto px-4 py-8 content-fade-in" style="padding-top: 120px;">
|
||||
<!-- 페이지 헤더 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6 mb-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
@@ -384,6 +421,46 @@
|
||||
let filteredIssues = [];
|
||||
let readStatus = new Set(); // 읽은 부적합 ID 저장
|
||||
|
||||
// 애니메이션 함수들
|
||||
function animateHeaderAppearance() {
|
||||
console.log('🎨 헤더 애니메이션 시작');
|
||||
|
||||
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
||||
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
||||
|
||||
if (headerElement) {
|
||||
headerElement.classList.add('header-fade-in');
|
||||
setTimeout(() => {
|
||||
headerElement.classList.add('visible');
|
||||
console.log('✨ 헤더 페이드인 완료');
|
||||
|
||||
// 헤더 애니메이션 완료 후 본문 애니메이션
|
||||
setTimeout(() => {
|
||||
animateContentAppearance();
|
||||
}, 200);
|
||||
}, 50);
|
||||
} else {
|
||||
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
||||
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
||||
animateContentAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
// 본문 컨텐츠 애니메이션
|
||||
function animateContentAppearance() {
|
||||
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
||||
|
||||
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
||||
const contentElements = document.querySelectorAll('.content-fade-in');
|
||||
|
||||
contentElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('visible');
|
||||
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
||||
}, index * 100); // 100ms씩 지연
|
||||
});
|
||||
}
|
||||
|
||||
// API 로드 후 초기화 함수
|
||||
async function initializeInbox() {
|
||||
console.log('🚀 수신함 초기화 시작');
|
||||
@@ -406,6 +483,11 @@
|
||||
|
||||
// 공통 헤더 초기화
|
||||
await window.commonHeader.init(user, 'issues_inbox');
|
||||
|
||||
// 헤더 초기화 후 부드러운 애니메이션 시작
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
|
||||
// 페이지 접근 권한 체크
|
||||
setTimeout(() => {
|
||||
@@ -454,6 +536,10 @@
|
||||
const user = JSON.parse(localStorage.getItem('currentUser') || '{}');
|
||||
if (user.id) {
|
||||
await window.commonHeader.init(user, 'issues_inbox');
|
||||
// 에러 상황에서도 애니메이션 적용
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
}
|
||||
} catch (headerError) {
|
||||
console.error('공통 헤더 초기화 실패:', headerError);
|
||||
|
||||
@@ -46,13 +46,50 @@
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
/* 부드러운 페이드인 애니메이션 */
|
||||
.fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
|
||||
}
|
||||
|
||||
.fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 헤더 전용 빠른 페이드인 */
|
||||
.header-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.4s ease-out, transform 0.4s ease-out;
|
||||
}
|
||||
|
||||
.header-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* 본문 컨텐츠 지연 페이드인 */
|
||||
.content-fade-in {
|
||||
opacity: 0;
|
||||
transform: translateY(30px);
|
||||
transition: opacity 0.8s ease-out, transform 0.8s ease-out;
|
||||
transition-delay: 0.2s;
|
||||
}
|
||||
|
||||
.content-fade-in.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
|
||||
|
||||
<!-- 메인 컨텐츠 -->
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl">
|
||||
<main class="container mx-auto px-4 py-8 max-w-4xl content-fade-in">
|
||||
<!-- 프로젝트 생성 섹션 -->
|
||||
<div class="bg-white rounded-xl shadow-sm p-6 mb-8">
|
||||
<h2 class="text-lg font-semibold text-gray-800 mb-4">
|
||||
@@ -169,6 +206,46 @@
|
||||
// 사용자 확인 (관리자만 접근 가능)
|
||||
let currentUser = null;
|
||||
|
||||
// 애니메이션 함수들
|
||||
function animateHeaderAppearance() {
|
||||
console.log('🎨 헤더 애니메이션 시작');
|
||||
|
||||
// 헤더 요소 찾기 (공통 헤더가 생성한 요소)
|
||||
const headerElement = document.querySelector('header') || document.querySelector('[class*="header"]') || document.querySelector('nav');
|
||||
|
||||
if (headerElement) {
|
||||
headerElement.classList.add('header-fade-in');
|
||||
setTimeout(() => {
|
||||
headerElement.classList.add('visible');
|
||||
console.log('✨ 헤더 페이드인 완료');
|
||||
|
||||
// 헤더 애니메이션 완료 후 본문 애니메이션
|
||||
setTimeout(() => {
|
||||
animateContentAppearance();
|
||||
}, 200);
|
||||
}, 50);
|
||||
} else {
|
||||
// 헤더를 찾지 못했으면 바로 본문 애니메이션
|
||||
console.log('⚠️ 헤더 요소를 찾지 못함 - 본문 애니메이션 시작');
|
||||
animateContentAppearance();
|
||||
}
|
||||
}
|
||||
|
||||
// 본문 컨텐츠 애니메이션
|
||||
function animateContentAppearance() {
|
||||
console.log('🎨 본문 컨텐츠 애니메이션 시작');
|
||||
|
||||
// 모든 content-fade-in 요소들을 순차적으로 애니메이션
|
||||
const contentElements = document.querySelectorAll('.content-fade-in');
|
||||
|
||||
contentElements.forEach((element, index) => {
|
||||
setTimeout(() => {
|
||||
element.classList.add('visible');
|
||||
console.log(`✨ 컨텐츠 ${index + 1} 페이드인 완료`);
|
||||
}, index * 100); // 100ms씩 지연
|
||||
});
|
||||
}
|
||||
|
||||
async function initAuth() {
|
||||
console.log('인증 초기화 시작');
|
||||
const token = localStorage.getItem('access_token');
|
||||
@@ -205,6 +282,11 @@
|
||||
// 공통 헤더 초기화
|
||||
await window.commonHeader.init(currentUser, 'projects_manage');
|
||||
|
||||
// 헤더 초기화 후 부드러운 애니메이션 시작
|
||||
setTimeout(() => {
|
||||
animateHeaderAppearance();
|
||||
}, 100);
|
||||
|
||||
// 페이지 접근 권한 체크 (프로젝트 관리 페이지)
|
||||
setTimeout(() => {
|
||||
if (!canAccessPage('projects_manage')) {
|
||||
|
||||
Reference in New Issue
Block a user