[251114] feat: ProductAllSection ProductVideo.v3
🕐 커밋 시간: 2025. 11. 14. 14:24:07 📊 변경 통계: • 총 파일: 13개 • 추가: +135줄 • 삭제: -54줄 📁 추가된 파일: + com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js + com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less + com.twin.app.shoptime/src/hooks/useMediaPanelController.js + com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v3.jsx + com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx + com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.module.less 📝 수정된 파일: ~ com.twin.app.shoptime/src/actions/mediaActions.js ~ com.twin.app.shoptime/src/views/DetailPanel/DetailPanel.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.jsx ~ com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.v2.jsx ~ com.twin.app.shoptime/src/views/MainView/MainView.jsx 🔧 함수 변경 내용: 📄 com.twin.app.shoptime/src/actions/mediaActions.js (javascript): 🔄 Modified: switchMediaToModal() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx (javascript): 🔄 Modified: SpotlightContainerDecorator(), extractProductMeta() 📄 com.twin.app.shoptime/src/views/DetailPanel/ProductContentSection/ProductVideo/ProductVideo.jsx (javascript): ✅ Added: Spottable() 📄 com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js (javascript): ✅ Added: getControlsHandleAboveHoldConfig(), shouldJump(), calcNumberValueOfPlaybackRate(), getDurFmt(), getVideoPhoneNumberClassNames() 📄 com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.module.less (unknown): ✅ Added: gradient(), focused(), position(), rotate(), applySkins(), scale() 📄 com.twin.app.shoptime/src/hooks/useMediaPanelController.js (javascript): ✅ Added: MediaPanelControllerProvider(), useMediaPanelController() 📄 com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx (javascript): ✅ Added: findSelector(), getLogTpNo(), normalizeModalStyle(), parseValue(), handleVisibilityChange(), onKeyDown(), handleEvent(), propsAreEqual() 🔧 주요 변경 내용: • 핵심 비즈니스 로직 개선 • UI 컴포넌트 아키텍처 개선
This commit is contained in:
@@ -238,10 +238,10 @@ export const switchMediaToModal = (modalContainerId, modalClassName) => (dispatc
|
|||||||
export const minimizeModalMedia = () => (dispatch, getState) => {
|
export const minimizeModalMedia = () => (dispatch, getState) => {
|
||||||
const panels = getState().panels.panels;
|
const panels = getState().panels.panels;
|
||||||
|
|
||||||
console.log('[minimizeModalMedia] ========== Called ==========');
|
console.log('[Minimize] ========== Called ==========');
|
||||||
console.log('[minimizeModalMedia] Total panels:', panels.length);
|
console.log('[Minimize] Total panels:', panels.length);
|
||||||
console.log(
|
console.log(
|
||||||
'[minimizeModalMedia] All panels:',
|
'[Minimize] All panels:',
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal })),
|
panels.map((p) => ({ name: p.name, modal: p.panelInfo?.modal })),
|
||||||
null,
|
null,
|
||||||
@@ -253,15 +253,13 @@ export const minimizeModalMedia = () => (dispatch, getState) => {
|
|||||||
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
(panel) => panel.name === panel_names.MEDIA_PANEL && panel.panelInfo?.modal
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('[minimizeModalMedia] Found modalMediaPanel:', !!modalMediaPanel);
|
console.log('[Minimize] Found modalMediaPanel:', !!modalMediaPanel);
|
||||||
if (modalMediaPanel) {
|
if (modalMediaPanel) {
|
||||||
console.log(
|
console.log(
|
||||||
'[minimizeModalMedia] modalMediaPanel.panelInfo:',
|
'[Minimize] modalMediaPanel.panelInfo:',
|
||||||
JSON.stringify(modalMediaPanel.panelInfo, null, 2)
|
JSON.stringify(modalMediaPanel.panelInfo, null, 2)
|
||||||
);
|
);
|
||||||
console.log(
|
console.log('[Minimize] ✅ Minimizing modal MediaPanel (modal=false, isMinimized=true)');
|
||||||
'[minimizeModalMedia] ✅ Minimizing modal MediaPanel (modal=false, isMinimized=true)'
|
|
||||||
);
|
|
||||||
dispatch(
|
dispatch(
|
||||||
updatePanel({
|
updatePanel({
|
||||||
name: panel_names.MEDIA_PANEL,
|
name: panel_names.MEDIA_PANEL,
|
||||||
@@ -269,13 +267,14 @@ export const minimizeModalMedia = () => (dispatch, getState) => {
|
|||||||
...modalMediaPanel.panelInfo,
|
...modalMediaPanel.panelInfo,
|
||||||
modal: false, // fullscreen 모드로 전환
|
modal: false, // fullscreen 모드로 전환
|
||||||
isMinimized: true, // modal-minimized 클래스 적용 (1px 크기)
|
isMinimized: true, // modal-minimized 클래스 적용 (1px 크기)
|
||||||
|
shouldShrinkTo1px: true, // shrink 플래그 추가
|
||||||
// modalContainerId, modalClassName 등은 복원을 위해 유지
|
// modalContainerId, modalClassName 등은 복원을 위해 유지
|
||||||
// isPaused는 변경하지 않음 - 재생은 계속됨
|
// isPaused는 변경하지 않음 - 재생은 계속됨
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log('[minimizeModalMedia] ❌ No modal MediaPanel found - cannot minimize');
|
console.log('[Minimize] ❌ No modal MediaPanel found - cannot minimize');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -286,10 +285,10 @@ export const minimizeModalMedia = () => (dispatch, getState) => {
|
|||||||
export const restoreModalMedia = () => (dispatch, getState) => {
|
export const restoreModalMedia = () => (dispatch, getState) => {
|
||||||
const panels = getState().panels.panels;
|
const panels = getState().panels.panels;
|
||||||
|
|
||||||
console.log('[restoreModalMedia] ========== Called ==========');
|
console.log('[Restore]] ========== Called ==========');
|
||||||
console.log('[restoreModalMedia] Total panels:', panels.length);
|
console.log('[Restore] Total panels:', panels.length);
|
||||||
console.log(
|
console.log(
|
||||||
'[restoreModalMedia] All panels:',
|
'[Restore] All panels:',
|
||||||
JSON.stringify(
|
JSON.stringify(
|
||||||
panels.map((p) => ({
|
panels.map((p) => ({
|
||||||
name: p.name,
|
name: p.name,
|
||||||
@@ -325,6 +324,7 @@ export const restoreModalMedia = () => (dispatch, getState) => {
|
|||||||
...minimizedMediaPanel.panelInfo,
|
...minimizedMediaPanel.panelInfo,
|
||||||
modal: true, // modal 모드로 복원 (원래 위치로 복귀)
|
modal: true, // modal 모드로 복원 (원래 위치로 복귀)
|
||||||
isMinimized: false, // 최소화 해제
|
isMinimized: false, // 최소화 해제
|
||||||
|
shouldShrinkTo1px: false, // shrink 플래그 초기화
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
2674
com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js
Normal file
2674
com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.v3.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,843 @@
|
|||||||
|
// VideoPlayer.module.less
|
||||||
|
//
|
||||||
|
@import "~@enact/sandstone/styles/variables.less";
|
||||||
|
@import "~@enact/sandstone/styles/mixins.less";
|
||||||
|
@import "~@enact/sandstone/styles/skin.less";
|
||||||
|
@import "../../style/utils.module.less";
|
||||||
|
@import "../../style/CommonStyle.module.less";
|
||||||
|
.videoPlayer {
|
||||||
|
// Set by counting the IconButtons inside the side components.
|
||||||
|
--liftDistance: 0px;
|
||||||
|
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
:focus {
|
||||||
|
outline: none !important;
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.video {
|
||||||
|
height: calc(100% - 4px);
|
||||||
|
width: calc(100% - 4px);
|
||||||
|
background: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media {
|
||||||
|
height: calc(100% - 4px);
|
||||||
|
width: calc(100% - 4px);
|
||||||
|
background: #000;
|
||||||
|
|
||||||
|
&.mediaBackground {
|
||||||
|
&:after {
|
||||||
|
width: 560px;
|
||||||
|
height: 200px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 0;
|
||||||
|
content: "";
|
||||||
|
background: linear-gradient(
|
||||||
|
to top,
|
||||||
|
rgba(255, 255, 255, 1),
|
||||||
|
transparent
|
||||||
|
);
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.preloadVideo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thumbnail {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
> img {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
&.noRadiusThumbnail {
|
||||||
|
> img {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.verticalThumbnail {
|
||||||
|
> img {
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.smallThumbnail {
|
||||||
|
&::after {
|
||||||
|
.focused(@boxShadow:0, @borderRadius: 12px);
|
||||||
|
border: 6px solid @PRIMARY_COLOR_RED;
|
||||||
|
top: -4px;
|
||||||
|
right: -4px;
|
||||||
|
bottom: -4px;
|
||||||
|
left: -4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.disclaimer {
|
||||||
|
.size(@w: 100% , @h: 54px);
|
||||||
|
display: flex;
|
||||||
|
background-color: rgba(0, 0, 0, 0.9);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1;
|
||||||
|
> span {
|
||||||
|
.size(@w: 18px , @h: 18px);
|
||||||
|
background-image: url("../../../assets/images/icons/ic-alert-20@3x.png");
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
margin: 0 12px 0 20px;
|
||||||
|
}
|
||||||
|
> h3 {
|
||||||
|
.size(@w: 100% , @h: 54px);
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 54px;
|
||||||
|
.elip(@clamp:1);
|
||||||
|
.marquee {
|
||||||
|
width: 100%;
|
||||||
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.videoOverlayWithPhoneNumberFull {
|
||||||
|
bottom: 59px;
|
||||||
|
left: 141px;
|
||||||
|
}
|
||||||
|
.videoOverlayWithPhoneNumber {
|
||||||
|
display: none;
|
||||||
|
&.ru {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
width: 22%;
|
||||||
|
height: 12.5%;
|
||||||
|
bottom: 6.5% !important;
|
||||||
|
left: 48% !important;
|
||||||
|
padding: 4px !important;
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
> div:first-child {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 12px;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
margin-top: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
> img {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.us {
|
||||||
|
&.vertical {
|
||||||
|
width: 105px;
|
||||||
|
height: 66px;
|
||||||
|
bottom: 225px !important;
|
||||||
|
left: -96px !important;
|
||||||
|
}
|
||||||
|
&.horizontal {
|
||||||
|
> div:first-child {
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
> img {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 16px;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.qvc {
|
||||||
|
display: flex;
|
||||||
|
width: 18%;
|
||||||
|
height: 22%;
|
||||||
|
padding: 1%;
|
||||||
|
bottom: 4% !important;
|
||||||
|
left: 4.5% !important;
|
||||||
|
> div:first-child {
|
||||||
|
font-size: 48%;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
> img {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 48%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.hsn {
|
||||||
|
display: flex;
|
||||||
|
width: 18.5%;
|
||||||
|
height: 22%;
|
||||||
|
padding: 1%;
|
||||||
|
bottom: 4% !important;
|
||||||
|
left: 7% !important;
|
||||||
|
> div:first-child {
|
||||||
|
font-size: 48%;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
> img {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 48%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.verticalModal {
|
||||||
|
> div:last-child {
|
||||||
|
> img {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
> img {
|
||||||
|
width: 102px;
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div > img {
|
||||||
|
width: 34px;
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoOverlayMedia {
|
||||||
|
bottom: 24% !important;
|
||||||
|
left: 7% !important;
|
||||||
|
&.callToOrderHide {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
&.qvc {
|
||||||
|
display: flex;
|
||||||
|
width: 23%;
|
||||||
|
height: 15%;
|
||||||
|
padding: 30px 5px;
|
||||||
|
> div:first-child {
|
||||||
|
flex: none;
|
||||||
|
font-size: 13px !important;
|
||||||
|
line-height: 13px !important;
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
display: flex;
|
||||||
|
flex: none;
|
||||||
|
align-items: center;
|
||||||
|
height: 4px;
|
||||||
|
> img {
|
||||||
|
flex: none;
|
||||||
|
width: 13px;
|
||||||
|
height: 13px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
flex: none;
|
||||||
|
font-size: 15px;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.hsn {
|
||||||
|
display: flex;
|
||||||
|
width: 23%;
|
||||||
|
height: 15%;
|
||||||
|
padding: 30px 5px;
|
||||||
|
> div:first-child {
|
||||||
|
flex: none;
|
||||||
|
font-size: 13px !important;
|
||||||
|
line-height: 13px !important;
|
||||||
|
padding: 3px 5px;
|
||||||
|
}
|
||||||
|
> div:last-child {
|
||||||
|
display: flex;
|
||||||
|
flex: none;
|
||||||
|
align-items: center;
|
||||||
|
height: 4px;
|
||||||
|
> img {
|
||||||
|
flex: none;
|
||||||
|
width: 13px;
|
||||||
|
height: 13px;
|
||||||
|
}
|
||||||
|
> span {
|
||||||
|
flex: none;
|
||||||
|
font-size: 15px;
|
||||||
|
height: auto;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loaderWrap {
|
||||||
|
height: 100%;
|
||||||
|
> div {
|
||||||
|
width: 220px;
|
||||||
|
height: 220px;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
left: calc(50% - 110px);
|
||||||
|
top: calc(50% - 110px);
|
||||||
|
background-color: transparent;
|
||||||
|
> div {
|
||||||
|
> div {
|
||||||
|
-webkit-animation: mulShdSpinWhite 1.2s infinite ease !important;
|
||||||
|
animation: mulShdSpinWhite 1.2s infinite ease !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes mulShdSpinWhite {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em #fff,
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em #fff,
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
12.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7),
|
||||||
|
1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7),
|
||||||
|
1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff,
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff,
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
37.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff,
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff,
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff,
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff,
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
62.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff,
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff,
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff,
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff,
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
87.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff;
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mulShdSpinWhite {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em #fff,
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em #fff,
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
12.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7),
|
||||||
|
1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.7),
|
||||||
|
1.8em -1.8em 0 0em #fff, 2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff,
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.7), 2.5em 0em 0 0em #fff,
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
37.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff,
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.7), 1.75em 1.75em 0 0em #fff,
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff,
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.7), 0em 2.5em 0 0em #fff,
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
62.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff,
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.7), -1.8em 1.8em 0 0em #fff,
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff,
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.7), -2.6em 0em 0 0em #fff,
|
||||||
|
-1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
87.5% {
|
||||||
|
-webkit-box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff;
|
||||||
|
box-shadow: 0em -2.6em 0em 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.8em -1.8em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
2.5em 0em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
1.75em 1.75em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
0em 2.5em 0 0em rgba(255, 255, 255, 0.2),
|
||||||
|
-1.8em 1.8em 0 0em rgba(255, 255, 255, 0.5),
|
||||||
|
-2.6em 0em 0 0em rgba(255, 255, 255, 0.7), -1.8em -1.8em 0 0em #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
.position(@position: absolute, @top: 0, @right: 0, @bottom: 0, @left: 0);
|
||||||
|
}
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0.25turn);
|
||||||
|
}
|
||||||
|
33% {
|
||||||
|
transform: rotate(0.5turn);
|
||||||
|
}
|
||||||
|
80% {
|
||||||
|
transform: rotate(0.95turn);
|
||||||
|
}
|
||||||
|
85% {
|
||||||
|
transform: rotate(1turn);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(1.25turn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.spinner {
|
||||||
|
background-image: url("../../../assets/images/player/icon_loading.png");
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
position: relative;
|
||||||
|
background-size: cover;
|
||||||
|
border-radius: 20.8125rem;
|
||||||
|
overflow: hidden;
|
||||||
|
// margin: 490px auto;
|
||||||
|
left: calc(50% - 50px);
|
||||||
|
top: calc(50% - 50px);
|
||||||
|
animation: none 1.25s linear infinite;
|
||||||
|
animation-name: spin;
|
||||||
|
// animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.controlFeedbackBtnLayer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 50;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 94px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
&.lift {
|
||||||
|
transform: translateY(~"calc(var(--liftDistance) * -1)");
|
||||||
|
transition: transform 0.3s linear;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fullscreen {
|
||||||
|
.miniFeedback {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 50;
|
||||||
|
top: 506px;
|
||||||
|
left: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 94px;
|
||||||
|
-webkit-margin-end: 0px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
&.liveFullScreen {
|
||||||
|
.bottom {
|
||||||
|
bottom: 78px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bottom {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 3; // Value assigned as part of the VideoPlayer API so layers may be inserted in-between
|
||||||
|
bottom: 70px;
|
||||||
|
// bottom: 78px;
|
||||||
|
// bottom: -18px;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 70px;
|
||||||
|
// left: @sand-video-player-padding-side;
|
||||||
|
// right: @sand-video-player-padding-side;
|
||||||
|
|
||||||
|
&.videoVerticalBottom {
|
||||||
|
height: 54px;
|
||||||
|
}
|
||||||
|
&.lift {
|
||||||
|
transform: translateY(~"calc(var(--liftDistance) * -1)");
|
||||||
|
transition: transform 0.3s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.hidden {
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
.sliderContainer {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoFrame {
|
||||||
|
display: flex;
|
||||||
|
margin-left: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderContainer {
|
||||||
|
// display: flex;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
margin-left: 60px;
|
||||||
|
margin-right: 59px;
|
||||||
|
height: 70px;
|
||||||
|
bottom: -20px;
|
||||||
|
> *:first-child {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.enact-locale-rtl({
|
||||||
|
direction: ltr;
|
||||||
|
});
|
||||||
|
|
||||||
|
&.videoVertical {
|
||||||
|
margin-left: 680px;
|
||||||
|
margin-right: 673px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.controlsHandleAbove {
|
||||||
|
pointer-events: none;
|
||||||
|
.position(@position: absolute, @top: 0, @right: 0, @bottom: auto, @left: 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skin colors
|
||||||
|
.applySkins({
|
||||||
|
.fullscreen {
|
||||||
|
.bottom {
|
||||||
|
background-color: @sand-video-player-bottom-bg-color;
|
||||||
|
|
||||||
|
.infoFrame {
|
||||||
|
text-shadow: @sand-video-player-title-text-shadow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&.scrim::before,
|
||||||
|
&.scrim::after {
|
||||||
|
width: 1920px;
|
||||||
|
height: 50%;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
content: "";
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
&.scrim::before {
|
||||||
|
bottom: 0;
|
||||||
|
background: linear-gradient(0deg, rgba(0, 0, 0, 1) 0%, transparent 50%);
|
||||||
|
}
|
||||||
|
&.scrim::after {
|
||||||
|
top: 0;
|
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 1) 0%, transparent 50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
// &.scrim::after {
|
||||||
|
// background: @sand-video-player-scrim-gradient-color
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========== MediaPlayer.v2 Controls ==========
|
||||||
|
.controlsContainer {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
padding: 20px 40px 30px;
|
||||||
|
background: linear-gradient(to top, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.7) 60%, transparent 100%);
|
||||||
|
z-index: 10;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sliderContainer {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.times {
|
||||||
|
min-width: 80px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controlsButtons {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playPauseBtn {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
font-size: 24px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.6);
|
||||||
|
border-radius: 50%;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.95);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.backBtn {
|
||||||
|
padding: 12px 24px;
|
||||||
|
font-size: 18px;
|
||||||
|
background: rgba(255, 255, 255, 0.2);
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.6);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: white;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.2s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(255, 255, 255, 0.3);
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
}
|
||||||
15
com.twin.app.shoptime/src/hooks/useMediaPanelController.js
Normal file
15
com.twin.app.shoptime/src/hooks/useMediaPanelController.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import React, { createContext, useContext } from 'react';
|
||||||
|
|
||||||
|
const MediaPanelControllerContext = createContext(null);
|
||||||
|
|
||||||
|
export function MediaPanelControllerProvider({ controller, children }) {
|
||||||
|
return (
|
||||||
|
<MediaPanelControllerContext.Provider value={controller}>
|
||||||
|
{children}
|
||||||
|
</MediaPanelControllerContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMediaPanelController() {
|
||||||
|
return useContext(MediaPanelControllerContext);
|
||||||
|
}
|
||||||
@@ -1,41 +1,22 @@
|
|||||||
// src/views/DetailPanel/DetailPanel.new.jsx
|
// src/views/DetailPanel/DetailPanel.new.jsx
|
||||||
import React, {
|
import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useLayoutEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import {
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
useDispatch,
|
|
||||||
useSelector,
|
|
||||||
} from 'react-redux';
|
|
||||||
|
|
||||||
import Spotlight from '@enact/spotlight';
|
import Spotlight from '@enact/spotlight';
|
||||||
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
import { setContainerLastFocusedElement } from '@enact/spotlight/src/container';
|
||||||
|
|
||||||
import { getDeviceAdditionInfo } from '../../actions/deviceActions';
|
import { getDeviceAdditionInfo } from '../../actions/deviceActions';
|
||||||
import { getThemeCurationDetailInfo } from '../../actions/homeActions';
|
import { getThemeCurationDetailInfo } from '../../actions/homeActions';
|
||||||
import {
|
import { getMainCategoryDetail, getMainYouMayLike } from '../../actions/mainActions';
|
||||||
getMainCategoryDetail,
|
|
||||||
getMainYouMayLike,
|
|
||||||
} from '../../actions/mainActions';
|
|
||||||
import { finishModalMediaForce } from '../../actions/mediaActions';
|
import { finishModalMediaForce } from '../../actions/mediaActions';
|
||||||
import {
|
import { popPanel, updatePanel } from '../../actions/panelActions';
|
||||||
popPanel,
|
|
||||||
updatePanel,
|
|
||||||
} from '../../actions/panelActions';
|
|
||||||
import {
|
import {
|
||||||
finishVideoPreview,
|
finishVideoPreview,
|
||||||
pauseFullscreenVideo,
|
pauseFullscreenVideo,
|
||||||
resumeFullscreenVideo,
|
resumeFullscreenVideo,
|
||||||
} from '../../actions/playActions';
|
} from '../../actions/playActions';
|
||||||
import {
|
import { clearProductDetail, getProductOptionId } from '../../actions/productActions';
|
||||||
clearProductDetail,
|
|
||||||
getProductOptionId,
|
|
||||||
} from '../../actions/productActions';
|
|
||||||
import { clearAllToasts } from '../../actions/toastActions';
|
import { clearAllToasts } from '../../actions/toastActions';
|
||||||
import TBody from '../../components/TBody/TBody';
|
import TBody from '../../components/TBody/TBody';
|
||||||
import TPanel from '../../components/TPanel/TPanel';
|
import TPanel from '../../components/TPanel/TPanel';
|
||||||
@@ -148,7 +129,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
};
|
};
|
||||||
}, [dispatch]);
|
}, [dispatch]);
|
||||||
|
|
||||||
const onClick = useCallback(
|
const onBackClick = useCallback(
|
||||||
(isCancelClick) => (ev) => {
|
(isCancelClick) => (ev) => {
|
||||||
fp.pipe(
|
fp.pipe(
|
||||||
() => {
|
() => {
|
||||||
@@ -195,7 +176,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
|
|
||||||
const onBackButtonFocus = useCallback(() => {
|
const onBackButtonFocus = useCallback(() => {
|
||||||
dispatch(clearAllToasts());
|
dispatch(clearAllToasts());
|
||||||
},[dispatch])
|
}, [dispatch]);
|
||||||
|
|
||||||
const handleScrollToSection = useCallback(
|
const handleScrollToSection = useCallback(
|
||||||
(sectionId) => {
|
(sectionId) => {
|
||||||
@@ -429,13 +410,22 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
dispatch(
|
dispatch(
|
||||||
updatePanel({
|
updatePanel({
|
||||||
name: panel_names.DETAIL_PANEL,
|
name: panel_names.DETAIL_PANEL,
|
||||||
panelInfo: { shouldReload: false }
|
panelInfo: { shouldReload: false },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log('[DetailPanel] Reload complete');
|
console.log('[DetailPanel] Reload complete');
|
||||||
}
|
}
|
||||||
}, [panelShouldReload, dispatch, panelType, panelPatnrId, panelCurationId, panelBgImgNo, panelPrdtId, panelLiveReqFlag]);
|
}, [
|
||||||
|
panelShouldReload,
|
||||||
|
dispatch,
|
||||||
|
panelType,
|
||||||
|
panelPatnrId,
|
||||||
|
panelCurationId,
|
||||||
|
panelBgImgNo,
|
||||||
|
panelPrdtId,
|
||||||
|
panelLiveReqFlag,
|
||||||
|
]);
|
||||||
|
|
||||||
// 최근 본 상품 트리거 예시:
|
// 최근 본 상품 트리거 예시:
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
@@ -730,7 +720,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
<TPanel
|
<TPanel
|
||||||
isTabActivated={false}
|
isTabActivated={false}
|
||||||
className={css.detailPanelWrap}
|
className={css.detailPanelWrap}
|
||||||
handleCancel={onClick(true)}
|
handleCancel={onBackClick(true)}
|
||||||
spotlightId={spotlightId}
|
spotlightId={spotlightId}
|
||||||
>
|
>
|
||||||
<THeaderCustom
|
<THeaderCustom
|
||||||
@@ -738,7 +728,7 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
prdtId={productData?.prdtId}
|
prdtId={productData?.prdtId}
|
||||||
title={headerTitle}
|
title={headerTitle}
|
||||||
onBackButton
|
onBackButton
|
||||||
onClick={onClick(false)}
|
onClick={onBackClick(false)}
|
||||||
onBackButtonFocus={onBackButtonFocus}
|
onBackButtonFocus={onBackButtonFocus}
|
||||||
spotlightDisabled={isLoading}
|
spotlightDisabled={isLoading}
|
||||||
onSpotlightUp={onSpotlightUpTButton}
|
onSpotlightUp={onSpotlightUpTButton}
|
||||||
@@ -747,7 +737,6 @@ export default function DetailPanel({ panelInfo, isOnTop, spotlightId }) {
|
|||||||
ariaLabel={ariaLabel}
|
ariaLabel={ariaLabel}
|
||||||
logoImg={productData?.patncLogoPath}
|
logoImg={productData?.patncLogoPath}
|
||||||
patnrId={panelPatnrId}
|
patnrId={panelPatnrId}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
<TBody
|
<TBody
|
||||||
className={css.tbody}
|
className={css.tbody}
|
||||||
|
|||||||
@@ -1,40 +1,24 @@
|
|||||||
import React, {
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useRef,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
// import { throttle } from 'lodash';
|
// import { throttle } from 'lodash';
|
||||||
import { PropTypes } from 'prop-types';
|
import { PropTypes } from 'prop-types';
|
||||||
import {
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
useDispatch,
|
|
||||||
useSelector,
|
|
||||||
} from 'react-redux';
|
|
||||||
|
|
||||||
import Spotlight from '@enact/spotlight';
|
import Spotlight from '@enact/spotlight';
|
||||||
/* eslint-disable react/jsx-no-bind */
|
/* eslint-disable react/jsx-no-bind */
|
||||||
// src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx
|
// src/views/DetailPanel/ProductAllSection/ProductAllSection.jsx
|
||||||
import SpotlightContainerDecorator
|
import SpotlightContainerDecorator from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
from '@enact/spotlight/SpotlightContainerDecorator';
|
|
||||||
|
|
||||||
// import Spottable from '@enact/spotlight/Spottable';
|
// import Spottable from '@enact/spotlight/Spottable';
|
||||||
//image
|
//image
|
||||||
import arrowDown
|
import arrowDown from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
|
||||||
from '../../../../assets/images/icons/ic_arrow_down_3x_new.png';
|
import indicatorDefaultImage from '../../../../assets/images/img-thumb-empty-144@3x.png';
|
||||||
import indicatorDefaultImage
|
|
||||||
from '../../../../assets/images/img-thumb-empty-144@3x.png';
|
|
||||||
// import { pushPanel } from '../../../actions/panelActions';
|
// import { pushPanel } from '../../../actions/panelActions';
|
||||||
import { minimizeModalMedia, restoreModalMedia } from '../../../actions/mediaActions';
|
import { minimizeModalMedia, restoreModalMedia } from '../../../actions/mediaActions';
|
||||||
import { pauseFullscreenVideo } from '../../../actions/playActions';
|
import { pauseFullscreenVideo } from '../../../actions/playActions';
|
||||||
import { resetShowAllReviews } from '../../../actions/productActions';
|
import { resetShowAllReviews } from '../../../actions/productActions';
|
||||||
import {
|
import { clearAllToasts, removeToast, showToast } from '../../../actions/toastActions';
|
||||||
clearAllToasts,
|
|
||||||
removeToast,
|
|
||||||
showToast,
|
|
||||||
} from '../../../actions/toastActions';
|
|
||||||
// ProductInfoSection imports
|
// ProductInfoSection imports
|
||||||
import TButton from '../../../components/TButton/TButton';
|
import TButton from '../../../components/TButton/TButton';
|
||||||
import useReviews from '../../../hooks/useReviews/useReviews';
|
import useReviews from '../../../hooks/useReviews/useReviews';
|
||||||
@@ -67,16 +51,13 @@ import StarRating from '../components/StarRating';
|
|||||||
// ProductContentSection imports
|
// ProductContentSection imports
|
||||||
import TScrollerDetail from '../components/TScroller/TScrollerDetail';
|
import TScrollerDetail from '../components/TScroller/TScrollerDetail';
|
||||||
import DetailPanelSkeleton from '../DetailPanelSkeleton/DetailPanelSkeleton';
|
import DetailPanelSkeleton from '../DetailPanelSkeleton/DetailPanelSkeleton';
|
||||||
import ProductDescription
|
import ProductDescription from '../ProductContentSection/ProductDescription/ProductDescription';
|
||||||
from '../ProductContentSection/ProductDescription/ProductDescription';
|
import ProductDetail from '../ProductContentSection/ProductDetail/ProductDetail.new';
|
||||||
import ProductDetail
|
|
||||||
from '../ProductContentSection/ProductDetail/ProductDetail.new';
|
|
||||||
import { ProductVideoV2 } from '../ProductContentSection/ProductVideo/ProductVideo.v2.jsx';
|
import { ProductVideoV2 } from '../ProductContentSection/ProductVideo/ProductVideo.v2.jsx';
|
||||||
import ProductVideo from '../ProductContentSection/ProductVideo/ProductVideo';
|
import ProductVideo from '../ProductContentSection/ProductVideo/ProductVideo.v3';
|
||||||
import UserReviews from '../ProductContentSection/UserReviews/UserReviews';
|
import UserReviews from '../ProductContentSection/UserReviews/UserReviews';
|
||||||
// import ViewAllReviewsButton from '../ProductContentSection/UserReviews/ViewAllReviewsButton';
|
// import ViewAllReviewsButton from '../ProductContentSection/UserReviews/ViewAllReviewsButton';
|
||||||
import YouMayAlsoLike
|
import YouMayAlsoLike from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike';
|
||||||
from '../ProductContentSection/YouMayAlsoLike/YouMayAlsoLike';
|
|
||||||
import QRCode from '../ProductInfoSection/QRCode/QRCode';
|
import QRCode from '../ProductInfoSection/QRCode/QRCode';
|
||||||
import ProductOverview from '../ProductOverview/ProductOverview';
|
import ProductOverview from '../ProductOverview/ProductOverview';
|
||||||
// CSS imports
|
// CSS imports
|
||||||
@@ -120,10 +101,7 @@ const HorizontalContainer = SpotlightContainerDecorator(
|
|||||||
const getProductData = curry((productType, themeProductInfo, productInfo) =>
|
const getProductData = curry((productType, themeProductInfo, productInfo) =>
|
||||||
pipe(
|
pipe(
|
||||||
when(
|
when(
|
||||||
() =>
|
() => isVal(productType) && productType === 'theme' && isVal(themeProductInfo),
|
||||||
isVal(productType) &&
|
|
||||||
productType === 'theme' &&
|
|
||||||
isVal(themeProductInfo),
|
|
||||||
() => themeProductInfo
|
() => themeProductInfo
|
||||||
),
|
),
|
||||||
defaultTo(productInfo),
|
defaultTo(productInfo),
|
||||||
@@ -165,9 +143,7 @@ export default function ProductAllSection({
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
// Redux 상태
|
// Redux 상태
|
||||||
const webOSVersion = useSelector(
|
const webOSVersion = useSelector((state) => state.common.appStatus.webOSVersion);
|
||||||
(state) => state.common.appStatus.webOSVersion
|
|
||||||
);
|
|
||||||
const groupInfos = useSelector((state) => state.product.groupInfo);
|
const groupInfos = useSelector((state) => state.product.groupInfo);
|
||||||
|
|
||||||
// YouMayLike 데이터는 API 응답 시간이 걸리므로 직접 구독
|
// YouMayLike 데이터는 API 응답 시간이 걸리므로 직접 구독
|
||||||
@@ -275,9 +251,7 @@ export default function ProductAllSection({
|
|||||||
if (webOSVersion < '6.0') {
|
if (webOSVersion < '6.0') {
|
||||||
return (
|
return (
|
||||||
productData?.pmtSuptYn === 'N' ||
|
productData?.pmtSuptYn === 'N' ||
|
||||||
(productData?.pmtSuptYn === 'Y' &&
|
(productData?.pmtSuptYn === 'Y' && productData?.grPrdtProcYn === 'N' && panelInfo?.prdtId)
|
||||||
productData?.grPrdtProcYn === 'N' &&
|
|
||||||
panelInfo?.prdtId)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,10 +272,7 @@ export default function ProductAllSection({
|
|||||||
|
|
||||||
// 여행/테마 상품 - DetailPanel.backup.jsx와 동일한 로직
|
// 여행/테마 상품 - DetailPanel.backup.jsx와 동일한 로직
|
||||||
const isTravelProductVisible = useMemo(() => {
|
const isTravelProductVisible = useMemo(() => {
|
||||||
return (
|
return panelInfo?.curationId && (panelInfo?.type === 'theme' || panelInfo?.type === 'hotel');
|
||||||
panelInfo?.curationId &&
|
|
||||||
(panelInfo?.type === 'theme' || panelInfo?.type === 'hotel')
|
|
||||||
);
|
|
||||||
}, [panelInfo]);
|
}, [panelInfo]);
|
||||||
|
|
||||||
// useReviews Hook 사용 - 모든 리뷰 관련 로직을 담당
|
// useReviews Hook 사용 - 모든 리뷰 관련 로직을 담당
|
||||||
@@ -374,47 +345,50 @@ export default function ProductAllSection({
|
|||||||
// reviewListData가 반복적으로 초기화되어 Chrome에서 진입 불가 발생
|
// reviewListData가 반복적으로 초기화되어 Chrome에서 진입 불가 발생
|
||||||
|
|
||||||
// BUY NOW 버튼 클릭 핸들러 - Toast로 BuyOption 표시
|
// BUY NOW 버튼 클릭 핸들러 - Toast로 BuyOption 표시
|
||||||
const handleBuyNowClick = useCallback((e) => {
|
const handleBuyNowClick = useCallback(
|
||||||
// console.log('[BuyNow] Buy Now button clicked');
|
(e) => {
|
||||||
e.stopPropagation();
|
// console.log('[BuyNow] Buy Now button clicked');
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
console.log('[ProductAllSection] 🛒 BUY NOW clicked - productData:', {
|
console.log('[ProductAllSection] 🛒 BUY NOW clicked - productData:', {
|
||||||
prdtId: productData?.prdtId,
|
prdtId: productData?.prdtId,
|
||||||
patnrId: productData?.patnrId,
|
patnrId: productData?.patnrId,
|
||||||
prdtNm: productData?.prdtNm,
|
prdtNm: productData?.prdtNm,
|
||||||
hasProductData: !!productData,
|
hasProductData: !!productData,
|
||||||
});
|
});
|
||||||
if(openToast === false){
|
if (openToast === false) {
|
||||||
dispatch(
|
dispatch(
|
||||||
showToast({
|
showToast({
|
||||||
id: productData.prdtId,
|
id: productData.prdtId,
|
||||||
message: '',
|
message: '',
|
||||||
type: 'buyOption',
|
type: 'buyOption',
|
||||||
duration: 0,
|
duration: 0,
|
||||||
position: 'bottom-center',
|
position: 'bottom-center',
|
||||||
// 🚀 BuyOption에 전달할 props 데이터
|
// 🚀 BuyOption에 전달할 props 데이터
|
||||||
productInfo: productData,
|
productInfo: productData,
|
||||||
selectedPatnrId: productData?.patnrId,
|
selectedPatnrId: productData?.patnrId,
|
||||||
selectedPrdtId: productData?.prdtId,
|
selectedPrdtId: productData?.prdtId,
|
||||||
// BuyOption Toast가 닫힐 때 BUY NOW 버튼으로 포커스 복구
|
// BuyOption Toast가 닫힐 때 BUY NOW 버튼으로 포커스 복구
|
||||||
onToastClose: () => {
|
onToastClose: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setOpenToast(false);
|
setOpenToast(false);
|
||||||
Spotlight.focus('detail-buy-now-button');
|
Spotlight.focus('detail-buy-now-button');
|
||||||
}, 100);
|
}, 100);
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
setOpenToast(true);
|
setOpenToast(true);
|
||||||
}
|
}
|
||||||
}, [dispatch, productData, openToast]);
|
},
|
||||||
|
[dispatch, productData, openToast]
|
||||||
|
);
|
||||||
|
|
||||||
//닫히도록
|
//닫히도록
|
||||||
const handleCloseToast = useCallback(() => {
|
const handleCloseToast = useCallback(() => {
|
||||||
dispatch(clearAllToasts());
|
dispatch(clearAllToasts());
|
||||||
setOpenToast(false);
|
setOpenToast(false);
|
||||||
},[dispatch])
|
}, [dispatch]);
|
||||||
|
|
||||||
// 스크롤 컨테이너의 클릭 이벤트 추적용 로깅
|
// 스크롤 컨테이너의 클릭 이벤트 추적용 로깅
|
||||||
const handleScrollContainerClick = useCallback((e) => {
|
const handleScrollContainerClick = useCallback((e) => {
|
||||||
@@ -425,11 +399,14 @@ export default function ProductAllSection({
|
|||||||
bubbles: e.bubbles,
|
bubbles: e.bubbles,
|
||||||
defaultPrevented: e.defaultPrevented,
|
defaultPrevented: e.defaultPrevented,
|
||||||
timestamp: new Date().getTime(),
|
timestamp: new Date().getTime(),
|
||||||
eventPath: e.composedPath?.().slice(0, 5).map(el => ({
|
eventPath: e
|
||||||
tag: el.tagName,
|
.composedPath?.()
|
||||||
className: el.className,
|
.slice(0, 5)
|
||||||
id: el.id
|
.map((el) => ({
|
||||||
}))
|
tag: el.tagName,
|
||||||
|
className: el.className,
|
||||||
|
id: el.id,
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -441,11 +418,14 @@ export default function ProductAllSection({
|
|||||||
currentTarget: e.currentTarget?.className,
|
currentTarget: e.currentTarget?.className,
|
||||||
bubbles: e.bubbles,
|
bubbles: e.bubbles,
|
||||||
defaultPrevented: e.defaultPrevented,
|
defaultPrevented: e.defaultPrevented,
|
||||||
eventPath: e.composedPath?.().slice(0, 8).map(el => ({
|
eventPath: e
|
||||||
tag: el.tagName,
|
.composedPath?.()
|
||||||
className: el.className,
|
.slice(0, 8)
|
||||||
id: el.id
|
.map((el) => ({
|
||||||
}))
|
tag: el.tagName,
|
||||||
|
className: el.className,
|
||||||
|
id: el.id,
|
||||||
|
})),
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@@ -455,10 +435,7 @@ export default function ProductAllSection({
|
|||||||
// TODO: 장바구니 추가 로직 구현
|
// TODO: 장바구니 추가 로직 구현
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const { revwGrd, orderPhnNo } = useMemo(
|
const { revwGrd, orderPhnNo } = useMemo(() => extractProductMeta(productInfo), [productInfo]);
|
||||||
() => extractProductMeta(productInfo),
|
|
||||||
[productInfo]
|
|
||||||
);
|
|
||||||
|
|
||||||
const [favoriteOverride, setFavoriteOverride] = useState(null);
|
const [favoriteOverride, setFavoriteOverride] = useState(null);
|
||||||
const favoriteFlag = useMemo(
|
const favoriteFlag = useMemo(
|
||||||
@@ -467,8 +444,7 @@ export default function ProductAllSection({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const [mobileSendPopupOpen, setMobileSendPopupOpen] = useState(false);
|
const [mobileSendPopupOpen, setMobileSendPopupOpen] = useState(false);
|
||||||
const [isShowUserReviewsFocused, setIsShowUserReviewsFocused] =
|
const [isShowUserReviewsFocused, setIsShowUserReviewsFocused] = useState(false);
|
||||||
useState(false);
|
|
||||||
|
|
||||||
const reviewTotalCount = stats.totalReviews;
|
const reviewTotalCount = stats.totalReviews;
|
||||||
|
|
||||||
@@ -491,12 +467,9 @@ export default function ProductAllSection({
|
|||||||
);
|
);
|
||||||
|
|
||||||
// User Reviews 스크롤 핸들러 추가
|
// User Reviews 스크롤 핸들러 추가
|
||||||
const handleUserReviewsClick = useCallback(
|
const handleUserReviewsClick = useCallback(() => {
|
||||||
() => {
|
scrollToSection('scroll-marker-user-reviews');
|
||||||
scrollToSection('scroll-marker-user-reviews');
|
}, [scrollToSection]);
|
||||||
},
|
|
||||||
[scrollToSection]
|
|
||||||
);
|
|
||||||
|
|
||||||
// ProductVideo V1 전용 - MediaPanel minimize 포함
|
// ProductVideo V1 전용 - MediaPanel minimize 포함
|
||||||
const handleScrollToImagesV1 = useCallback(() => {
|
const handleScrollToImagesV1 = useCallback(() => {
|
||||||
@@ -571,11 +544,7 @@ export default function ProductAllSection({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 이미지들 추가
|
// 이미지들 추가
|
||||||
if (
|
if (productData && productData.imgUrls600 && productData.imgUrls600.length > 0) {
|
||||||
productData &&
|
|
||||||
productData.imgUrls600 &&
|
|
||||||
productData.imgUrls600.length > 0
|
|
||||||
) {
|
|
||||||
productData.imgUrls600.forEach((image, imgIndex) => {
|
productData.imgUrls600.forEach((image, imgIndex) => {
|
||||||
items.push({
|
items.push({
|
||||||
type: 'image',
|
type: 'image',
|
||||||
@@ -595,9 +564,7 @@ export default function ProductAllSection({
|
|||||||
// renderItems에 Video가 존재하는지 확인하는 boolean 상태
|
// renderItems에 Video가 존재하는지 확인하는 boolean 상태
|
||||||
const hasVideo = useMemo(() => {
|
const hasVideo = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
renderItems &&
|
renderItems && renderItems.length > 0 && renderItems.some((item) => item.type === 'video')
|
||||||
renderItems.length > 0 &&
|
|
||||||
renderItems.some((item) => item.type === 'video')
|
|
||||||
);
|
);
|
||||||
}, [renderItems]);
|
}, [renderItems]);
|
||||||
|
|
||||||
@@ -640,10 +607,7 @@ export default function ProductAllSection({
|
|||||||
pipe(
|
pipe(
|
||||||
() => setOpenThemeItemOverlay(true),
|
() => setOpenThemeItemOverlay(true),
|
||||||
tap(() => {
|
tap(() => {
|
||||||
const timerId = setTimeout(
|
const timerId = setTimeout(() => Spotlight.focus('theme-close-button'), 0);
|
||||||
() => Spotlight.focus('theme-close-button'),
|
|
||||||
0
|
|
||||||
);
|
|
||||||
timersRef.current.push(timerId);
|
timersRef.current.push(timerId);
|
||||||
})
|
})
|
||||||
),
|
),
|
||||||
@@ -661,6 +625,9 @@ export default function ProductAllSection({
|
|||||||
);
|
);
|
||||||
const scrollPositionRef = useRef(0);
|
const scrollPositionRef = useRef(0);
|
||||||
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
const prevScrollPositionRef = useRef(0); // 이전 스크롤 위치 추적
|
||||||
|
const prevScrollTopRef = useRef(0); // HomePanel 스타일 스크롤 위치 추적
|
||||||
|
const scrollExpandTimerRef = useRef(null); // 스크롤 확장 타이머
|
||||||
|
const mediaMinimizedRef = useRef(false);
|
||||||
|
|
||||||
const handleArrowClickAlternative = useCallback(() => {
|
const handleArrowClickAlternative = useCallback(() => {
|
||||||
const currentHeight = scrollPositionRef.current;
|
const currentHeight = scrollPositionRef.current;
|
||||||
@@ -672,8 +639,7 @@ export default function ProductAllSection({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// documentHeight를 활용하여 반복 계산 제거
|
// documentHeight를 활용하여 반복 계산 제거
|
||||||
const totalHeight =
|
const totalHeight = documentHeight + (youMayAlsoLikelRef.current?.scrollHeight || 0);
|
||||||
documentHeight + (youMayAlsoLikelRef.current?.scrollHeight || 0);
|
|
||||||
const isAtBottom = scrollPositionRef.current + 1100 >= totalHeight;
|
const isAtBottom = scrollPositionRef.current + 1100 >= totalHeight;
|
||||||
|
|
||||||
if (isAtBottom) {
|
if (isAtBottom) {
|
||||||
@@ -681,20 +647,71 @@ export default function ProductAllSection({
|
|||||||
}
|
}
|
||||||
}, [documentHeight, scrollTop]);
|
}, [documentHeight, scrollTop]);
|
||||||
|
|
||||||
// const handleScroll = useCallback(
|
const handleScroll = useCallback(
|
||||||
// (e) => {
|
(e) => {
|
||||||
// scrollPositionRef.current = e.scrollTop;
|
const currentScrollTop = e.scrollTop;
|
||||||
// if (documentHeight) {
|
const prevScrollTop = prevScrollTopRef.current;
|
||||||
// const isAtBottom =
|
|
||||||
// scrollPositionRef.current + 944 >=
|
scrollPositionRef.current = currentScrollTop;
|
||||||
// documentHeight + (youMayAlsoLikelRef.current?.scrollHeight || 0);
|
|
||||||
// if (isAtBottom !== isBottom) {
|
// 기존 bottom 체크 로직 유지
|
||||||
// setIsBottom(isAtBottom);
|
if (documentHeight) {
|
||||||
// }
|
const isAtBottom =
|
||||||
// }
|
scrollPositionRef.current + 944 >=
|
||||||
// },
|
documentHeight + (youMayAlsoLikelRef.current?.scrollHeight || 0);
|
||||||
// [documentHeight, isBottom]
|
if (isAtBottom !== isBottom) {
|
||||||
// );
|
setIsBottom(isAtBottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔽 ProductVideo (v3.jsx)에만 HomePanel 스타일 즉각 스크롤 로직 적용
|
||||||
|
// ProductVideo.v3.jsx는 ProductVideo로 import되어 productVideoVersion === 1일 때 사용됨
|
||||||
|
if (productVideoVersion === 1) {
|
||||||
|
const isScrollingDown = currentScrollTop > prevScrollTop;
|
||||||
|
|
||||||
|
prevScrollTopRef.current = currentScrollTop;
|
||||||
|
|
||||||
|
// 아래로 스크롤: 즉시 1px 축소 (HomePanel과 동일)
|
||||||
|
if (isScrollingDown && currentScrollTop > 0) {
|
||||||
|
console.log('🚀 [ProductVideo.v3] onScroll Down - immediate minimize');
|
||||||
|
dispatch(minimizeModalMedia());
|
||||||
|
setShouldMinimizeMedia(true);
|
||||||
|
|
||||||
|
// 기존 타이머 취소
|
||||||
|
if (scrollExpandTimerRef.current) {
|
||||||
|
clearTimeout(scrollExpandTimerRef.current);
|
||||||
|
scrollExpandTimerRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 위로 스크롤 (최상단 아님): 1초 후 복구
|
||||||
|
else if (!isScrollingDown && currentScrollTop > 1) {
|
||||||
|
console.log('🚀 [ProductVideo.v3] onScroll Up - expand after 1s');
|
||||||
|
|
||||||
|
if (scrollExpandTimerRef.current) {
|
||||||
|
clearTimeout(scrollExpandTimerRef.current);
|
||||||
|
}
|
||||||
|
scrollExpandTimerRef.current = setTimeout(() => {
|
||||||
|
dispatch(restoreModalMedia());
|
||||||
|
setShouldMinimizeMedia(false);
|
||||||
|
scrollExpandTimerRef.current = null;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
// 최상단 도달: 즉시 복구 (HomePanel과 동일)
|
||||||
|
else if (currentScrollTop <= 1) {
|
||||||
|
console.log('🚀 [ProductVideo.v3] onScroll AtTop - immediate expand');
|
||||||
|
dispatch(restoreModalMedia());
|
||||||
|
setShouldMinimizeMedia(false);
|
||||||
|
|
||||||
|
if (scrollExpandTimerRef.current) {
|
||||||
|
clearTimeout(scrollExpandTimerRef.current);
|
||||||
|
scrollExpandTimerRef.current = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// v2: onScrollStop에서 처리 (기존 로직 유지)
|
||||||
|
},
|
||||||
|
[documentHeight, isBottom, productVideoVersion, dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
// 스크롤 멈추었을 때만 호출 (성능 최적화)
|
// 스크롤 멈추었을 때만 호출 (성능 최적화)
|
||||||
const handleScrollStop = useCallback(
|
const handleScrollStop = useCallback(
|
||||||
@@ -712,13 +729,29 @@ export default function ProductAllSection({
|
|||||||
}
|
}
|
||||||
|
|
||||||
console.log('📍 [ProductAllSection] 스크롤 멈춤 - 위치:', currentScrollTop);
|
console.log('📍 [ProductAllSection] 스크롤 멈춤 - 위치:', currentScrollTop);
|
||||||
|
|
||||||
const shouldMinimize = currentScrollTop > 0;
|
const shouldMinimize = currentScrollTop > 0;
|
||||||
console.log('📍 [ProductAllSection] setShouldMinimizeMedia 호출:', shouldMinimize);
|
setShouldMinimizeMedia((prev) => {
|
||||||
setShouldMinimizeMedia(shouldMinimize); // state 업데이트만
|
if (prev === shouldMinimize) return prev;
|
||||||
|
console.log('📍 [ProductAllSection] setShouldMinimizeMedia 호출:', shouldMinimize);
|
||||||
|
return shouldMinimize;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[documentHeight, isBottom]
|
[documentHeight, isBottom]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldMinimizeMedia && !mediaMinimizedRef.current) {
|
||||||
|
console.log('📍 [ProductAllSection] MediaPanel 최소화 (effect)');
|
||||||
|
dispatch(minimizeModalMedia());
|
||||||
|
mediaMinimizedRef.current = true;
|
||||||
|
} else if (!shouldMinimizeMedia && mediaMinimizedRef.current) {
|
||||||
|
console.log('📍 [ProductAllSection] MediaPanel 복원 (effect)');
|
||||||
|
dispatch(restoreModalMedia());
|
||||||
|
mediaMinimizedRef.current = false;
|
||||||
|
}
|
||||||
|
}, [shouldMinimizeMedia, dispatch]);
|
||||||
|
|
||||||
const handleButtonFocus = useCallback((buttonType) => {
|
const handleButtonFocus = useCallback((buttonType) => {
|
||||||
if (activeButton !== buttonType) {
|
if (activeButton !== buttonType) {
|
||||||
setActiveButton(buttonType);
|
setActiveButton(buttonType);
|
||||||
@@ -829,6 +862,12 @@ export default function ProductAllSection({
|
|||||||
scrollToImagesTimeoutRef.current = null;
|
scrollToImagesTimeoutRef.current = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔽 스크롤 확장 타이머 cleanup 추가
|
||||||
|
if (scrollExpandTimerRef.current) {
|
||||||
|
clearTimeout(scrollExpandTimerRef.current);
|
||||||
|
scrollExpandTimerRef.current = null;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('[ProductAllSection] cleanup 완료 on unmount');
|
console.log('[ProductAllSection] cleanup 완료 on unmount');
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
@@ -875,11 +914,7 @@ export default function ProductAllSection({
|
|||||||
>
|
>
|
||||||
<div className={css.qrWrapper}>
|
<div className={css.qrWrapper}>
|
||||||
{isShowQRCode ? (
|
{isShowQRCode ? (
|
||||||
<QRCode
|
<QRCode productInfo={productData} productType={productType} kind={'detail'} />
|
||||||
productInfo={productData}
|
|
||||||
productType={productType}
|
|
||||||
kind={'detail'}
|
|
||||||
/>
|
|
||||||
) : (
|
) : (
|
||||||
<div className={css.qrRollingWrap}>
|
<div className={css.qrRollingWrap}>
|
||||||
<div className={css.innerText}>
|
<div className={css.innerText}>
|
||||||
@@ -929,9 +964,7 @@ export default function ProductAllSection({
|
|||||||
onClick={handleShopByMobileOpen}
|
onClick={handleShopByMobileOpen}
|
||||||
onSpotlightUp={handleSpotlightUpToBackButton}
|
onSpotlightUp={handleSpotlightUpToBackButton}
|
||||||
>
|
>
|
||||||
<div className={css.shopByMobileText}>
|
<div className={css.shopByMobileText}>{$L('SHOP BY MOBILE')}</div>
|
||||||
{$L('SHOP BY MOBILE')}
|
|
||||||
</div>
|
|
||||||
</TButton>
|
</TButton>
|
||||||
{panelInfo && (
|
{panelInfo && (
|
||||||
<div className={css.favoriteBtnWrapper}>
|
<div className={css.favoriteBtnWrapper}>
|
||||||
@@ -950,9 +983,7 @@ export default function ProductAllSection({
|
|||||||
<div className={css.callToOrderSection}>
|
<div className={css.callToOrderSection}>
|
||||||
{orderPhnNo && (
|
{orderPhnNo && (
|
||||||
<>
|
<>
|
||||||
<div className={css.callToOrderText}>
|
<div className={css.callToOrderText}>{$L('Call to Order')}</div>
|
||||||
{$L('Call to Order')}
|
|
||||||
</div>
|
|
||||||
<div className={css.phoneSection}>
|
<div className={css.phoneSection}>
|
||||||
<div className={css.phoneIconContainer}>
|
<div className={css.phoneIconContainer}>
|
||||||
<div className={css.phoneIcon} />
|
<div className={css.phoneIcon} />
|
||||||
@@ -979,7 +1010,7 @@ export default function ProductAllSection({
|
|||||||
</TButton>
|
</TButton>
|
||||||
{isReviewDataComplete && (
|
{isReviewDataComplete && (
|
||||||
<>
|
<>
|
||||||
{/*
|
{/*
|
||||||
{console.log('[ProductAllSection_useReviewList] 🎯 버튼 렌더링:', {
|
{console.log('[ProductAllSection_useReviewList] 🎯 버튼 렌더링:', {
|
||||||
hasReviews,
|
hasReviews,
|
||||||
reviewTotalCount,
|
reviewTotalCount,
|
||||||
@@ -1020,17 +1051,15 @@ export default function ProductAllSection({
|
|||||||
})()} */}
|
})()} */}
|
||||||
</Container>
|
</Container>
|
||||||
|
|
||||||
{panelInfo &&
|
{panelInfo && panelInfo.type === 'theme' && !openThemeItemOverlay && (
|
||||||
panelInfo.type === 'theme' &&
|
<TButton
|
||||||
!openThemeItemOverlay && (
|
className={css.themeButton}
|
||||||
<TButton
|
onClick={handleThemeItemButtonClick}
|
||||||
className={css.themeButton}
|
spotlightId="theme-open-button"
|
||||||
onClick={handleThemeItemButtonClick}
|
>
|
||||||
spotlightId="theme-open-button"
|
{$L('THEME ITEM')}
|
||||||
>
|
</TButton>
|
||||||
{$L('THEME ITEM')}
|
)}
|
||||||
</TButton>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<DetailMobileSendPopUp
|
<DetailMobileSendPopUp
|
||||||
ismobileSendPopupOpen={mobileSendPopupOpen}
|
ismobileSendPopupOpen={mobileSendPopupOpen}
|
||||||
@@ -1060,7 +1089,7 @@ export default function ProductAllSection({
|
|||||||
spotlightId="main-content-scroller"
|
spotlightId="main-content-scroller"
|
||||||
spotlightDisabled={false}
|
spotlightDisabled={false}
|
||||||
spotlightRestrict="none"
|
spotlightRestrict="none"
|
||||||
// onScroll={handleScroll}
|
onScroll={handleScroll}
|
||||||
onScrollStop={handleScrollStop}
|
onScrollStop={handleScrollStop}
|
||||||
onClick={handleScrollContainerClick}
|
onClick={handleScrollContainerClick}
|
||||||
>
|
>
|
||||||
@@ -1073,36 +1102,32 @@ export default function ProductAllSection({
|
|||||||
onBlur={handleButtonBlur}
|
onBlur={handleButtonBlur}
|
||||||
>
|
>
|
||||||
{/* 비디오가 있으면 먼저 렌더링 (productVideoVersion이 3이 아닐 때만) */}
|
{/* 비디오가 있으면 먼저 렌더링 (productVideoVersion이 3이 아닐 때만) */}
|
||||||
{hasVideo &&
|
{hasVideo && renderItems[0].type === 'video' && productVideoVersion !== 3 && (
|
||||||
renderItems[0].type === 'video' &&
|
<>
|
||||||
productVideoVersion !== 3 && (
|
{productVideoVersion === 1 ? (
|
||||||
<>
|
<ProductVideo
|
||||||
{productVideoVersion === 1 ? (
|
key="product-video-0"
|
||||||
<ProductVideo
|
productInfo={productData}
|
||||||
key="product-video-0"
|
videoUrl={renderItems[0].url}
|
||||||
productInfo={productData}
|
thumbnailUrl={renderItems[0].thumbnail}
|
||||||
videoUrl={renderItems[0].url}
|
autoPlay={true}
|
||||||
thumbnailUrl={renderItems[0].thumbnail}
|
continuousPlay={true}
|
||||||
autoPlay={true}
|
onScrollToImages={handleScrollToImagesV1}
|
||||||
continuousPlay={true}
|
onFocus={() => console.log('[ProductVideo V1] Focused')}
|
||||||
onScrollToImages={handleScrollToImagesV1}
|
/>
|
||||||
/>
|
) : (
|
||||||
) : (
|
<ProductVideoV2
|
||||||
<ProductVideoV2
|
key="product-video-v2-0"
|
||||||
key="product-video-v2-0"
|
productInfo={productData}
|
||||||
productInfo={productData}
|
videoUrl={renderItems[0].url}
|
||||||
videoUrl={renderItems[0].url}
|
thumbnailUrl={renderItems[0].thumbnail}
|
||||||
thumbnailUrl={renderItems[0].thumbnail}
|
autoPlay={true}
|
||||||
autoPlay={true}
|
onScrollToImages={handleScrollToImagesV2}
|
||||||
onScrollToImages={handleScrollToImagesV2}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
<div id="scroll-marker-after-video" className={css.scrollMarker}></div>
|
||||||
<div
|
</>
|
||||||
id="scroll-marker-after-video"
|
)}
|
||||||
className={css.scrollMarker}
|
|
||||||
></div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 이미지들만 렌더링 (비디오 제외) */}
|
{/* 이미지들만 렌더링 (비디오 제외) */}
|
||||||
{renderItems.length > 0
|
{renderItems.length > 0
|
||||||
@@ -1121,10 +1146,7 @@ export default function ProductAllSection({
|
|||||||
))
|
))
|
||||||
: !hasVideo && <ProductDetail productInfo={productData} />}
|
: !hasVideo && <ProductDetail productInfo={productData} />}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div id="scroll-marker-product-details" className={css.scrollMarker}></div>
|
||||||
id="scroll-marker-product-details"
|
|
||||||
className={css.scrollMarker}
|
|
||||||
></div>
|
|
||||||
<div
|
<div
|
||||||
id="product-description-section"
|
id="product-description-section"
|
||||||
ref={descriptionRef}
|
ref={descriptionRef}
|
||||||
@@ -1134,10 +1156,7 @@ export default function ProductAllSection({
|
|||||||
<ProductDescription productInfo={productData} />
|
<ProductDescription productInfo={productData} />
|
||||||
</div>
|
</div>
|
||||||
{/* 리뷰 데이터가 완전할 때만 UserReviews 섹션 표시 */}
|
{/* 리뷰 데이터가 완전할 때만 UserReviews 섹션 표시 */}
|
||||||
<div
|
<div id="scroll-marker-user-reviews" className={css.scrollMarker}></div>
|
||||||
id="scroll-marker-user-reviews"
|
|
||||||
className={css.scrollMarker}
|
|
||||||
></div>
|
|
||||||
{isReviewDataComplete && (
|
{isReviewDataComplete && (
|
||||||
<div
|
<div
|
||||||
id="user-reviews-section"
|
id="user-reviews-section"
|
||||||
@@ -1165,10 +1184,7 @@ export default function ProductAllSection({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div ref={youMayAlsoLikelRef}>
|
<div ref={youMayAlsoLikelRef}>
|
||||||
<div
|
<div id="scroll-marker-you-may-also-like" className={css.scrollMarker}></div>
|
||||||
id="scroll-marker-you-may-also-like"
|
|
||||||
className={css.scrollMarker}
|
|
||||||
></div>
|
|
||||||
{hasYouMayAlsoLike && (
|
{hasYouMayAlsoLike && (
|
||||||
<div id="you-may-also-like-section">
|
<div id="you-may-also-like-section">
|
||||||
{/* {(() => {
|
{/* {(() => {
|
||||||
|
|||||||
@@ -120,8 +120,6 @@
|
|||||||
padding: 0 15px 0 30px;
|
padding: 0 15px 0 30px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export default function ProductVideo({
|
|||||||
onScrollToImages,
|
onScrollToImages,
|
||||||
autoPlay = false, // 자동 재생 여부
|
autoPlay = false, // 자동 재생 여부
|
||||||
continuousPlay = false, // 반복 재생 여부
|
continuousPlay = false, // 반복 재생 여부
|
||||||
|
onFocus = null, // 외부에서 전달된 포커스 핸들러
|
||||||
}) {
|
}) {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
@@ -115,8 +116,13 @@ export default function ProductVideo({
|
|||||||
console.log('[ProductVideo] Calling restoreModalMedia');
|
console.log('[ProductVideo] Calling restoreModalMedia');
|
||||||
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
||||||
// dispatch(restoreModalMedia());
|
// dispatch(restoreModalMedia());
|
||||||
|
|
||||||
|
// 외부에서 전달된 onFocus 핸들러도 호출
|
||||||
|
if (onFocus) {
|
||||||
|
onFocus();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [canPlayVideo, dispatch]);
|
}, [canPlayVideo, dispatch, onFocus]);
|
||||||
|
|
||||||
const videoContainerOnBlur = useCallback(() => {
|
const videoContainerOnBlur = useCallback(() => {
|
||||||
console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
||||||
|
|||||||
@@ -614,12 +614,7 @@ export function ProductVideoV2({
|
|||||||
debugLog('[Fullscreen Container] Enter key - overlay visible, allow default behavior');
|
debugLog('[Fullscreen Container] Enter key - overlay visible, allow default behavior');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[
|
[isPlaying, isFullscreen, toggleOverlayVisibility, mediaOverlayState.controls?.visible]
|
||||||
isPlaying,
|
|
||||||
isFullscreen,
|
|
||||||
toggleOverlayVisibility,
|
|
||||||
mediaOverlayState.controls?.visible,
|
|
||||||
]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// 마우스 다운 (클릭) 이벤트 - capture phase에서 처리
|
// 마우스 다운 (클릭) 이벤트 - capture phase에서 처리
|
||||||
@@ -1178,6 +1173,3 @@ export function ProductVideoV2({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
import React, { useCallback, useMemo, useState, useEffect } from 'react';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
|
import {
|
||||||
|
startMediaPlayer,
|
||||||
|
finishMediaPreview,
|
||||||
|
switchMediaToFullscreen,
|
||||||
|
minimizeModalMedia,
|
||||||
|
restoreModalMedia,
|
||||||
|
} from '../../../../actions/mediaActions';
|
||||||
|
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';
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable('div');
|
||||||
|
|
||||||
|
export default function ProductVideo({
|
||||||
|
productInfo,
|
||||||
|
videoUrl,
|
||||||
|
thumbnailUrl,
|
||||||
|
onScrollToImages,
|
||||||
|
autoPlay = false, // 자동 재생 여부
|
||||||
|
continuousPlay = false, // 반복 재생 여부
|
||||||
|
onFocus = null, // 외부에서 전달된 포커스 핸들러
|
||||||
|
}) {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
// MediaPanel 상태 체크를 위한 selectors 추가
|
||||||
|
const panels = useSelector((state) => state.panels.panels);
|
||||||
|
const [isLaunchedFromPlayer, setIsLaunchedFromPlayer] = useState(false);
|
||||||
|
const [focused, setFocused] = useState(false);
|
||||||
|
const [modalState, setModalState] = useState(true); // 모달 상태 관리 추가
|
||||||
|
const [hasAutoPlayed, setHasAutoPlayed] = useState(false); // 자동 재생 완료 여부
|
||||||
|
|
||||||
|
const topPanel = panels[panels.length - 1];
|
||||||
|
|
||||||
|
// MediaPanel 상태 체크 로직 + 모달 상태 복원
|
||||||
|
useEffect(() => {
|
||||||
|
if (
|
||||||
|
topPanel &&
|
||||||
|
topPanel.name === panel_names.MEDIA_PANEL &&
|
||||||
|
topPanel.panelInfo.modal === false
|
||||||
|
) {
|
||||||
|
return; // MediaPanel이 전체화면 모드일 때는 처리하지 않음
|
||||||
|
}
|
||||||
|
|
||||||
|
// MediaPanel이 닫혔을 때 modalState를 true로 복원
|
||||||
|
if (!topPanel || topPanel.name !== panel_names.MEDIA_PANEL) {
|
||||||
|
setModalState(true);
|
||||||
|
}
|
||||||
|
}, [topPanel]);
|
||||||
|
|
||||||
|
// autoPlay 기능: 컴포넌트 마운트 시 자동으로 비디오 재생
|
||||||
|
useEffect(() => {
|
||||||
|
if (autoPlay && canPlayVideo && !hasAutoPlayed && productInfo) {
|
||||||
|
console.log('[ProductVideo] Auto-playing video');
|
||||||
|
setHasAutoPlayed(true);
|
||||||
|
|
||||||
|
// 짧은 딜레이 후 재생 시작 (컴포넌트 마운트 완료 후)
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(
|
||||||
|
startMediaPlayer({
|
||||||
|
qrCurrentItem: productInfo,
|
||||||
|
showUrl: productInfo?.prdtMediaUrl,
|
||||||
|
showNm: productInfo?.prdtNm,
|
||||||
|
patnrNm: productInfo?.patncNm,
|
||||||
|
patncLogoPath: productInfo?.patncLogoPath,
|
||||||
|
orderPhnNo: productInfo?.orderPhnNo,
|
||||||
|
disclaimer: productInfo?.disclaimer,
|
||||||
|
subtitle: productInfo?.prdtMediaSubtitlUrl,
|
||||||
|
lgCatCd: productInfo?.catCd,
|
||||||
|
patnrId: productInfo?.patnrId,
|
||||||
|
lgCatNm: productInfo?.catNm,
|
||||||
|
prdtId: productInfo?.prdtId,
|
||||||
|
patncNm: productInfo?.patncNm,
|
||||||
|
prdtNm: productInfo?.prdtNm,
|
||||||
|
thumbnailUrl: productInfo?.thumbnailUrl960,
|
||||||
|
shptmBanrTpNm: 'MEDIA',
|
||||||
|
modal: true,
|
||||||
|
modalContainerId: 'product-video-player',
|
||||||
|
modalClassName: modalClassNameChange(),
|
||||||
|
spotlightDisable: true,
|
||||||
|
continuousPlay, // 반복 재생 옵션 전달
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}, 100);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
autoPlay,
|
||||||
|
canPlayVideo,
|
||||||
|
hasAutoPlayed,
|
||||||
|
productInfo,
|
||||||
|
dispatch,
|
||||||
|
modalClassNameChange,
|
||||||
|
continuousPlay,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// 비디오 재생 가능 여부 체크
|
||||||
|
const canPlayVideo = useMemo(() => {
|
||||||
|
return Boolean(productInfo?.prdtMediaUrl);
|
||||||
|
}, [productInfo]);
|
||||||
|
|
||||||
|
// 모달 CSS 클래스 변경 로직
|
||||||
|
const modalClassNameChange = useCallback(() => {
|
||||||
|
if (focused) {
|
||||||
|
return css.videoModal;
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}, [focused]);
|
||||||
|
|
||||||
|
// 포커스 이벤트 핸들러
|
||||||
|
const videoContainerOnFocus = useCallback(() => {
|
||||||
|
if (canPlayVideo) {
|
||||||
|
setFocused(true);
|
||||||
|
console.log('[ProductVideo] Calling restoreModalMedia');
|
||||||
|
// ProductVideo에 포커스가 돌아오면 비디오 복원
|
||||||
|
// dispatch(restoreModalMedia());
|
||||||
|
|
||||||
|
// 외부에서 전달된 onFocus 핸들러도 호출
|
||||||
|
if (onFocus) {
|
||||||
|
onFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [canPlayVideo, dispatch, onFocus]);
|
||||||
|
|
||||||
|
const videoContainerOnBlur = useCallback(() => {
|
||||||
|
console.log('[ProductVideo] onBlur called - canPlayVideo:', canPlayVideo);
|
||||||
|
// if (canPlayVideo) {
|
||||||
|
// setFocused(false);
|
||||||
|
// // 포커스를 잃으면 모달 MediaPanel을 최소화하여 1px 상태로 유지
|
||||||
|
// dispatch(minimizeModalMedia());
|
||||||
|
// }
|
||||||
|
}, [canPlayVideo, dispatch]);
|
||||||
|
|
||||||
|
// Spotlight Down 키 핸들러 - 비디오 다음 이미지로 스크롤
|
||||||
|
const handleSpotlightDown = useCallback(
|
||||||
|
(e) => {
|
||||||
|
if (canPlayVideo && onScrollToImages) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
dispatch(minimizeModalMedia());
|
||||||
|
onScrollToImages();
|
||||||
|
return true; // 이벤트 처리 완료
|
||||||
|
}
|
||||||
|
return false; // Spotlight가 기본 동작 수행
|
||||||
|
},
|
||||||
|
[canPlayVideo, onScrollToImages, dispatch]
|
||||||
|
);
|
||||||
|
|
||||||
|
// MediaPanel 비디오 클릭 핸들러 + 모달 토글 기능
|
||||||
|
const handleVideoClick = useCallback(() => {
|
||||||
|
console.log('[ProductVideo] ========== handleVideoClick 호출 ==========');
|
||||||
|
console.log('[ProductVideo] canPlayVideo:', canPlayVideo);
|
||||||
|
console.log('[ProductVideo] panels.length:', panels.length);
|
||||||
|
console.log('[ProductVideo] All panels:', JSON.stringify(panels, null, 2));
|
||||||
|
|
||||||
|
if (canPlayVideo) {
|
||||||
|
const currentTopPanel = panels[panels.length - 1];
|
||||||
|
|
||||||
|
// 현재 MediaPanel이 modal=true로 재생 중인지 확인
|
||||||
|
const isCurrentlyPlayingModal =
|
||||||
|
currentTopPanel &&
|
||||||
|
currentTopPanel.name === panel_names.MEDIA_PANEL &&
|
||||||
|
currentTopPanel.panelInfo.modal === true;
|
||||||
|
|
||||||
|
console.log('[ProductVideo] currentTopPanel:', JSON.stringify(currentTopPanel, null, 2));
|
||||||
|
console.log('[ProductVideo] isCurrentlyPlayingModal:', isCurrentlyPlayingModal);
|
||||||
|
|
||||||
|
// modal로 재생 중이면 전체화면으로 전환
|
||||||
|
if (isCurrentlyPlayingModal) {
|
||||||
|
console.log(
|
||||||
|
'[ProductVideo] *** Switching to fullscreen mode via switchMediaToFullscreen ***'
|
||||||
|
);
|
||||||
|
dispatch(switchMediaToFullscreen());
|
||||||
|
setModalState(false);
|
||||||
|
} else {
|
||||||
|
console.log('[ProductVideo] *** Starting modal MediaPanel ***');
|
||||||
|
console.log('[ProductVideo] productInfo:', JSON.stringify(productInfo, null, 2));
|
||||||
|
// 처음 재생 시작 - modal=true로 시작
|
||||||
|
dispatch(
|
||||||
|
startMediaPlayer({
|
||||||
|
qrCurrentItem: productInfo,
|
||||||
|
showUrl: productInfo?.prdtMediaUrl,
|
||||||
|
showNm: productInfo?.prdtNm,
|
||||||
|
patnrNm: productInfo?.patncNm,
|
||||||
|
patncLogoPath: productInfo?.patncLogoPath,
|
||||||
|
orderPhnNo: productInfo?.orderPhnNo,
|
||||||
|
disclaimer: productInfo?.disclaimer,
|
||||||
|
subtitle: productInfo?.prdtMediaSubtitlUrl,
|
||||||
|
lgCatCd: productInfo?.catCd,
|
||||||
|
patnrId: productInfo?.patnrId,
|
||||||
|
lgCatNm: productInfo?.catNm,
|
||||||
|
prdtId: productInfo?.prdtId,
|
||||||
|
patncNm: productInfo?.patncNm,
|
||||||
|
prdtNm: productInfo?.prdtNm,
|
||||||
|
thumbnailUrl: productInfo?.thumbnailUrl960,
|
||||||
|
shptmBanrTpNm: 'MEDIA',
|
||||||
|
modal: true,
|
||||||
|
modalContainerId: 'product-video-player',
|
||||||
|
modalClassName: modalClassNameChange(),
|
||||||
|
spotlightDisable: true,
|
||||||
|
continuousPlay, // 반복 재생 옵션 전달
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLaunchedFromPlayer) {
|
||||||
|
setIsLaunchedFromPlayer(false);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
dispatch,
|
||||||
|
productInfo,
|
||||||
|
canPlayVideo,
|
||||||
|
isLaunchedFromPlayer,
|
||||||
|
modalClassNameChange,
|
||||||
|
panels,
|
||||||
|
modalState,
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!canPlayVideo) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SpottableComponent
|
||||||
|
className={css.videoContainer}
|
||||||
|
onClick={handleVideoClick}
|
||||||
|
onFocus={videoContainerOnFocus}
|
||||||
|
onBlur={videoContainerOnBlur}
|
||||||
|
onSpotlightDown={handleSpotlightDown}
|
||||||
|
spotlightId="product-video-player"
|
||||||
|
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>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ import IntroPanel from '../IntroPanel/IntroPanel.new';
|
|||||||
import JustForYouPanel from '../JustForYouPanel/JustForYouPanel';
|
import JustForYouPanel from '../JustForYouPanel/JustForYouPanel';
|
||||||
import JustForYouTestPanel from '../JustForYouTestPanel/JustForYouTestPanel';
|
import JustForYouTestPanel from '../JustForYouTestPanel/JustForYouTestPanel';
|
||||||
import LoadingPanel from '../LoadingPanel/LoadingPanel';
|
import LoadingPanel from '../LoadingPanel/LoadingPanel';
|
||||||
import MediaPanel from '../MediaPanel/MediaPanel';
|
import MediaPanel from '../MediaPanel/MediaPanel.v3';
|
||||||
import MyPagePanel from '../MyPagePanel/MyPagePanel';
|
import MyPagePanel from '../MyPagePanel/MyPagePanel';
|
||||||
import OnSalePanel from '../OnSalePanel/OnSalePanel';
|
import OnSalePanel from '../OnSalePanel/OnSalePanel';
|
||||||
import PlayerPanel from '../PlayerPanel/PlayerPanel';
|
import PlayerPanel from '../PlayerPanel/PlayerPanel';
|
||||||
@@ -163,7 +163,7 @@ export default function MainView({ className, initService }) {
|
|||||||
const [imagePreloaded, setImagePreloaded] = useState(false);
|
const [imagePreloaded, setImagePreloaded] = useState(false);
|
||||||
const [ariaHidden, setAriaHidden] = useState(false);
|
const [ariaHidden, setAriaHidden] = useState(false);
|
||||||
const [showEndOfServicePopup, setShowEndOfServicePopup] = useState(false);
|
const [showEndOfServicePopup, setShowEndOfServicePopup] = useState(false);
|
||||||
|
|
||||||
const topPanel = panels[panels.length - 1];
|
const topPanel = panels[panels.length - 1];
|
||||||
|
|
||||||
// BUYNOW_CONFIG 초기화 (마운트 시 한 번만 실행)
|
// BUYNOW_CONFIG 초기화 (마운트 시 한 번만 실행)
|
||||||
@@ -208,14 +208,19 @@ export default function MainView({ className, initService }) {
|
|||||||
console.log(`[MainView] 🔍 Top panel name: ${topPanel?.name}`);
|
console.log(`[MainView] 🔍 Top panel name: ${topPanel?.name}`);
|
||||||
console.log(`[MainView] 🔍 isStandalonePanel check:`, isStandalonePanel(topPanel?.name));
|
console.log(`[MainView] 🔍 isStandalonePanel check:`, isStandalonePanel(topPanel?.name));
|
||||||
console.log(`[MainView] 🔍 STANDALONE_PANELS:`, STANDALONE_PANELS);
|
console.log(`[MainView] 🔍 STANDALONE_PANELS:`, STANDALONE_PANELS);
|
||||||
console.log(`[MainView] 🔍 All panels:`, panels.map(p => ({ name: p.name, hasModal: !!p.panelInfo?.modal })));
|
console.log(
|
||||||
|
`[MainView] 🔍 All panels:`,
|
||||||
|
panels.map((p) => ({ name: p.name, hasModal: !!p.panelInfo?.modal }))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isStandalonePanel(topPanel?.name)) {
|
if (isStandalonePanel(topPanel?.name)) {
|
||||||
if (DEBUG_MODE) {
|
if (DEBUG_MODE) {
|
||||||
console.log(`[MainView] ✅ Standalone panel detected: ${topPanel?.name} - rendering independently`);
|
console.log(
|
||||||
|
`[MainView] ✅ Standalone panel detected: ${topPanel?.name} - rendering independently`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
renderingPanels = [topPanel]; // 단독 패널만 단독으로 렌더링
|
renderingPanels = [topPanel]; // 단독 패널만 단독으로 렌더링
|
||||||
}
|
}
|
||||||
// 기존 3-layer 구조 체크: PlayerPanel + DetailPanel + MediaPanel(modal)
|
// 기존 3-layer 구조 체크: PlayerPanel + DetailPanel + MediaPanel(modal)
|
||||||
else {
|
else {
|
||||||
@@ -716,7 +721,12 @@ export default function MainView({ className, initService }) {
|
|||||||
}, [webOSVersion]);
|
}, [webOSVersion]);
|
||||||
const handleErrorPopupClose = useCallback(() => {
|
const handleErrorPopupClose = useCallback(() => {
|
||||||
if (DEBUG_MODE) {
|
if (DEBUG_MODE) {
|
||||||
console.log('handleErrorPopupClose 호출됨! activePopup:', activePopup, 'popupData:', popupData);
|
console.log(
|
||||||
|
'handleErrorPopupClose 호출됨! activePopup:',
|
||||||
|
activePopup,
|
||||||
|
'popupData:',
|
||||||
|
popupData
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (popupData?.shouldPopPanel) {
|
if (popupData?.shouldPopPanel) {
|
||||||
dispatch(popPanel());
|
dispatch(popPanel());
|
||||||
|
|||||||
2629
com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx
Normal file
2629
com.twin.app.shoptime/src/views/MediaPanel/MediaPanel.v3.jsx
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,142 @@
|
|||||||
|
@import "../../style/CommonStyle.module.less";
|
||||||
|
@import "../../style/utils.module.less";
|
||||||
|
|
||||||
|
@videoBackgroundColor: black;
|
||||||
|
.videoContainer {
|
||||||
|
position: absolute;
|
||||||
|
background-color: @videoBackgroundColor;
|
||||||
|
z-index: 21;
|
||||||
|
outline: none;
|
||||||
|
|
||||||
|
&:focus-visible,
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoFrame {
|
||||||
|
padding: 2px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoFrame:focus-within {
|
||||||
|
outline: 2px solid #c70850;
|
||||||
|
border-radius: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoFrame video,
|
||||||
|
.videoFrame iframe {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.playButton {
|
||||||
|
.size(@w: 60px, @h: 60px);
|
||||||
|
background-image: url("../../../assets/images/btn/btn-video-play-nor@3x.png");
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
.size(@w: 60px, @h: 60px);
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #c70850;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pauseButton {
|
||||||
|
.size(@w: 60px, @h: 60px);
|
||||||
|
background-image: url("../../../assets/images/btn/btn-voc-pause-nor@3x.png");
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
.size(@w: 60px, @h: 60px);
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: #c70850;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.toOpenBtn {
|
||||||
|
.size(@w: 147px, @h: 243px);
|
||||||
|
min-width: 60px !important;
|
||||||
|
margin: 192px 0 136px 512px;
|
||||||
|
text-align: center;
|
||||||
|
background-image: url(../../../assets/images/btn/btn-toopen-foc.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.videoReduce {
|
||||||
|
.size(@w:78px, @h:78px);
|
||||||
|
background: url("../../../assets/images/btn/btn-video-min-nor@3x.png")
|
||||||
|
no-repeat center center/60px 60px;
|
||||||
|
position: absolute;
|
||||||
|
right: 60px;
|
||||||
|
bottom: 150px;
|
||||||
|
z-index: 3;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
.size(@w:78px, @h:78px);
|
||||||
|
background-color: rgba(199, 8, 80, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.shrinkTo1px {
|
||||||
|
/* 모달 비디오를 1px로 축소 */
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
left: -1px;
|
||||||
|
top: -1px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: @videoBackgroundColor;
|
||||||
|
overflow: visible;
|
||||||
|
.tabContainer,
|
||||||
|
.arrow,
|
||||||
|
.toOpenBtn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.modal,
|
||||||
|
&.modal-minimized,
|
||||||
|
&.background {
|
||||||
|
/* 실제 css */
|
||||||
|
width: 1px;
|
||||||
|
height: 1px;
|
||||||
|
left: -1px;
|
||||||
|
top: -1px;
|
||||||
|
/* //실제 css */
|
||||||
|
/* 테스트 용도 */
|
||||||
|
// width: 1920px;
|
||||||
|
// height: 1080px;
|
||||||
|
// left: 0;
|
||||||
|
// top: 0;
|
||||||
|
/* //테스트 용도 */
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: @videoBackgroundColor;
|
||||||
|
overflow: visible;
|
||||||
|
.tabContainer,
|
||||||
|
.arrow,
|
||||||
|
.toOpenBtn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.background-visible {
|
||||||
|
width: 1920px;
|
||||||
|
height: 1080px;
|
||||||
|
left: -1px;
|
||||||
|
top: -1px;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 1;
|
||||||
|
background-color: @videoBackgroundColor;
|
||||||
|
overflow: visible;
|
||||||
|
.tabContainer,
|
||||||
|
.arrow,
|
||||||
|
.toOpenBtn {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.hideSubtitle {
|
||||||
|
video::cue {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user