feat: 부드러운 단계적 로딩 애니메이션 구현 - 헤더 우선 표시 후 본문 페이드인

🎨 Smooth Progressive Loading:
- 헤더 먼저 표시 → 본문 부드럽게 페이드인
- 3단계 애니메이션 시스템 구현
- 자연스러운 사용자 경험 제공

🎯 Animation Strategy:
Step 1: 헤더 빠른 페이드인 (0.4s, -10px → 0)
Step 2: 본문 지연 페이드인 (0.8s, +30px → 0, 0.2s delay)
Step 3: 순차적 컨텐츠 표시 (100ms 간격)

🔧 CSS Animations:
- .header-fade-in: 헤더 전용 빠른 애니메이션
- .content-fade-in: 본문 지연 페이드인 + 상향 이동
- .fade-in: 범용 페이드인 애니메이션
- ease-out 트랜지션으로 자연스러운 감속

🎨 Progressive Loading Flow:
1. 페이지 로드 → 헤더 초기화
2. 헤더 페이드인 (0.4초)
3. 200ms 후 본문 애니메이션 시작
4. 컨텐츠 요소들 순차 페이드인 (100ms 간격)

🔧 Enhanced UX Features:
- 섹션 전환 시에도 부드러운 애니메이션
- 애니메이션 상태 리셋 및 재적용
- 헤더 요소 자동 감지 및 애니메이션
- 로딩 상태별 상세 로그

🎯 Visual Improvements:
- 헤더: 위에서 아래로 부드럽게 등장
- 본문: 아래에서 위로 부드럽게 등장
- 지연 효과로 계층적 정보 표시
- 매끄러운 페이지 전환

Expected Result:
 헤더 우선 표시 (즉시 네비게이션 가능)
 본문 부드러운 페이드인 (시각적 만족감)
 단계적 로딩으로 자연스러운 UX
 섹션 전환 시에도 애니메이션 적용
This commit is contained in:
Hyungi Ahn
2025-10-25 12:42:13 +09:00
parent 71e99fed1a
commit 08c9c946cc

View File

@@ -150,6 +150,43 @@
text-align: center;
box-shadow: 0 4px 6px rgba(0, 0, 0, 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>
@@ -208,10 +245,10 @@
<!-- 메인 화면 (기본 표시 - AuthManager가 결정) -->
<div id="mainScreen" class="min-h-screen bg-gray-50">
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 -->
<!-- 공통 헤더가 여기에 자동으로 삽입됩니다 (헤더는 별도 애니메이션) -->
<!-- 부적합 등록 섹션 (모바일 최적화) -->
<section id="reportSection" class="container mx-auto px-3 py-4 max-w-md">
<section id="reportSection" class="container mx-auto px-3 py-4 max-w-md content-fade-in">
<!-- 페이지 헤더 -->
<div class="mb-4">
<h1 class="text-xl font-bold text-gray-900 flex items-center">
@@ -344,7 +381,7 @@
</section>
<!-- 목록 관리 섹션 -->
<section id="listSection" class="hidden container mx-auto px-4 py-6" style="padding-top: 120px;">
<section id="listSection" class="hidden container mx-auto px-4 py-6 content-fade-in" style="padding-top: 120px;">
<div class="bg-white rounded-xl shadow-sm p-6">
<div class="mb-4">
<div class="flex justify-between items-center mb-4">
@@ -403,7 +440,7 @@
</section>
<!-- 보고서 섹션 -->
<section id="summarySection" class="hidden container mx-auto px-4 py-6" style="padding-top: 120px;">
<section id="summarySection" class="hidden container mx-auto px-4 py-6 content-fade-in" style="padding-top: 120px;">
<div class="bg-white rounded-xl shadow-sm p-6">
<div class="flex justify-between items-center mb-6">
<h2 class="text-lg font-semibold text-gray-800">작업 보고서</h2>
@@ -497,6 +534,12 @@
await window.commonHeader.init(user, 'issues_create');
window.commonHeaderInitialized = true;
console.log('✅ 공통 헤더 초기화 완료');
// 헤더 초기화 후 부드러운 애니메이션 시작
setTimeout(() => {
animateHeaderAppearance();
}, 100);
} else {
console.error('❌ 공통 헤더 모듈이 로드되지 않음');
// 지연 재시도
@@ -505,11 +548,56 @@
console.log('🔄 지연된 공통 헤더 초기화');
await window.commonHeader.init(user, 'issues_create');
window.commonHeaderInitialized = true;
// 지연된 헤더도 애니메이션 적용
setTimeout(() => {
animateHeaderAppearance();
}, 100);
}
}, 200);
}
}
// 단계적 애니메이션 함수
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씩 지연
});
}
// 수동 초기화 함수 (initializeApp 함수가 로드되지 않을 때 사용)
async function manualInitialize() {
console.log('🔧 수동 초기화 시작');
@@ -711,10 +799,21 @@
window.addEventListener('hashchange', handleUrlHash);
function showSection(section) {
// 모든 섹션 숨기기
document.querySelectorAll('section').forEach(s => s.classList.add('hidden'));
// 모든 섹션 숨기기 (애니메이션 리셋)
document.querySelectorAll('section').forEach(s => {
s.classList.add('hidden');
s.classList.remove('visible');
});
// 선택된 섹션 표시
document.getElementById(section + 'Section').classList.remove('hidden');
const targetSection = document.getElementById(section + 'Section');
targetSection.classList.remove('hidden');
// 부드러운 페이드인 애니메이션
setTimeout(() => {
targetSection.classList.add('visible');
console.log(`${section} 섹션 페이드인 완료`);
}, 50);
// 공통 헤더 현재 페이지 업데이트
if (window.commonHeader && currentUser) {