Files

279 lines
10 KiB
JavaScript

/**
* intro-section.js
* 섹션 전환 및 스크롤 처리 로직
* 공통 모듈 활용 (ErrorHandler, DOMUtils, AnimationUtils, Utils)
*/
// 전역 의존성 (폴백 포함)
const _sectionDomUtils = typeof DOMUtils !== 'undefined' ? DOMUtils : null;
const _sectionErrorHandler = typeof ErrorHandler !== 'undefined' ? ErrorHandler : null;
const _sectionUtils = typeof Utils !== 'undefined' ? Utils : null;
const _sectionAnimationUtils = typeof AnimationUtils !== 'undefined' ? AnimationUtils : null;
/**
* 에러 처리 헬퍼
* @private
*/
function _handleError(error, context, additionalInfo = {}) {
if (_sectionErrorHandler) {
_sectionErrorHandler.handle(error, {
context: `IntroSection.${context}`,
component: 'IntroSection',
...additionalInfo
}, false);
} else {
console.error(`[IntroSection] ${context}:`, error, additionalInfo);
}
}
/**
* 특정 섹션으로 이동
* @param {number} index - 이동할 섹션 인덱스 (0, 1, 2)
*/
function goToSection(index) {
try {
// 입력 검증
if (typeof index !== 'number' || index < 0 || index > 2) {
_handleError(new Error(`유효하지 않은 섹션 인덱스: ${index}`), 'goToSection');
return;
}
if (typeof INTRO_STATE === 'undefined') {
_handleError(new Error('INTRO_STATE가 정의되지 않았습니다'), 'goToSection');
return;
}
if (INTRO_STATE.isAnimating) return;
INTRO_STATE.isAnimating = true;
// 자동 스크롤 타이머 정지
clearTimeout(INTRO_STATE.autoScrollTimer);
// DOM 요소 선택
const section1Text = _sectionDomUtils?.$("#section1Text") || document.getElementById("section1Text");
const section2Text = _sectionDomUtils?.$("#section2Text") || document.getElementById("section2Text");
const section3Text = _sectionDomUtils?.$("#section3Text") || document.getElementById("section3Text");
const cardsContainer = _sectionDomUtils?.$("#cardsContainer") || document.getElementById("cardsContainer");
const ctaBtn = _sectionDomUtils?.$("#ctaBtn") || document.getElementById("ctaBtn");
const scrollIndicator = _sectionDomUtils?.$("#scrollIndicator") || document.getElementById("scrollIndicator");
// 요소 존재 확인
if (!section1Text || !section2Text || !section3Text || !cardsContainer || !ctaBtn || !scrollIndicator) {
_handleError(new Error('필수 DOM 요소를 찾을 수 없습니다'), 'goToSection');
INTRO_STATE.isAnimating = false;
return;
}
// 현재 섹션 페이드 아웃
const currentSection = INTRO_STATE.currentSection;
if (currentSection === 0) {
if (_sectionDomUtils && _sectionDomUtils.addClasses) {
_sectionDomUtils.addClasses(section1Text, 'fade-out');
} else {
section1Text.classList.add("fade-out");
}
} else if (currentSection === 1) {
if (_sectionDomUtils && _sectionDomUtils.addClasses) {
_sectionDomUtils.addClasses(section2Text, 'fade-out');
} else {
section2Text.classList.add("fade-out");
}
// 카드 숨기기
["card1", "card2", "card3", "card4"].forEach((id) => {
const card = _sectionDomUtils?.$(`#${id}`) || document.getElementById(id);
if (card) {
if (_sectionDomUtils && _sectionDomUtils.removeClasses) {
_sectionDomUtils.removeClasses(card, 'show');
} else {
card.classList.remove("show");
}
}
});
} else if (currentSection === 2) {
if (_sectionDomUtils && _sectionDomUtils.addClasses) {
_sectionDomUtils.addClasses(section3Text, 'fade-out');
} else {
section3Text.classList.add("fade-out");
}
if (_sectionDomUtils && _sectionDomUtils.removeClasses) {
_sectionDomUtils.removeClasses(ctaBtn, 'show');
} else {
ctaBtn.classList.remove("show");
}
}
// 전환 애니메이션 지연
const transitionDelay = 400;
const delayFn = _sectionUtils && _sectionUtils.delay ? _sectionUtils.delay : (ms) => new Promise(resolve => setTimeout(resolve, ms));
delayFn(transitionDelay).then(() => {
try {
// 모든 섹션 숨기기
if (_sectionDomUtils && _sectionDomUtils.addClasses) {
_sectionDomUtils.addClasses(section1Text, 'hidden');
_sectionDomUtils.addClasses(section2Text, 'hidden');
_sectionDomUtils.addClasses(section3Text, 'hidden');
} else {
section1Text.classList.add("hidden");
section2Text.classList.add("hidden");
section3Text.classList.add("hidden");
}
if (_sectionDomUtils && _sectionDomUtils.removeClasses) {
_sectionDomUtils.removeClasses(scrollIndicator, 'sec2');
_sectionDomUtils.removeClasses(section1Text, 'fade-out');
_sectionDomUtils.removeClasses(section2Text, 'fade-out');
_sectionDomUtils.removeClasses(section3Text, 'fade-out');
} else {
scrollIndicator.classList.remove("sec2");
section1Text.classList.remove("fade-out");
section2Text.classList.remove("fade-out");
section3Text.classList.remove("fade-out");
}
// 목표 섹션 표시
if (index === 0) {
if (_sectionDomUtils && _sectionDomUtils.removeClasses) {
_sectionDomUtils.removeClasses(section1Text, 'hidden');
_sectionDomUtils.removeClasses(scrollIndicator, 'hidden');
} else {
section1Text.classList.remove("hidden");
scrollIndicator.classList.remove("hidden");
}
if (_sectionDomUtils && _sectionDomUtils.setStyles) {
_sectionDomUtils.setStyles(cardsContainer, { display: 'none' });
_sectionDomUtils.setStyles(ctaBtn, { display: 'none' });
} else {
cardsContainer.style.display = "none";
ctaBtn.style.display = "none";
}
} else if (index === 1) {
if (_sectionDomUtils && _sectionDomUtils.addClasses) {
_sectionDomUtils.addClasses(scrollIndicator, 'sec2');
_sectionDomUtils.removeClasses(section2Text, 'hidden');
_sectionDomUtils.removeClasses(scrollIndicator, 'hidden');
} else {
scrollIndicator.classList.add("sec2");
section2Text.classList.remove("hidden");
scrollIndicator.classList.remove("hidden");
}
// 모바일(≤992px): section2Text 먼저 보여준 뒤 animateSection2에서 카드 표시
const isMobile = window.innerWidth <= 992;
if (_sectionDomUtils && _sectionDomUtils.setStyles) {
_sectionDomUtils.setStyles(cardsContainer, { display: isMobile ? 'none' : 'flex' });
_sectionDomUtils.setStyles(ctaBtn, { display: 'none' });
} else {
cardsContainer.style.display = isMobile ? "none" : "flex";
ctaBtn.style.display = "none";
}
resetSection2();
setTimeout(animateSection2, 200);
} else if (index === 2) {
if (_sectionDomUtils && _sectionDomUtils.removeClasses) {
_sectionDomUtils.removeClasses(section3Text, 'hidden');
_sectionDomUtils.addClasses(scrollIndicator, 'hidden');
_sectionDomUtils.removeClasses(scrollIndicator, 'sec2');
} else {
section3Text.classList.remove("hidden");
scrollIndicator.classList.add("hidden");
scrollIndicator.classList.remove("sec2");
}
if (_sectionDomUtils && _sectionDomUtils.setStyles) {
_sectionDomUtils.setStyles(cardsContainer, { display: 'none' });
_sectionDomUtils.setStyles(ctaBtn, { display: 'block' });
} else {
cardsContainer.style.display = "none";
ctaBtn.style.display = "block";
}
resetSection3();
setTimeout(animateSection3, 200);
}
INTRO_STATE.currentSection = index;
// 애니메이션 완료 플래그 리셋
const resetDelay = 500;
delayFn(resetDelay).then(() => {
INTRO_STATE.isAnimating = false;
});
} catch (error) {
_handleError(error, 'goToSection.transition');
INTRO_STATE.isAnimating = false;
}
});
} catch (error) {
_handleError(error, 'goToSection');
if (typeof INTRO_STATE !== 'undefined') {
INTRO_STATE.isAnimating = false;
}
}
}
/**
* 다음 섹션으로 스크롤
*/
function handleScrollDown() {
try {
if (typeof INTRO_STATE === 'undefined') {
_handleError(new Error('INTRO_STATE가 정의되지 않았습니다'), 'handleScrollDown');
return;
}
if (INTRO_STATE.isScrolling || INTRO_STATE.isAnimating) return;
const delayFn = _sectionUtils && _sectionUtils.delay ? _sectionUtils.delay : (ms) => new Promise(resolve => setTimeout(resolve, ms));
const scrollCooldown = 700;
if (INTRO_STATE.currentSection === 0) {
INTRO_STATE.isScrolling = true;
delayFn(scrollCooldown).then(() => {
INTRO_STATE.isScrolling = false;
});
goToSection(1);
} else if (INTRO_STATE.currentSection === 1 && INTRO_STATE.section2AnimDone) {
INTRO_STATE.isScrolling = true;
delayFn(scrollCooldown).then(() => {
INTRO_STATE.isScrolling = false;
});
goToSection(2);
}
} catch (error) {
_handleError(error, 'handleScrollDown');
}
}
/**
* 이전 섹션으로 스크롤
*/
function handleScrollUp() {
try {
if (typeof INTRO_STATE === 'undefined') {
_handleError(new Error('INTRO_STATE가 정의되지 않았습니다'), 'handleScrollUp');
return;
}
if (INTRO_STATE.isScrolling || INTRO_STATE.isAnimating) return;
INTRO_STATE.isScrolling = true;
const delayFn = _sectionUtils && _sectionUtils.delay ? _sectionUtils.delay : (ms) => new Promise(resolve => setTimeout(resolve, ms));
const scrollCooldown = 700;
delayFn(scrollCooldown).then(() => {
INTRO_STATE.isScrolling = false;
});
if (INTRO_STATE.currentSection === 2) {
goToSection(1);
} else if (INTRO_STATE.currentSection === 1) {
goToSection(0);
}
} catch (error) {
_handleError(error, 'handleScrollUp');
}
}