[251006] feat: views - PlayerPanel.jsx, LiveShowContainer.jsx, LiveSho...

🕐 커밋 시간: 2025. 10. 06. 17:12:55

📊 변경 통계:
  • 총 파일: 7개
  • 추가: +33줄
  • 삭제: -15줄

📁 추가된 파일:
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/LiveShowContainer.jsx
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/LiveShowContainer.module.less
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.jsx
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowContainer.jsx
  + com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowContainer.module.less

📝 수정된 파일:
  ~ com.twin.app.shoptime/src/views/PlayerPanel/PlayerPanel.jsx

🔧 함수 변경 내용:
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/LiveShowContainer.module.less (unknown):
     Added: position(), gradient(), focused()
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowButton.module.less (unknown):
     Added: position(), gradient(), focused()
  📄 com.twin.app.shoptime/src/views/PlayerPanel/PlayerTabContents/v2/ShopNowContainer.module.less (unknown):
     Added: position(), gradient()
This commit is contained in:
2025-10-06 17:12:57 +09:00
parent 66ba686f33
commit ea5a855019
7 changed files with 405 additions and 15 deletions

View File

@@ -55,7 +55,9 @@ import PlayerOverlayQRCode from './PlayerOverlay/PlayerOverlayQRCode';
import css from './PlayerPanel.module.less';
import PlayerTabButton from './PlayerTabContents/TabButton/PlayerTabButton';
import TabContainer from './PlayerTabContents/TabContainer';
import BelowTabContainer from './PlayerTabContents/v2/BelowTabContainer';
import LiveShowContainer from './PlayerTabContents/v2/LiveShowContainer';
import ShopNowContainer from './PlayerTabContents/v2/ShopNowContainer';
import ShopNowButton from './PlayerTabContents/v2/ShopNowButton';
const Container = SpotlightContainerDecorator(
{ enterTo: 'default-element', preserveld: true },
@@ -200,6 +202,7 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
isDetailMediaReady: false,
});
const [isVODPaused, setIsVODPaused] = USE_STATE('isVODPaused', false);
const [belowTabMode, setBelowTabMode] = USE_STATE('belowTabMode', 'liveShow');
const panels = USE_SELECTOR('panels', (state) => state.panels.panels);
const chatData = USE_SELECTOR('chatData', (state) => state.play.chatData);
@@ -2057,20 +2060,35 @@ const PlayerPanel = ({ isTabActivated, panelInfo, isOnTop, spotlightId, ...props
/>
)}
{showBelowContents && (
<BelowTabContainer
panelInfo={panelInfo}
liveInfos={playListInfo}
currentTime={currentTime}
setSelectedIndex={setSelectedIndex}
videoVerticalVisible={videoVerticalVisible}
currentVideoShowId={playListInfo && playListInfo[selectedIndex]?.showId}
handleItemFocus={handleItemFocus}
tabTitle={[
$L('SHOP NOW'),
panelInfo?.shptmBanrTpNm === 'LIVE' ? $L('LIVE CHANNEL') : $L('FEATURED SHOWS'),
]}
/>
{!panelInfo?.modal && (
<>
{belowTabMode === 'liveShow' && (
<LiveShowContainer
panelInfo={panelInfo}
liveInfos={playListInfo}
currentTime={currentTime}
setSelectedIndex={setSelectedIndex}
videoVerticalVisible={videoVerticalVisible}
currentVideoShowId={playListInfo && playListInfo[selectedIndex]?.showId}
handleItemFocus={handleItemFocus}
onLiveChannelButtonClick={() => setBelowTabMode('shopNowButton')}
/>
)}
{belowTabMode === 'shopNowButton' && (
<ShopNowButton onClick={() => setBelowTabMode('shopNow')} />
)}
{belowTabMode === 'shopNow' && (
<ShopNowContainer
panelInfo={panelInfo}
liveInfos={playListInfo}
currentTime={currentTime}
setSelectedIndex={setSelectedIndex}
videoVerticalVisible={videoVerticalVisible}
currentVideoShowId={playListInfo && playListInfo[selectedIndex]?.showId}
handleItemFocus={handleItemFocus}
/>
)}
</>
)}
</Container>

View File

@@ -0,0 +1,49 @@
import React from 'react';
import classNames from 'classnames';
import Spottable from '@enact/spotlight/Spottable';
import css from './LiveShowContainer.module.less';
import icon_arrow_dwon from '../../../../../assets/images/player/icon_tabcontainer_arrow_down.png';
import LiveChannelContents from './LiveChannelContents';
const SpottableDiv = Spottable('div');
export default function LiveShowContainer({
liveInfos,
currentTime,
setSelectedIndex,
videoVerticalVisible,
currentVideoShowId,
handleItemFocus,
tabTitle,
panelInfo,
onLiveChannelButtonClick,
}) {
return (
<div className={css.container}>
<SpottableDiv
className={css.liveChannelButton}
onClick={onLiveChannelButtonClick}
spotlightId="below-tab-live-channel-button"
>
<span className={css.buttonText}>LIVE CHANNEL</span>
<div className={css.arrowIcon}>
<img src={icon_arrow_dwon} alt="arrow down" />
</div>
</SpottableDiv>
<LiveChannelContents
liveInfos={liveInfos}
currentTime={currentTime}
setSelectedIndex={setSelectedIndex}
videoVerticalVisible={videoVerticalVisible}
currentVideoShowId={currentVideoShowId}
handleItemFocus={handleItemFocus}
tabTitle={tabTitle}
panelInfo={panelInfo}
/>
</div>
);
}

View File

@@ -0,0 +1,214 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.size(@w: 100%, @h: 365px);
.position(@position: fixed, @bottom: 0, @left: 0);
padding: 60px;
background: linear-gradient(
to top,
rgba(0, 0, 0, 0.95) 0%,
rgba(0, 0, 0, 0.85) 40%,
rgba(0, 0, 0, 0.6) 70%,
rgba(0, 0, 0, 0) 100%
);
border-top: 1px solid rgba(234, 234, 234, 0.3);
overflow: hidden;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start, @direction: column);
z-index: 5;
> * + * {
margin-top: 20px;
}
&::before {
content: "";
.position(@position: absolute, @top: 0, @left: 0);
.size(@w: 100%, @h: 100%);
background: linear-gradient(
90deg,
rgba(30, 30, 30, 0.4) 0%,
rgba(50, 50, 50, 0.25) 30%,
transparent 50%,
rgba(50, 50, 50, 0.25) 70%,
rgba(30, 30, 30, 0.4) 100%
);
pointer-events: none;
z-index: -1;
}
}
.liveChannelButton {
.size(@w: 300px, @h: 70px);
padding: 20px 30px;
border-radius: 100px;
border: 1px solid rgba(234, 234, 234, 0.5);
overflow: hidden;
.flex(@display: flex, @justifyCenter: space-between, @alignCenter: center);
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(5px);
cursor: pointer;
transition: all 0.3s ease;
.buttonText {
color: @COLOR_WHITE;
font-size: 24px;
font-family: @baseFont;
font-weight: 600;
line-height: 35px;
}
.arrowIcon {
.size(@w: 26.25px, @h: 15.63px);
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
&:hover {
background: rgba(0, 0, 0, 0.5);
border-color: rgba(234, 234, 234, 0.7);
}
&:focus {
background: rgba(199, 8, 80, 0.2);
border-color: @PRIMARY_COLOR_RED;
&::after {
.focused(@boxShadow: 22px, @borderRadius: 100px);
}
}
}
.channelList {
width: 100%;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start);
overflow-x: auto;
overflow-y: hidden;
> * + * {
margin-left: 30px;
}
}
.channelCard {
.size(@w: 470px, @h: 155px);
padding: 18px;
background: rgba(44, 44, 44, 0.85);
backdrop-filter: blur(10px);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.1);
flex-shrink: 0;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start);
transition: all 0.3s ease;
> * + * {
margin-left: 10px;
}
.thumbnail {
flex: 1 1 0;
.size(@w: 212px, @h: 119px);
overflow: hidden;
.flex(@display: flex, @justifyCenter: center, @alignCenter: center);
> img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.cardContent {
flex: 1 1 0;
height: 110px;
.flex(@display: flex, @justifyCenter: space-between, @alignCenter: flex-start, @direction: column);
.channelHeader {
width: 100%;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: center);
> * + * {
margin-left: 9px;
}
.logoWrapper {
.size(@w: 40px, @h: 40px);
border-radius: 100px;
.position(@position: relative);
overflow: hidden;
.flex(@display: flex, @justifyCenter: center, @alignCenter: center);
.logo {
max-width: 80%;
max-height: 80%;
object-fit: contain;
}
}
.channelName {
color: #EAEAEA;
font-size: 24px;
font-family: @baseFont;
font-weight: 700;
line-height: 31px;
margin: 0;
}
}
.programName {
width: 100%;
color: #EAEAEA;
font-size: 24px;
font-family: @baseFont;
font-weight: 400;
line-height: 31px;
.elip(@clamp: 1);
}
.progressBarWrapper {
width: 100%;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start);
> * + * {
margin-left: 10px;
}
.progressBar {
flex: 1 1 0;
height: 5px;
.position(@position: relative);
overflow: hidden;
.progressTrack {
.size(@w: 100%, @h: 5px);
.position(@position: absolute, @top: 0, @left: 0);
background: #D4D4D4;
}
.progressFill {
height: 5px;
.position(@position: absolute, @top: 0, @left: 0);
background: #7D848C;
transition: width 0.3s ease;
}
}
}
}
&:hover {
background: rgba(44, 44, 44, 0.95);
border-color: rgba(255, 255, 255, 0.2);
}
&:focus {
background: rgba(44, 44, 44, 1);
border-color: @PRIMARY_COLOR_RED;
&::after {
.focused(@boxShadow: 22px, @borderRadius: 12px);
}
}
}

