diff --git a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js index 40522613..b2a7ec56 100644 --- a/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js +++ b/com.twin.app.shoptime/src/components/VideoPlayer/VideoPlayer.js @@ -859,28 +859,6 @@ const VideoPlayerBase = class extends React.Component { } } - // TabContainerV2와 mediaControls 동기화 - if ( - this.props.tabContainerVersion === 2 && - this.props.belowContentsVisible !== undefined && - prevProps.belowContentsVisible !== this.props.belowContentsVisible - ) { - console.log('[VideoPlayer] belowContentsVisible 변경 감지:', { - prev: prevProps.belowContentsVisible, - current: this.props.belowContentsVisible, - mediaControlsVisible: this.state.mediaControlsVisible, - }); - - if (this.props.belowContentsVisible && !this.state.mediaControlsVisible) { - // TabContainerV2가 표시될 때 controls도 표시 - console.log('[VideoPlayer] TabContainerV2 표시 - controls 강제 표시'); - this.showControls(); - } else if (!this.props.belowContentsVisible && this.state.mediaControlsVisible) { - // TabContainerV2가 숨겨질 때 controls도 숨김 - console.log('[VideoPlayer] TabContainerV2 숨김 - controls 숨김'); - this.hideControls(); - } - } if ( (!this.state.mediaControlsVisible && prevState.mediaControlsVisible !== this.state.mediaControlsVisible) || @@ -1044,12 +1022,6 @@ const VideoPlayerBase = class extends React.Component { // detection of when "more" is pressed vs when the state is updated is mismatched. Using an // instance variable that's only set and used for this express purpose seems cleanest. - // TabContainerV2가 표시 중이면 자동으로 닫지 않음 - if (this.props.tabContainerVersion === 2 && this.props.belowContentsVisible) { - console.log('[VideoPlayer] TabContainerV2 표시 중 - autoClose 비활성화'); - return; - } - if (this.props.autoCloseTimeout && !this.props.sideContentsVisible) { this.autoCloseJob.startAfter(this.props.autoCloseTimeout); } @@ -1981,15 +1953,6 @@ const VideoPlayerBase = class extends React.Component { return; } - // tabContainerVersion === 2일 때 belowContentsVisible도 함께 토글 - if (this.props.tabContainerVersion === 2 && this.props.setBelowContentsVisible) { - const willShowControls = !this.state.mediaControlsVisible; - console.log('[VideoPlayer] 클릭 - 상태 동기화 토글:', willShowControls); - - // belowContentsVisible을 먼저 변경 (componentDidUpdate에서 mediaControls 동기화됨) - this.props.setBelowContentsVisible(willShowControls); - } - this.toggleControls(); }; diff --git a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.module.less b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.module.less index 445dc46a..eaa29b05 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/DetailPanelSkeleton/DetailPanelSkeleton.module.less @@ -157,7 +157,13 @@ width: 100%; display: flex; flex-direction: column; - gap: 10px; + + > * { + margin-bottom: 10px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonTitle { @@ -190,8 +196,14 @@ .skeletonButtons { width: 100%; display: flex; - gap: 10px; align-items: center; + + > * { + margin-right: 10px; + &:last-child { + margin-right: 0; + } + } } .skeletonShopButton { @@ -218,7 +230,13 @@ width: 100%; display: flex; flex-direction: column; - gap: 5px; + + > * { + margin-bottom: 5px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonActionButton { @@ -248,7 +266,13 @@ width: 100%; display: flex; flex-direction: column; - gap: 15px; + + > * { + margin-bottom: 15px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonDescTitle { @@ -274,7 +298,13 @@ width: 100%; display: flex; flex-direction: column; - gap: 20px; + + > * { + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonReviewTitle { @@ -286,8 +316,14 @@ .skeletonReviewItem { width: 100%; display: flex; - gap: 15px; align-items: flex-start; + + > * { + margin-right: 15px; + &:last-child { + margin-right: 0; + } + } } .skeletonReviewAvatar { @@ -302,7 +338,13 @@ flex: 1; display: flex; flex-direction: column; - gap: 10px; + + > * { + margin-bottom: 10px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonReviewHeader { @@ -328,7 +370,13 @@ width: 100%; display: flex; flex-direction: column; - gap: 25px; + + > * { + margin-bottom: 25px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonYouMayLikeTitle { @@ -340,16 +388,28 @@ .skeletonProductGrid { width: 100%; display: flex; - gap: 20px; justify-content: flex-start; + + > * { + margin-right: 20px; + &:last-child { + margin-right: 0; + } + } } .skeletonProductCard { width: 300px; display: flex; flex-direction: column; - gap: 10px; flex-shrink: 0; + + > * { + margin-bottom: 10px; + &:last-child { + margin-bottom: 0; + } + } } .skeletonProductImage { diff --git a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less index 84f9e601..138fd1ff 100644 --- a/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less +++ b/com.twin.app.shoptime/src/views/DetailPanel/ProductAllSection/ProductAllSection.module.less @@ -140,7 +140,7 @@ // 스크롤바 thumb에 hover 효과 적용 &:hover::-webkit-scrollbar-thumb { - background: #c72054; + background: @PRIMARY_COLOR_RED; } } @@ -280,15 +280,24 @@ } // 포커스 상태 추가 - &:focus, - &.active { + &:focus { background: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경 outline: 2px solid @PRIMARY_COLOR_RED !important; + animation: focusShadowPulse 0.4s ease-out !important; .shopByMobileText { color: white !important; // 포커스시에도 텍스트는 흰색 유지 } } + + &.active { + background: @PRIMARY_COLOR_RED !important; + outline: 2px solid @PRIMARY_COLOR_RED !important; + + .shopByMobileText { + color: white !important; + } + } } .favoriteBtnWrapper { @@ -398,9 +407,13 @@ font-weight: 400; // Bold에서 Regular로 변경 line-height: 35px; - &:focus, + &:focus { + background: @PRIMARY_COLOR_RED; // 포커스시만 빨간색 + animation: focusShadowPulse 0.4s ease-out; + } + &.active { - background: #c72054; // 포커스시만 빨간색 + background: @PRIMARY_COLOR_RED; } } @@ -412,7 +425,8 @@ margin-top: 10px; &:focus { - background: #c72054; + background: @PRIMARY_COLOR_RED; + animation: focusShadowPulse 0.4s ease-out; } } @@ -611,7 +625,7 @@ // 스크롤바 thumb에 hover 효과 적용 &:hover::-webkit-scrollbar-thumb { - background: #c72054; + background: @PRIMARY_COLOR_RED; } } @@ -750,6 +764,7 @@ &:focus { background: @PRIMARY_COLOR_RED !important; // 포커스시 빨간색 배경 outline: 2px solid @PRIMARY_COLOR_RED !important; + animation: focusShadowPulse 0.4s ease-out !important; .shopByMobileText { color: white !important; // 포커스시에도 텍스트는 흰색 유지 @@ -864,7 +879,8 @@ line-height: 35px; &:focus { - background: #c72054; // 포커스시만 빨간색 + background: @PRIMARY_COLOR_RED; // 포커스시만 빨간색 + animation: focusShadowPulse 0.4s ease-out; } } @@ -876,7 +892,8 @@ margin-top: 10px; &:focus { - background: #c72054; + background: @PRIMARY_COLOR_RED; + animation: focusShadowPulse 0.4s ease-out; } } @@ -999,7 +1016,13 @@ display: flex; justify-content: flex-start; align-items: center; - gap: 10px; + + > * { + margin-right: 10px; + &:last-child { + margin-right: 0; + } + } } .buyNowButton { @@ -1026,6 +1049,7 @@ &:focus { background: @PRIMARY_COLOR_RED !important; outline: 2px solid @PRIMARY_COLOR_RED !important; + animation: focusShadowPulse 0.4s ease-out !important; .buyNowText { color: white !important; @@ -1057,6 +1081,7 @@ &:focus { background: @PRIMARY_COLOR_RED !important; outline: 2px solid @PRIMARY_COLOR_RED !important; + animation: focusShadowPulse 0.4s ease-out !important; .addToCartText { color: white !important; @@ -1072,3 +1097,16 @@ // PlayerPanel 모달이 이 영역에서만 재생되도록 설정 z-index: 1; } + +// 포커스 Pulse 애니메이션 - Box Shadow 방식 +@keyframes focusShadowPulse { + 0% { + box-shadow: 0 0 0 0 @PRIMARY_COLOR_RED; + } + 50% { + box-shadow: 0 0 0 6px fade(@PRIMARY_COLOR_RED, 50%); + } + 100% { + box-shadow: 0 0 0 0 @PRIMARY_COLOR_RED; + } +} diff --git a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less index 9c916376..6c55a0e5 100644 --- a/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less +++ b/com.twin.app.shoptime/src/views/IntroPanel/IntroPanel.new.module.less @@ -26,26 +26,44 @@ flex-direction: column; justify-content: space-between; align-items: center; - gap: 40px; display: inline-flex; background-color: @BG_COLOR_03; + > * { + margin-bottom: 40px; + &:last-child { + margin-bottom: 0; + } + } + // 첫 번째 영역: 헤더 섹션 (타이틀 + 설명) .headerSection { width: 1834px; flex-direction: column; justify-content: flex-start; align-items: center; - gap: 40px; display: flex; + > * { + margin-bottom: 40px; + &:last-child { + margin-bottom: 0; + } + } + .titleContainer { align-self: stretch; justify-content: center; align-items: center; - gap: 14px; display: inline-flex; + > * { + margin-right: 14px; + &:last-child { + margin-right: 0; + } + } + .welcomeText { color: #807f81; font-size: 62px; @@ -89,9 +107,15 @@ align-self: stretch; justify-content: center; align-items: center; - gap: 10px; display: inline-flex; + > * { + margin-right: 10px; + &:last-child { + margin-right: 0; + } + } + .descriptionText { width: 1012.49px; text-align: center; @@ -225,9 +249,15 @@ height: 100px; position: relative; display: flex; - gap: 40px; justify-content: center; + > * { + margin-right: 40px; + &:last-child { + margin-right: 0; + } + } + .agreeButton, .disagreeButton { width: 450px; diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.module.less b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.module.less index b7f984af..30e6e67e 100644 --- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.module.less +++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/OptionalTermsInfo.module.less @@ -67,8 +67,15 @@ display: flex; align-items: center; justify-content: center; - gap: 20px; flex-wrap: wrap; + + > * { + margin-right: 20px; + margin-bottom: 20px; + &:last-child { + margin-right: 0; + } + } } .benefitImage { diff --git a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfService.module.less b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfService.module.less index 080914f4..4ebb1cd1 100644 --- a/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfService.module.less +++ b/com.twin.app.shoptime/src/views/MyPagePanel/MyPageSub/TermsOfService/TermsOfService.module.less @@ -159,14 +159,26 @@ .popup_container { display: flex !important; flex-direction: column !important; - gap: 30px !important; + + > * { + margin-bottom: 30px !important; + &:last-child { + margin-bottom: 0 !important; + } + } } .button_container { display: flex !important; flex-direction: row !important; justify-content: center !important; - gap: 12px !important; + + > * { + margin-right: 12px !important; + &:last-child { + margin-right: 0 !important; + } + } .button { width: 380px !important; @@ -187,8 +199,14 @@ flex-direction: column; justify-content: center; align-items: center; - gap: 30px; box-sizing: border-box; + + > * { + margin-bottom: 30px; + &:last-child { + margin-bottom: 0; + } + } } .disagreePopupText { @@ -202,7 +220,13 @@ display: flex; flex-direction: row; justify-content: center; - gap: 12px; + + > * { + margin-right: 12px; + &:last-child { + margin-right: 0; + } + } } .disagreePopupButton { diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx index 8dc7c684..670eb27f 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerOverlay/PlayerOverlayContents.jsx @@ -42,6 +42,12 @@ export default function PlayerOverlayContents({ const cntry_cd = useSelector((state) => state.common.httpHeader?.cntry_cd); const dispatch = useDispatch(); const onClickBack = (ev) => { + // TabContainerV2가 표시된 상태에서 백버튼 클릭 시 이벤트 버블링 방지 + // (Overlay의 onClick으로 전파되어 toggleControls()가 호출되는 것을 막음) + if (tabContainerVersion === 2 && belowContentsVisible) { + ev.stopPropagation(); + } + if (onClick) { onClick(ev); } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index ff41e045..5b63a5cf 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -835,9 +835,14 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props (ev, isEnd) => { //modal로부터 Full 전환된 경우 다시 preview 모드로 돌아감. - if (sideContentsVisible && !videoVerticalVisible && panelInfo.shptmBanrTpNm !== 'MEDIA') { + // TabContainer(v1)만: Side Contents가 보이는 경우 먼저 숨기고 return + if ( + tabContainerVersion === 1 && + sideContentsVisible && + !videoVerticalVisible && + panelInfo.shptmBanrTpNm !== 'MEDIA' + ) { setSideContentsVisible(false); - setBelowContentsVisible(false); ev?.stopPropagation(); // ev?.preventDefault(); return; @@ -888,9 +893,10 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props nowMenu, videoPlayer, sideContentsVisible, - setBelowContentsVisible, videoVerticalVisible, backupInitialIndex, + panels, + tabContainerVersion, ] ); diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less index 788c76a7..7aa6379b 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less @@ -21,18 +21,29 @@ display: inline-flex; justify-content: center; align-items: center; - gap: 10px; cursor: pointer; transition: all 0.3s ease; + + > * { + margin-right: 10px; + &:last-child { + margin-right: 0; + } + } + &:hover { background: rgba(0, 0, 0, 0.5); border-color: rgba(234, 234, 234, 0.7); } &:focus { - background: rgba(199, 8, 80, 0.2); + background: @PRIMARY_COLOR_RED; border-color: @PRIMARY_COLOR_RED; + .buttonText { + color: white; + } + &::after { .focused(@boxShadow: 22px, @borderRadius: 12px); } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx index 1930eb3a..e2592682 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx @@ -102,9 +102,14 @@ export default function TabContainerV2({ Spotlight.focus(SpotlightIds.PLAYER_BACK_BUTTON); }, []); - // useEffect(()=>{ - // console.log('[tabIndex]',tabIndex) - // },[tabIndex]) + // tabIndex가 2(ShopNowButton)로 변경되면 자동으로 포커스 이동 + useEffect(() => { + if (tabIndex === 2) { + setTimeout(() => { + Spotlight.focus('below-tab-shop-now-button'); + }, 100); + } + }, [tabIndex]); return ( * { + margin-bottom: 10px; + &:last-child { + margin-bottom: 0; + } + } } .noReviews {