Initial commit: 교육 프로젝트 배포
This commit is contained in:
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user