From d5336b43225cc99848264658a5d2058705596b0b Mon Sep 17 00:00:00 2001 From: optrader Date: Wed, 19 Nov 2025 19:56:12 +0900 Subject: [PATCH] [251119] feat: FloatingGradientLayer..Experimental..3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🕐 커밋 시간: 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 컴포넌트 아키텍처 개선 • 소규모 기능 개선 --- .../src/views/DetailPanel/DetailPanel.jsx | 36 ++++---- .../DetailPanelBackground.jsx | 86 +++++++++++++++++-- 2 files changed, 95 insertions(+), 27 deletions(-) diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx index 75751415..f8479fdb 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx @@ -148,24 +148,16 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { }; }, [dispatch]); - // ✅ DOM 렌더링 후 그라데이션 배경 숨기기 - HomePanel→DetailPanel 전환 완료 시 - useEffect(() => { - // DOM이 렌더링된 후 약간의 지연 시간을 두고 그라데이션 숨김 - const timer = setTimeout(() => { - 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 포함 + // ✅ DetailPanelBackground 이미지 완전 렌더링 후 그라데이션 배경 숨기기 + const handleBackgroundImageReady = useCallback(() => { + console.log('[TRACE-GRADIENT] ✅ DetailPanel - BackgroundImage fully rendered, hiding gradient'); + dispatch(updateHomeInfo({ + name: panel_names.HOME_PANEL, + panelInfo: { + showGradientBackground: false, + } + })); + }, [dispatch]); // ✅ [251118] DetailPanel이 사라질 때 HomePanel 활성화 useEffect(() => { @@ -805,8 +797,12 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) { return (
- - + + { + 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 && (