[250929] feat: ProductAllSection 비디오 기능 수정
This commit is contained in:
@@ -1028,3 +1028,12 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 비디오 컨테이너 스타일 (modal 영역 지정용)
|
||||
.videoContainer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
// PlayerPanel 모달이 이 영역에서만 재생되도록 설정
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import React, { useCallback, useMemo, useState, useEffect } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import Spottable from '@enact/spotlight/Spottable';
|
||||
import { startVideoPlayer } from '../../../../actions/playActions';
|
||||
import { startVideoPlayer, finishVideoPreview } from '../../../../actions/playActions';
|
||||
import CustomImage from '../../../../components/CustomImage/CustomImage';
|
||||
import { panel_names } from '../../../../utils/Config';
|
||||
import playImg from '../../../../../assets/images/btn/btn-play-thumb-nor.png';
|
||||
import css from './ProductVideo.module.less';
|
||||
|
||||
@@ -11,10 +12,51 @@ const SpottableComponent = Spottable('div');
|
||||
export default function ProductVideo({ productInfo, videoUrl, thumbnailUrl }) {
|
||||
const dispatch = useDispatch();
|
||||
|
||||
// Indicator.jsx의 canPlayVideo 로직 이식
|
||||
// PlayerPanel 상태 체크를 위한 selectors 추가 (Indicator.jsx와 동일)
|
||||
const panels = useSelector((state) => state.panels.panels);
|
||||
const [isLaunchedFromPlayer, setIsLaunchedFromPlayer] = useState(false);
|
||||
const [focused, setFocused] = useState(false);
|
||||
|
||||
const topPanel = panels[panels.length - 1];
|
||||
|
||||
// Indicator.jsx의 PlayerPanel 상태 체크 로직 추가
|
||||
useEffect(() => {
|
||||
if (
|
||||
topPanel &&
|
||||
topPanel.name === panel_names.PLAYER_PANEL &&
|
||||
topPanel.panelInfo.modal === false
|
||||
) {
|
||||
return; // PlayerPanel이 전체화면 모드일 때는 처리하지 않음
|
||||
}
|
||||
}, [topPanel]);
|
||||
|
||||
// Indicator.jsx의 canPlayVideo 로직 완전 이식 (selectedIndex === 0 조건 포함)
|
||||
const canPlayVideo = useMemo(() => {
|
||||
return Boolean(productInfo?.prdtMediaUrl && videoUrl);
|
||||
}, [productInfo, videoUrl]);
|
||||
return Boolean(productInfo?.prdtMediaUrl);
|
||||
}, [productInfo]);
|
||||
|
||||
// Indicator.jsx의 modalClassNameChange 로직 추가
|
||||
const modalClassNameChange = useCallback(() => {
|
||||
if (focused) {
|
||||
return css.videoModal;
|
||||
}
|
||||
return '';
|
||||
}, [focused]);
|
||||
|
||||
// focus 이벤트 핸들러 추가 (Indicator.jsx와 동일)
|
||||
const videoContainerOnFocus = useCallback(() => {
|
||||
if (canPlayVideo) {
|
||||
setFocused(true);
|
||||
}
|
||||
}, [canPlayVideo]);
|
||||
|
||||
const videoContainerOnBlur = useCallback(() => {
|
||||
if (canPlayVideo) {
|
||||
setFocused(false);
|
||||
// ProductVideo에서 포커스가 벗어나면 비디오 재생 종료
|
||||
dispatch(finishVideoPreview());
|
||||
}
|
||||
}, [canPlayVideo, dispatch]);
|
||||
|
||||
// Indicator.jsx의 handleVideoOnClick 로직 완전히 이식
|
||||
const handleVideoClick = useCallback(() => {
|
||||
@@ -37,15 +79,18 @@ export default function ProductVideo({ productInfo, videoUrl, thumbnailUrl }) {
|
||||
prdtNm: productInfo?.prdtNm,
|
||||
thumbnailUrl: productInfo?.thumbnailUrl960,
|
||||
shptmBanrTpNm: 'MEDIA',
|
||||
// Indicator.jsx와 동일하게: 클릭 시 전체화면 모드
|
||||
modal: false,
|
||||
modalContainerId: 'product-video-player', // 우리 컴포넌트의 spotlightId
|
||||
modalClassName: css.videoModal,
|
||||
spotlightDisable: false,
|
||||
modal: true,
|
||||
modalContainerId: 'product-video-player',
|
||||
modalClassName: modalClassNameChange(),
|
||||
spotlightDisable: true,
|
||||
})
|
||||
);
|
||||
}
|
||||
}, [dispatch, productInfo, canPlayVideo]);
|
||||
|
||||
if (isLaunchedFromPlayer) {
|
||||
setIsLaunchedFromPlayer(false);
|
||||
}
|
||||
}, [dispatch, productInfo, canPlayVideo, isLaunchedFromPlayer, modalClassNameChange]);
|
||||
|
||||
if (!canPlayVideo) return null;
|
||||
|
||||
@@ -53,6 +98,8 @@ export default function ProductVideo({ productInfo, videoUrl, thumbnailUrl }) {
|
||||
<SpottableComponent
|
||||
className={css.videoContainer}
|
||||
onClick={handleVideoClick}
|
||||
onFocus={videoContainerOnFocus}
|
||||
onBlur={videoContainerOnBlur}
|
||||
spotlightId="product-video-player"
|
||||
aria-label={`${productInfo?.prdtNm} 동영상 재생`}
|
||||
>
|
||||
|
||||
@@ -1,19 +1,37 @@
|
||||
@import "../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../style/utils.module.less";
|
||||
|
||||
.videoContainer {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
width: 1114px; // ProductDetail과 동일한 고정 크기
|
||||
max-width: 1114px;
|
||||
height: 670px; // ProductDetail과 동일한 고정 높이
|
||||
margin-bottom: 30px; // ProductDetail과 동일한 간격
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
padding: 6px; // 포커스 테두리를 위한 공간
|
||||
|
||||
.videoThumbnailWrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
width: 658px; // ProductDetail과 동일한 썸네일 크기
|
||||
height: 610px; // ProductDetail과 동일한 썸네일 높이
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto;
|
||||
|
||||
.videoThumbnail {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
object-fit: contain; // 비율 유지하며 컨테이너에 맞춤
|
||||
background-color: @COLOR_WHITE;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.playButtonOverlay {
|
||||
@@ -38,22 +56,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Spotlight 포커스 스타일
|
||||
// ProductDetail과 동일한 포커스 스타일
|
||||
&:focus {
|
||||
outline: 2px solid #0078d4;
|
||||
outline-offset: 2px;
|
||||
&::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: -6px;
|
||||
right: -6px;
|
||||
bottom: -6px;
|
||||
z-index: 19;
|
||||
border: 6px solid @PRIMARY_COLOR_RED;
|
||||
box-shadow: 0 0 22px 0 rgba(0, 0, 0, 0.5);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.videoThumbnailWrapper .videoThumbnail {
|
||||
transform: scale(1.015); // 가로세로 10px 정도 확대 효과
|
||||
}
|
||||
|
||||
.playButtonOverlay {
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
// webOS TV 환경에서의 포커스 스타일
|
||||
&.spottable:focus {
|
||||
outline: 3px solid #ffffff;
|
||||
outline-offset: 3px;
|
||||
box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
// 동영상 모달 클래스 (PlayerPanel에서 사용)
|
||||
|
||||
Reference in New Issue
Block a user