View File

@@ -0,0 +1,17 @@
import React from 'react';
import Spottable from '@enact/spotlight/Spottable';
import css from './ShopNowButton.module.less';
const SpottableDiv = Spottable('div');
export default function ShopNowButton({ onClick }) {
return (
<div className={css.container}>
<SpottableDiv className={css.shopNowButton} onClick={onClick} spotlightId="shop-now-button">
<span className={css.buttonText}>SHOP NOW</span>
</SpottableDiv>
</div>
);
}

View File

@@ -0,0 +1,46 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.position(@position: fixed, @bottom: 247px, @right: 60px);
z-index: 5;
}
.shopNowButton {
width: 188px;
height: 85px;
padding: 10px 30px;
background: linear-gradient(0deg, rgba(0, 0, 0, 0.30) 0%, rgba(0, 0, 0, 0.30) 100%);
border: 1px solid rgba(234, 234, 234, 0.5);
overflow: hidden;
border-radius: 12px;
display: inline-flex;
justify-content: center;
align-items: center;
gap: 10px;
cursor: pointer;
transition: all 0.3s ease;
&:hover {
background: rgba(0, 0, 0, 0.5);
border-color: rgba(234, 234, 234, 0.7);
}
&:focus {
background: rgba(199, 8, 80, 0.2);
border-color: @PRIMARY_COLOR_RED;
&::after {
.focused(@boxShadow: 22px, @borderRadius: 12px);
}
}
}
.buttonText {
color: #FCFCFC;
font-size: 22px;
font-family: 'LG Smart UI';
font-weight: 700;
line-height: 15px;
word-wrap: break-word;
}

