[251119] feat: FloatingGradientLayer..Experimental..3

🕐 커밋 시간: 2025. 11. 19. 19:56:11

📊 변경 통계:
  • 총 파일: 2개
  • 추가: +95줄
  • 삭제: -27줄

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx
  ~ com.twin.app.shoptime/src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.jsx

🔧 주요 변경 내용:
  • UI 컴포넌트 아키텍처 개선
  • 소규모 기능 개선
This commit is contained in:
2025-11-19 19:56:12 +09:00
parent 276ee65979
commit d5336b4322
2 changed files with 95 additions and 27 deletions

View File

@@ -148,24 +148,16 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
};
}, [dispatch]);
// ✅ DOM 렌더링 후 그라데이션 배경 숨기기 - HomePanel→DetailPanel 전환 완료 시
useEffect(() => {
// DOM이 렌더링된 후 약간의 지연 시간을 두고 그라데이션 숨김
const timer = setTimeout(() => {
// ✅ DetailPanelBackground 이미지 완전 렌더링 후 그라데이션 배경 숨기기
const handleBackgroundImageReady = useCallback(() => {
console.log('[TRACE-GRADIENT] ✅ DetailPanel - BackgroundImage fully rendered, hiding gradient');
dispatch(updateHomeInfo({
name: panel_names.HOME_PANEL,
panelInfo: {
showGradientBackground: false,
}
}));
console.log('[TRACE-GRADIENT] 🔴 DetailPanel mounted 100ms timeout set showGradientBackground: false');
}, 100); // 100ms 지연으로 DOM 렌더링 완료 후 실행
return () => {
clearTimeout(timer); // 컴포넌트 언마운트 시 타이머 정리
console.log('[TRACE-GRADIENT] 🔴 DetailPanel unmount - gradient timer cleared');
};
}, [dispatch]); // dispatch 포함
}, [dispatch]);
// ✅ [251118] DetailPanel이 사라질 때 HomePanel 활성화
useEffect(() => {
@@ -806,7 +798,11 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
return (
<div ref={containerRef}>
<DetailPanelBackground launchedFromPlayer={panelLaunchedFromPlayer} patnrId={panelPatnrId}/>
<DetailPanelBackground
launchedFromPlayer={panelLaunchedFromPlayer}
patnrId={panelPatnrId}
onImageReady={handleBackgroundImageReady}
/>
<TPanel
isTabActivated={false}

View File

@@ -1,7 +1,9 @@
// src/views/DetailPanel/components/DetailPanelBackground/DetailPanelBackground.jsx
import React, {
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
@@ -25,9 +27,11 @@ import css from './DetailPanelBackground.module.less';
* - true: PlayerPanel의 MEDIA 재생 완료 후 진입 (updatePanel로 전달됨)
* - false/undefined: 다른 패널(Shop Now, You May Like 등)에서 진입
* - 이 값에 따라 배경 UI를 다르게 표시할 수 있음
* @param {Function} onImageReady - 이미지가 DOM에 완전히 렌더링되었을 때 호출되는 콜백
*/
export default function DetailPanelBackground({ launchedFromPlayer = false, patnrId }) {
export default function DetailPanelBackground({ launchedFromPlayer = false, patnrId, onImageReady }) {
const [imageReady, setImageReady] = useState(false);
const imgRef = useRef(null);
const BG_MAP = {
1: qvc,
@@ -43,10 +47,44 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
return BG_MAP[patnrId] || qvc;
}, [patnrId]);
// ✅ [251119] 프리로드된 이미지 사용 로직 수정
// launchedFromPlayer와 상관없이 항상 배경 이미지를 표시하도록 수정
// ✅ 이미지가 DOM에 완전히 렌더링되었는지 확인하는 함수
const checkImageFullyLoaded = useCallback(() => {
const img = imgRef.current;
if (!img) return false;
// 이미지 로드 완료 및 실제 크기가 파싱됨
const isLoaded = img.complete && img.naturalWidth > 0;
// 렌더링된 DOM에 크기가 설정됨
const isRendered = img.offsetHeight > 0 && img.offsetWidth > 0;
const isDOMReady = isLoaded && isRendered;
if (isDOMReady) {
console.log('[DetailPanelBackground] ✅ 이미지 DOM 완전 렌더링 완료:', {
imgSrc: detailPanelBg,
complete: img.complete,
naturalWidth: img.naturalWidth,
naturalHeight: img.naturalHeight,
offsetHeight: img.offsetHeight,
offsetWidth: img.offsetWidth,
});
}
return isDOMReady;
}, [detailPanelBg]);
// 🔧 [251119] PlayerPanel에서 올라온 DetailPanel은 배경 이미지를 표시하지 않음
// launchedFromPlayer가 false일 때만 배경 이미지를 로드하고 표시
useEffect(() => {
// 이미지가 프리로드되었는지 확인
// launchedFromPlayer가 true이면 배경 이미지를 로드하지 않음 (PlayerPanel 비디오 보이도록)
if (launchedFromPlayer) {
console.log('[DetailPanelBackground] Skip background image loading - launchedFromPlayer=true (showing PlayerPanel video)');
setImageReady(false);
return;
}
// launchedFromPlayer가 false일 때만 배경 이미지 로드
console.log('[DetailPanelBackground] Loading background image - launchedFromPlayer=false');
if (ImagePreloader.isLoaded(detailPanelBg)) {
console.log('[DetailPanelBackground] Using preloaded image:', detailPanelBg);
setImageReady(true);
@@ -64,7 +102,40 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
setImageReady(true);
});
}
}, [detailPanelBg]); // launchedFromPlayer 제거
}, [detailPanelBg, launchedFromPlayer]); // launchedFromPlayer 추가
// ✅ 이미지가 DOM에 완전히 렌더링되면 부모에 콜백 호출
useEffect(() => {
if (!imageReady || !imgRef.current) return;
// 이미 렌더링된 경우 (캐시된 이미지)
if (checkImageFullyLoaded()) {
if (onImageReady) {
onImageReady();
}
return;
}
// 아직 렌더링 중인 경우: onLoad 대기
const img = imgRef.current;
const handleLoad = () => {
if (checkImageFullyLoaded()) {
if (onImageReady) {
onImageReady();
}
}
};
// img 요소가 ready 상태라면 즉시 실행
if (img.complete) {
handleLoad();
} else {
img.addEventListener('load', handleLoad);
return () => {
img.removeEventListener('load', handleLoad);
};
}
}, [imageReady, onImageReady, checkImageFullyLoaded]);
useEffect(() => {
console.log('[DetailPanelBackground] 배경 이미지 경로:', detailPanelBg);
@@ -84,9 +155,10 @@ export default function DetailPanelBackground({ launchedFromPlayer = false, patn
/>
)}
{/* 실제 배경 이미지 - 항상 표시되도록 수정 */}
{imageReady && (
{/* 실제 배경 이미지 - launchedFromPlayer가 false일 때만 표시 */}
{imageReady && !launchedFromPlayer && (
<img
ref={imgRef}
src={detailPanelBg}
alt=""
className={css.backgroundImage}