fix: resolve merge conflict in ProductVideo.v2
Resolved stash pop merge conflict by keeping the cleaner stashed version. - Simplified VideoPlayer wrapper structure - Maintained PalmSystem source/track elements
This commit is contained in:
@@ -132,3 +132,26 @@
|
||||
// PlayerPanel 모달에서 사용되는 스타일
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
// 일반 재생 모드 container (VideoPlayer가 초기 렌더링되는 위치)
|
||||
.normalPlayerContainer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
// 전체화면 container (Portal, body에 항상 존재)
|
||||
.fullscreenContainer {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
z-index: 99999;
|
||||
background-color: @COLOR_BLACK;
|
||||
|
||||
.videoPlayerWrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,12 @@ export default function ProductVideoV2({
|
||||
const autoPlayTimerRef = useRef(null);
|
||||
const containerRef = useRef(null);
|
||||
|
||||
// VideoPlayer DOM 이동을 위한 refs
|
||||
const videoPlayerWrapperRef = useRef(null);
|
||||
const normalContainerRef = useRef(null);
|
||||
const fullscreenContainerRef = useRef(null);
|
||||
const initialRenderContainerRef = useRef(null); // React가 처음 렌더링하는 위치
|
||||
|
||||
// 비디오 재생 가능 여부 체크
|
||||
const canPlayVideo = useMemo(() => {
|
||||
return Boolean(productInfo?.prdtMediaUrl);
|
||||
@@ -230,6 +236,42 @@ export default function ProductVideoV2({
|
||||
};
|
||||
}, [autoPlay, canPlayVideo, isPlaying]);
|
||||
|
||||
// VideoPlayer wrapper를 적절한 container로 이동
|
||||
useEffect(() => {
|
||||
if (!isPlaying) return;
|
||||
|
||||
const wrapper = videoPlayerWrapperRef.current;
|
||||
const normalContainer = normalContainerRef.current;
|
||||
const fullscreenContainer = fullscreenContainerRef.current;
|
||||
|
||||
if (!wrapper || !normalContainer || !fullscreenContainer) {
|
||||
console.warn('[ProductVideoV2] Refs not ready:', {
|
||||
wrapper: !!wrapper,
|
||||
normalContainer: !!normalContainer,
|
||||
fullscreenContainer: !!fullscreenContainer,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 처음 재생 시작 시: 임시 컨테이너에서 적절한 위치로 이동
|
||||
// 이후 전환 시: 컨테이너 간 이동
|
||||
if (isFullscreen) {
|
||||
// 전체화면: wrapper를 fullscreen container로 이동
|
||||
if (wrapper.parentElement !== fullscreenContainer) {
|
||||
fullscreenContainer.appendChild(wrapper);
|
||||
fullscreenContainer.style.display = 'block';
|
||||
console.log('[ProductVideoV2] Moved to fullscreen');
|
||||
}
|
||||
} else {
|
||||
// 일반 모드: wrapper를 normal container로 이동
|
||||
if (wrapper.parentElement !== normalContainer) {
|
||||
normalContainer.appendChild(wrapper);
|
||||
fullscreenContainer.style.display = 'none';
|
||||
console.log('[ProductVideoV2] Moved to normal');
|
||||
}
|
||||
}
|
||||
}, [isFullscreen, isPlaying]);
|
||||
|
||||
if (!canPlayVideo) return null;
|
||||
|
||||
// 컨테이너 컴포넌트 결정
|
||||
@@ -258,87 +300,117 @@ export default function ProductVideoV2({
|
||||
}
|
||||
: {};
|
||||
|
||||
// 비디오 플레이어 컨텐츠
|
||||
const videoContent = (
|
||||
<ContainerComponent
|
||||
{...containerProps}
|
||||
ref={containerRef}
|
||||
className={`${css.videoContainer} ${isFullscreen ? css.fullscreen : ''}`}
|
||||
// VideoPlayer 컴포넌트 (한 번만 생성, DOM 이동으로 위치 변경)
|
||||
const videoPlayerElement = isPlaying ? (
|
||||
<div
|
||||
ref={videoPlayerWrapperRef}
|
||||
className={`${css.videoPlayerWrapper} ${isFullscreen ? css.fullscreenPlayer : ''}`}
|
||||
>
|
||||
{!isPlaying ? (
|
||||
// 썸네일 + 재생 버튼 표시
|
||||
<SpottableComponent
|
||||
className={css.videoThumbnailContainer}
|
||||
onClick={handleThumbnailClick}
|
||||
onFocus={videoContainerOnFocus}
|
||||
onBlur={videoContainerOnBlur}
|
||||
onSpotlightDown={handleSpotlightDown}
|
||||
spotlightId="product-video-v2-thumbnail"
|
||||
aria-label={`${productInfo?.prdtNm} 동영상 재생`}
|
||||
>
|
||||
<div className={css.videoThumbnailWrapper}>
|
||||
<CustomImage
|
||||
src={thumbnailUrl}
|
||||
alt={`${productInfo?.prdtNm} 동영상 썸네일`}
|
||||
className={css.videoThumbnail}
|
||||
/>
|
||||
<div className={css.playButtonOverlay}>
|
||||
<img src={playImg} alt="재생" />
|
||||
</div>
|
||||
</div>
|
||||
</SpottableComponent>
|
||||
) : (
|
||||
// VideoPlayer 내장 표시
|
||||
<div className={`${css.videoPlayerWrapper} ${isFullscreen ? css.fullscreenPlayer : ''}`}>
|
||||
<VideoPlayer
|
||||
setApiProvider={getPlayer}
|
||||
disabled={false}
|
||||
onEnded={handleVideoEnded}
|
||||
onBackButton={handleBackButton}
|
||||
noAutoPlay={false}
|
||||
autoCloseTimeout={3000}
|
||||
spotlightDisabled={!isFullscreen}
|
||||
isYoutube={isYoutube}
|
||||
src={productInfo?.prdtMediaUrl}
|
||||
reactPlayerConfig={reactPlayerSubtitleConfig}
|
||||
thumbnailUrl={thumbnailUrl}
|
||||
title={productInfo?.prdtNm}
|
||||
videoComponent={
|
||||
(typeof window === 'object' && !window.PalmSystem) || isYoutube ? TReactPlayer : Media
|
||||
}
|
||||
type="MEDIA"
|
||||
panelInfo={{ modal: false }}
|
||||
captionEnable={false}
|
||||
setIsSubtitleActive={setIsSubtitleActive}
|
||||
setCurrentTime={setCurrentTime}
|
||||
setIsVODPaused={setIsVODPaused}
|
||||
playListInfo={[]}
|
||||
selectedIndex={0}
|
||||
videoVerticalVisible={false}
|
||||
sideContentsVisible={false}
|
||||
setSideContentsVisible={setSideContentsVisible}
|
||||
handleIndicatorDownClick={handleIndicatorDownClick}
|
||||
handleIndicatorUpClick={handleIndicatorUpClick}
|
||||
<VideoPlayer
|
||||
setApiProvider={getPlayer}
|
||||
disabled={false}
|
||||
onEnded={handleVideoEnded}
|
||||
onBackButton={handleBackButton}
|
||||
noAutoPlay={false}
|
||||
autoCloseTimeout={3000}
|
||||
spotlightDisabled={!isFullscreen}
|
||||
isYoutube={isYoutube}
|
||||
src={productInfo?.prdtMediaUrl}
|
||||
reactPlayerConfig={reactPlayerSubtitleConfig}
|
||||
thumbnailUrl={thumbnailUrl}
|
||||
title={productInfo?.prdtNm}
|
||||
videoComponent={
|
||||
(typeof window === 'object' && !window.PalmSystem) || isYoutube ? TReactPlayer : Media
|
||||
}
|
||||
type="MEDIA"
|
||||
panelInfo={{ modal: false }}
|
||||
captionEnable={false}
|
||||
setIsSubtitleActive={setIsSubtitleActive}
|
||||
setCurrentTime={setCurrentTime}
|
||||
setIsVODPaused={setIsVODPaused}
|
||||
playListInfo={[]}
|
||||
selectedIndex={0}
|
||||
videoVerticalVisible={false}
|
||||
sideContentsVisible={false}
|
||||
setSideContentsVisible={setSideContentsVisible}
|
||||
handleIndicatorDownClick={handleIndicatorDownClick}
|
||||
handleIndicatorUpClick={handleIndicatorUpClick}
|
||||
>
|
||||
{typeof window === 'object' && window.PalmSystem && (
|
||||
<source src={productInfo?.prdtMediaUrl} type={videoType} />
|
||||
)}
|
||||
{productInfo?.prdtMediaSubtitlUrl &&
|
||||
typeof window === 'object' &&
|
||||
window.PalmSystem && (
|
||||
<track kind="subtitles" src={productInfo?.prdtMediaSubtitlUrl} default />
|
||||
)}
|
||||
</VideoPlayer>
|
||||
</div>
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* 일반 모드 container */}
|
||||
<ContainerComponent
|
||||
{...containerProps}
|
||||
ref={containerRef}
|
||||
className={`${css.videoContainer} ${isFullscreen ? css.fullscreen : ''}`}
|
||||
>
|
||||
{!isPlaying ? (
|
||||
// 썸네일 + 재생 버튼 표시
|
||||
<SpottableComponent
|
||||
className={css.videoThumbnailContainer}
|
||||
onClick={handleThumbnailClick}
|
||||
onFocus={videoContainerOnFocus}
|
||||
onBlur={videoContainerOnBlur}
|
||||
spotlightId="product-video-v2-thumbnail"
|
||||
aria-label={`${productInfo?.prdtNm} 동영상 재생`}
|
||||
>
|
||||
{typeof window === 'object' && window.PalmSystem && (
|
||||
<source src={productInfo?.prdtMediaUrl} type={videoType} />
|
||||
)}
|
||||
{productInfo?.prdtMediaSubtitlUrl &&
|
||||
typeof window === 'object' &&
|
||||
window.PalmSystem && (
|
||||
<track kind="subtitles" src={productInfo?.prdtMediaSubtitlUrl} default />
|
||||
)}
|
||||
</VideoPlayer>
|
||||
</div>
|
||||
<div className={css.videoThumbnailWrapper}>
|
||||
<CustomImage
|
||||
src={thumbnailUrl}
|
||||
alt={`${productInfo?.prdtNm} 동영상 썸네일`}
|
||||
className={css.videoThumbnail}
|
||||
/>
|
||||
<div className={css.playButtonOverlay}>
|
||||
<img src={playImg} alt="재생" />
|
||||
</div>
|
||||
</div>
|
||||
</SpottableComponent>
|
||||
) : (
|
||||
// 일반 재생 모드: VideoPlayer가 여기에 초기 렌더링됨
|
||||
<div ref={normalContainerRef} className={css.normalPlayerContainer} />
|
||||
)}
|
||||
</ContainerComponent>
|
||||
|
||||
{/* 전체화면 container (Portal, 항상 body에 존재) */}
|
||||
{ReactDOM.createPortal(
|
||||
<SpotlightContainer
|
||||
spotlightRestrict="self-only"
|
||||
spotlightId="product-video-v2-fullscreen-portal"
|
||||
>
|
||||
<div
|
||||
ref={fullscreenContainerRef}
|
||||
className={css.fullscreenContainer}
|
||||
style={{ display: 'none' }}
|
||||
/>
|
||||
</SpotlightContainer>,
|
||||
document.body
|
||||
)}
|
||||
</ContainerComponent>
|
||||
|
||||
{/* 임시 렌더링 컨테이너 - React가 여기에 VideoPlayer 렌더링, useEffect가 실제 위치로 이동 */}
|
||||
<div
|
||||
ref={initialRenderContainerRef}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: -9999,
|
||||
left: -9999,
|
||||
visibility: 'hidden',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
>
|
||||
{videoPlayerElement}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
// 전체화면일 때는 Portal로 body에 직접 렌더링
|
||||
if (isFullscreen) {
|
||||
return ReactDOM.createPortal(videoContent, document.body);
|
||||
}
|
||||
|
||||
// 일반 모드일 때는 그냥 렌더링
|
||||
return videoContent;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user