View File

@@ -0,0 +1,7 @@
import React from 'react';
import css from './ShopNowContainer.module.less';
export default function ShopNowContainer() {
return <div className={css.container}>{/* 나중에 콘텐츠 추가 예정 */}</div>;
}

View File

@@ -0,0 +1,39 @@
@import "../../../../style/CommonStyle.module.less";
@import "../../../../style/utils.module.less";
.container {
.size(@w: 100%, @h: 365px);
.position(@position: fixed, @bottom: 0, @left: 0);
padding: 60px;
background: linear-gradient(
to top,
rgba(0, 0, 0, 0.95) 0%,
rgba(0, 0, 0, 0.85) 40%,
rgba(0, 0, 0, 0.6) 70%,
rgba(0, 0, 0, 0) 100%
);
border-top: 1px solid rgba(234, 234, 234, 0.3);
overflow: hidden;
.flex(@display: flex, @justifyCenter: flex-start, @alignCenter: flex-start, @direction: column);
z-index: 5;
> * + * {
margin-top: 20px;
}
&::before {
content: "";
.position(@position: absolute, @top: 0, @left: 0);
.size(@w: 100%, @h: 100%);
background: linear-gradient(
90deg,
rgba(30, 30, 30, 0.4) 0%,
rgba(50, 50, 50, 0.25) 30%,
transparent 50%,
rgba(50, 50, 50, 0.25) 70%,
rgba(30, 30, 30, 0.4) 100%
);
pointer-events: none;
z-index: -1;
}
}