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:
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user