From 3916b07b2fdbc8324bfd96764913386d7972f7ee Mon Sep 17 00:00:00 2001 From: optrader Date: Thu, 9 Oct 2025 00:15:24 +0900 Subject: [PATCH] =?UTF-8?q?[251009]=20refactor=20CSS=20gap=20=EB=8C=80?= =?UTF-8?q?=EC=8B=A0=20margin=20=EC=82=AC=EC=9A=A9=20=EB=B0=8F=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=ACmes?= =?UTF-8?q?sag...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 변경사항을 반영했습니다 🕐 커밋 시간: 2025. 10. 09. 24:15:20 📊 변경 통계: • 총 파일: 8개 • 추가: +174줄 • 삭제: -69줄 📝 수정된 파일: ~ com.twin.app.shoptime/src/components/TItemCard/TItemCard.v2.module.less ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.v2.module.less ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.v2.module.less ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.jsx ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.module.less 🔧 주요 변경 내용: • UI 컴포넌트 아키텍처 개선 • 중간 규모 기능 개선 • 모듈 구조 개선 --- .../TItemCard/TItemCard.v2.module.less | 37 ++++++++--- .../src/views/PlayerPanel/PlayerPanel.jsx | 44 ++++++------- .../TabContents/ShopNowContents.jsx | 2 +- .../ShopNowContents.v2.module.less | 3 +- .../TabContents/YouMayLikeContents.jsx | 24 +++---- .../YouMayLikeContents.v2.module.less | 11 ++++ .../PlayerTabContents/v2/TabContainer.v2.jsx | 59 +++++++++++++---- .../v2/TabContainer.v2.module.less | 63 ++++++++++++++++--- 8 files changed, 174 insertions(+), 69 deletions(-) diff --git a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.v2.module.less b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.v2.module.less index 9d88e9bc..ca93c0fd 100644 --- a/com.twin.app.shoptime/src/components/TItemCard/TItemCard.v2.module.less +++ b/com.twin.app.shoptime/src/components/TItemCard/TItemCard.v2.module.less @@ -9,8 +9,15 @@ border-radius: 12px; border: 1px solid transparent; .flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start, @direction: column); - gap: 15px; flex-shrink: 0; + + > * { + margin-bottom: 15px; + + &:last-child { + margin-bottom: 0; + } + } transition: all 0.3s ease; .imageWrap { @@ -53,7 +60,14 @@ .descWrap { align-self: stretch; .flex(@display: flex, @justifyCenter: center, @alignCenter: flex-start, @direction: column); - gap: 15px; + + > * { + margin-bottom: 15px; + + &:last-child { + margin-bottom: 0; + } + } .logo { width: 60px; @@ -82,8 +96,15 @@ .priceInfo { align-self: stretch; .flex(@display: flex, @justifyCenter: flex-start, @alignCenter: center); - gap: 11px; font-weight: 700; + + > * { + margin-right: 11px; + + &:last-child { + margin-right: 0; + } + } font-size: 30px; color: @PRIMARY_COLOR_RED; font-family: @baseFont; @@ -122,8 +143,6 @@ &:focus { border-color: @PRIMARY_COLOR_RED; - outline: 4px @PRIMARY_COLOR_RED solid; - outline-offset: -4px; &::after { .focused(@boxShadow: 22px, @borderRadius: 12px); @@ -132,9 +151,9 @@ } // vertical type (v2에서는 사용하지 않음) -.vertical { -} +// .vertical { +// } // videoShow type (v2에서는 사용하지 않음) -.videoShow { -} +// .videoShow { +// } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx index 276f8927..a5c076c8 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx @@ -180,6 +180,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props ); const [prevChannelIndex, setPrevChannelIndex] = USE_STATE('prevChannelIndex', 0); const [sideContentsVisible, setSideContentsVisible] = USE_STATE('sideContentsVisible', true); + const [belowContentsVisible, setBelowContentsVisible] = USE_STATE('belowContentsVisible', true); const [currentTime, setCurrentTime] = USE_STATE('currentTime', 0); const [isInitialFocusOccurred, setIsInitialFocusOccurred] = USE_STATE( 'isInitialFocusOccurred', @@ -202,8 +203,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props isFullMediaLogReady: false, isDetailMediaReady: false, }); - const [isVODPaused, setIsVODPaused] = USE_STATE('isVODPaused', false); - const [belowTabMode, setBelowTabMode] = USE_STATE('belowTabMode', 'liveShow'); + const [isVODPaused, setIsVODPaused] = USE_STATE('isVODPaused', false); const [tabIndexV2, setTabIndexV2] = USE_STATE('tabIndexV2', 1); // 0: ShopNow, 1: LiveChannel, 2: ShopNowButton const panels = USE_SELECTOR('panels', (state) => state.panels.panels); @@ -1744,27 +1744,18 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props !panelInfo?.modal && isOnTop ); - }, [sideContentsVisible, playListInfo, panelInfo, isOnTop]); - - const [belowContentsVisible, setBelowContentsVisible] = USE_STATE('belowContentsVisible', true); - + }, [sideContentsVisible, playListInfo, panelInfo, isOnTop]); + const showBelowContents = useMemo(() => { return ( - belowContentsVisible && + sideContentsVisible && playListInfo && panelInfo?.shptmBanrTpNm !== 'MEDIA' && !panelInfo?.modal && isOnTop ); - }, [belowContentsVisible, playListInfo, panelInfo, isOnTop]); - - const shouldShowBelowTab = useMemo(() => { - // LiveShowContainer, ShopNowContainer, ShopNowButton 모두 표시 여부 - return ( - belowContentsVisible && !panelInfo?.modal && isOnTop && panelInfo?.shptmBanrTpNm !== 'MEDIA' - ); - }, [belowContentsVisible, panelInfo?.modal, isOnTop, panelInfo?.shptmBanrTpNm]); - + }, [belowContentsVisible, playListInfo, panelInfo, isOnTop]); + const qrCurrentItem = useMemo(() => { if (shopNowInfo?.length && panelInfo?.shptmBanrTpNm === 'LIVE') { return shopNowInfo[shopNowInfo.length - 1]; @@ -1812,14 +1803,14 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props timerId.current = setTimeout(() => { setSideContentsVisible(false); - setBelowContentsVisible(false); + // setBelowContentsVisible(false); }, timeout); }, []); useEffect(() => { if (isOnTop && !panelInfo.modal && !videoVerticalVisible) { setSideContentsVisible(true); - setBelowContentsVisible(true); + // setBelowContentsVisible(true); } }, [panelInfo.modal]); @@ -1974,11 +1965,11 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props spotlightRestrict="self-only" spotlightId="spotlightId-video-contaienr" onKeyDown={onKeyDown} - onClick={() => { - if (!panelInfo?.modal && isOnTop && panelInfo?.shptmBanrTpNm !== 'MEDIA') { - setBelowContentsVisible((prev) => !prev); - } - }} + // onClick={() => { + // if (!panelInfo?.modal && isOnTop && panelInfo?.shptmBanrTpNm !== 'MEDIA') { + // setBelowContentsVisible((prev) => !prev); + // } + // }} > {isReadyToPlay && ( )} */} - {shouldShowBelowTab && ( + {/* {showBelowContents && ( */} + { isOnTop && setTabIndexV2(0)} onLiveChannelButtonClick={() => setTabIndexV2(2)} + onTabClose={(newTabIndex) => setTabIndexV2(newTabIndex)} /> - )} + } + {/* )} */} {activePopup === ACTIVE_POPUP.alertPopup && ( diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx index a2de1f68..e8b0b6f0 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/ShopNowContents.jsx @@ -191,7 +191,7 @@ export default function ShopNowContents({ {shopNowInfo && shopNowInfo.length > 0 ? ( div:nth-child(1) { - .size(@w: 100%, @h: 100%); + width: 100%; + height: 420px; } } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx index dd3d5b6c..c9a98c11 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.jsx @@ -90,17 +90,19 @@ export default function YouMayLikeContents({
{$L("You may also like")}
- +
+ +
)} diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.v2.module.less b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.v2.module.less index ff5cc17b..406e495e 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.v2.module.less +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/TabContents/YouMayLikeContents.v2.module.less @@ -16,6 +16,17 @@ margin-bottom: 24px; } +.container { + width: 100%; + height: 420px; + overflow: hidden; + + > div:nth-child(1) { + width: 100%; + height: 420px; + } +} + .itemList { width: 100%; overflow: hidden; 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 c2889548..5875e495 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 @@ -7,6 +7,7 @@ import Spottable from "@enact/spotlight/Spottable"; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import { LOG_MENU } from "../../../../utils/Config"; +import { $L } from "../../../../utils/helperMethods"; import css from "./TabContainer.v2.module.less"; import LiveChannelContents from "../TabContents/LiveChannelContents"; import ShopNowContents from "../TabContents/ShopNowContents"; @@ -37,7 +38,15 @@ export default function TabContainerV2({ tabIndex = 1, // tabIndex prop으로 제어 (0: ShopNow, 1: LiveChannel, 2: ShopNowButton) onShopNowButtonClick, onLiveChannelButtonClick, + onTabClose, // 탭 닫기 콜백 함수 }) { + const tabList = [ + $L("SHOP NOW"), + panelInfo?.shptmBanrTpNm === "LIVE" + ? $L("LIVE CHANNEL") + : $L("FEATURED SHOWS"), + ]; + useEffect(() => { let nowMenu; @@ -77,6 +86,21 @@ export default function TabContainerV2({ [videoVerticalVisible] ); + const handleCloseButtonClick = useCallback( + (e) => { + e.stopPropagation(); + e.preventDefault(); + if (onTabClose) { + onTabClose(-1); // tabIndex를 -1로 설정 + } + }, + [onTabClose] + ); + + useEffect(()=>{ + console.log('[tabIndex]',tabIndex) + },[tabIndex]) + return (
-
- shop now icon +
+
+ shop now icon +
+
SHOP NOW
+
+
+ ×
-
SHOP NOW
+ {shopNowInfo && shopNowInfo.length < 3 && ( + + )} )} @@ -122,6 +164,7 @@ export default function TabContainerV2({ {panelInfo?.shptmBanrTpNm === "LIVE" && playListInfo && ( )} - - {shopNowInfo && shopNowInfo.length < 3 && tabIndex === 0 && ( - - )} ); } diff --git a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.module.less b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.module.less index 370f0430..10bd3858 100644 --- a/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.module.less +++ b/com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/TabContainer.v2.module.less @@ -9,20 +9,27 @@ // tabIndex = 0: ShopNow 스타일 (ShopNowContainer 참고) &.tabIndex0 { - .size(@w: 100%, @h: 675px); - padding: 60px; + .size(@w: 1920px, @h: 675px); + padding: 60px 120px; background: linear-gradient(270deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.62) 30%, rgba(0, 0, 0, 0) 65%), linear-gradient(0deg, rgba(0, 0, 0, 0.53) 0%, rgba(20.56, 4.68, 32.71, 0.53) 60%, rgba(199, 32, 84, 0) 98%), linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, black 45%, black 100%), rgba(0, 0, 0, 0.56); border-top: 1px solid rgba(234, 234, 234, 0.8); - gap: 40px; + + > * { + margin-bottom: 40px; + + &:last-child { + margin-bottom: 0; + } + } } // tabIndex = 1: LiveShow 스타일 (LiveShowContainer 참고) &.tabIndex1 { - .size(@w: 100%, @h: 365px); - padding: 60px; + .size(@w: 1920px, @h: 365px); + padding: 60px 120px; background: linear-gradient( to top, rgba(0, 0, 0, 0.95) 0%, @@ -31,7 +38,14 @@ rgba(0, 0, 0, 0) 100% ); border-top: 1px solid rgba(234, 234, 234, 0.3); - gap: 20px; + + > * { + margin-bottom: 20px; + + &:last-child { + margin-bottom: 0; + } + } &::before { content: ""; @@ -58,18 +72,18 @@ &.vertical { // vertical 모드일 때 추가 스타일 (필요시) + // 현재 추가 스타일 없음 } } // SHOP NOW 헤더 스타일 (ShopNowContainer 참고) .shopNowHeader { - width: 300px; + width: 100%; height: 70px; padding: 20px 0; overflow: hidden; border-radius: 100px; - .flex(@display: flex, @justifyCenter: flex-start, @alignCenter: center); - gap: 15px; + .flex(@display: flex, @justifyCenter: space-between, @alignCenter: center); } .shopNowIconWrapper { @@ -85,6 +99,18 @@ object-fit: contain; } +.shopNowHeaderLeft { + .flex(@display: flex, @justifyCenter: flex-start, @alignCenter: center); + + > * { + margin-right: 15px; + + &:last-child { + margin-right: 0; + } + } +} + .shopNowHeaderText { color: #EAEAEA; font-size: 24px; @@ -94,6 +120,25 @@ word-wrap: break-word; } +.closeButton { + .size(@w: 40px, @h: 40px); + .flex(@display: flex, @justifyCenter: center, @alignCenter: center); + background: rgba(0, 0, 0, 0.5); + border: 1px solid rgba(234, 234, 234, 0.3); + border-radius: 50%; + color: #EAEAEA; + font-size: 24px; + font-weight: 700; + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + background: rgba(0, 0, 0, 0.7); + border-color: rgba(234, 234, 234, 0.5); + color: white; + } +} + // LIVE CHANNEL 버튼 스타일 (LiveShowContainer 참고) .liveChannelButton { .size(@w: 300px, @h: 70px);