[251127] feat: Featured Brands - NBCU Series
🕐 커밋 시간: 2025. 11. 27. 10:42:58 📊 변경 통계: • 총 파일: 7개 • 추가: +137줄 • 삭제: -1줄 📁 추가된 파일: + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSectionTitle/NBCUSectionTitle.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSectionTitle/NBCUSectionTitle.module.less + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSeries/NBCUSeries.jsx + com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUSeries/NBCUSeries.module.less 📝 수정된 파일: ~ com.twin.app.shoptime/.gitignore ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.jsx ~ com.twin.app.shoptime/src/views/FeaturedBrandsPanel/NBCUContent/NBCUContent.module.less 🔧 주요 변경 내용: • 중간 규모 기능 개선 • 모듈 구조 개선
This commit is contained in:
2
com.twin.app.shoptime/.gitignore
vendored
2
com.twin.app.shoptime/.gitignore
vendored
@@ -22,3 +22,5 @@ nul
|
||||
OPTIMAL.md
|
||||
.docs
|
||||
|
||||
GEMINI.md
|
||||
|
||||
|
||||
@@ -1,17 +1,69 @@
|
||||
import React, { memo, useCallback, useState } from "react";
|
||||
import React, { memo, useCallback, useState, useEffect } from "react";
|
||||
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
import Spottable from "@enact/spotlight/Spottable";
|
||||
|
||||
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
|
||||
import NBCUSectionTitle from "./NBCUSectionTitle/NBCUSectionTitle";
|
||||
import { $L } from "../../../utils/helperMethods";
|
||||
import css from "./NBCUContent.module.less";
|
||||
import NBCUList from "./NBCUList/NBCUList";
|
||||
import NBCUSeries from "./NBCUSeries/NBCUSeries";
|
||||
|
||||
const STRING_CONF = {
|
||||
NBCU: "NBCU",
|
||||
PICKED_FOR_YOU: "PICKED FOR YOU",
|
||||
};
|
||||
|
||||
// Mock data for Series
|
||||
const MOCK_BRAND_SERIES_GROUP_INFO = [
|
||||
{
|
||||
seriesId: "series-1",
|
||||
seriesNm: "Drama Collection",
|
||||
seriesImgUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
patnrId: "nbcu-partner-1",
|
||||
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
|
||||
productId: `drama-${i}`,
|
||||
productNm: `Drama Show ${i + 1}`,
|
||||
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
priceInfo: "$15.00|$10.00|N|$5.00|33%|PROMO|2025-12-31",
|
||||
})),
|
||||
},
|
||||
{
|
||||
seriesId: "series-2",
|
||||
seriesNm: "Comedy Series",
|
||||
seriesImgUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
patnrId: "nbcu-partner-1",
|
||||
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
|
||||
productId: `comedy-${i}`,
|
||||
productNm: `Comedy Show ${i + 1}`,
|
||||
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
priceInfo: "$12.00|$8.00|N|$4.00|33%|PROMO|2025-12-31",
|
||||
})),
|
||||
},
|
||||
{
|
||||
seriesId: "series-3",
|
||||
seriesNm: "Sci-Fi Originals",
|
||||
seriesImgUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
patnrId: "nbcu-partner-1",
|
||||
brandSeriesProductInfo: Array.from({ length: 6 }).map((_, i) => ({
|
||||
productId: `scifi-${i}`,
|
||||
productNm: `Sci-Fi Show ${i + 1}`,
|
||||
imageUrl: "assets/images/img-thumb-empty-product@3x.png",
|
||||
priceInfo: "$18.00|$12.00|N|$6.00|33%|PROMO|2025-12-31",
|
||||
})),
|
||||
},
|
||||
];
|
||||
|
||||
const MOCK_BRAND_SERIES_INFO = [
|
||||
{ seriesId: "series-1", seriesNm: "LOVE ISLAND" },
|
||||
{ seriesId: "series-2", seriesNm: "TOP CHEF" },
|
||||
{ seriesId: "series-3", seriesNm: "BELOW DECK" },
|
||||
];
|
||||
|
||||
const SpottableDiv = Spottable('div');
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||
"div"
|
||||
@@ -26,6 +78,11 @@ const NBCUContent = ({
|
||||
order,
|
||||
}) => {
|
||||
const [firstChk, setFirstChk] = useState(0);
|
||||
const [selectedSeriesId, setSelectedSeriesId] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
console.log('[NBCUContent] Rendered. order:', order);
|
||||
}, [order]);
|
||||
|
||||
const _handleItemFocus = useCallback(() => {
|
||||
if (handleItemFocus) handleItemFocus(spotlightId, shelfOrder);
|
||||
@@ -65,6 +122,9 @@ const NBCUContent = ({
|
||||
data-title="nbcu"
|
||||
label="NBCU Heading 1"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<NBCUList
|
||||
handleItemFocus={_handleItemFocus}
|
||||
spotlightId={spotlightId}
|
||||
@@ -72,6 +132,45 @@ const NBCUContent = ({
|
||||
shelfTitle={shelfTitle}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
/>
|
||||
|
||||
{/* Keyword Bubble Section (Dummy) */}
|
||||
{/* <div className={css.keywordContainer}>
|
||||
{['Action', 'Comedy', 'Drama', 'Sci-Fi', 'Thriller', 'Romance', 'Documentary'].map((keyword, index) => (
|
||||
<SpottableDiv
|
||||
key={index}
|
||||
className={css.keywordBubble}
|
||||
onClick={() => console.log(`Clicked keyword: ${keyword}`)}
|
||||
>
|
||||
{keyword}
|
||||
</SpottableDiv>
|
||||
))}
|
||||
</div> */}
|
||||
|
||||
{/* Picked For You Section Title */}
|
||||
<NBCUSectionTitle
|
||||
title={$L(STRING_CONF.PICKED_FOR_YOU)}
|
||||
data-title="picked-for-you"
|
||||
label="Picked For You Heading"
|
||||
isBlack={true}
|
||||
/>
|
||||
|
||||
{/* Series Component with Mock Data */}
|
||||
<NBCUSeries
|
||||
brandSeriesGroupInfo={MOCK_BRAND_SERIES_GROUP_INFO}
|
||||
brandSeriesInfo={MOCK_BRAND_SERIES_INFO}
|
||||
fromGNB={false}
|
||||
fromQuickMenu={false}
|
||||
handleItemFocus={_handleItemFocus}
|
||||
order={order}
|
||||
shelfOrder={shelfOrder}
|
||||
shelfTitle={shelfTitle}
|
||||
spotlightId={`${spotlightId}-series`}
|
||||
selectedPatncNm="NBCU"
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
selectedSeriesId={selectedSeriesId}
|
||||
setSelectedSeriesId={setSelectedSeriesId}
|
||||
/>
|
||||
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1 +1,36 @@
|
||||
@import "../../../style/CommonStyle.module.less";
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 50px 0; // Adjust padding as needed
|
||||
}
|
||||
|
||||
.keywordContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
padding: 0 60px; // Match side padding of other contents
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.keywordBubble {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px 24px;
|
||||
border-radius: 30px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: #ffffff;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
border: 2px solid transparent;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
&:focus, &:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-color: #ffffff;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import React, { memo } from "react";
|
||||
|
||||
import classNames from "classnames";
|
||||
|
||||
import css from "./NBCUSectionTitle.module.less";
|
||||
|
||||
export default memo(function NBCUSectionTitle({
|
||||
className,
|
||||
itemCount,
|
||||
title,
|
||||
label,
|
||||
isBlack = false,
|
||||
...rest
|
||||
}) {
|
||||
return (
|
||||
<h2
|
||||
className={classNames(css.sectionTitle, isBlack && css.blackTitle, className)}
|
||||
aria-label={label ? label : title}
|
||||
tabIndex={-1}
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
{...rest}
|
||||
>
|
||||
{title}
|
||||
{itemCount && <span>({itemCount})</span>}
|
||||
</h2>
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,31 @@
|
||||
@import "../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../style/utils.module.less";
|
||||
|
||||
.sectionTitle {
|
||||
position: relative;
|
||||
.flex(@justifyCenter: flex-start);
|
||||
min-height: 50px;
|
||||
font-weight: bold;
|
||||
font-size: 42px;
|
||||
color: #000000 !important;
|
||||
|
||||
&::before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
.size(@w: 6px, @h: 36px);
|
||||
margin-right: 12px;
|
||||
background-color: #000000 !important;
|
||||
}
|
||||
|
||||
span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.blackTitle {
|
||||
color: #000000;
|
||||
|
||||
&::before {
|
||||
background-color: #000000;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
import React, { memo, useCallback, useEffect, useState } from "react";
|
||||
|
||||
import Spotlight from "@enact/spotlight";
|
||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||
|
||||
import NBCUSectionTitle from "../NBCUSectionTitle/NBCUSectionTitle";
|
||||
import { $L } from "../../../../utils/helperMethods";
|
||||
import css from "./NBCUSeries.module.less";
|
||||
import SeriesContents from "../../Series/SeriesContents/SeriesContents";
|
||||
import SeriesNav from "../../Series/SeriesNav/SeriesNav";
|
||||
|
||||
const STRING_CONF = {
|
||||
SERIES: "SERIES",
|
||||
};
|
||||
|
||||
const Container = SpotlightContainerDecorator(
|
||||
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||
"div"
|
||||
);
|
||||
|
||||
const NBCUSeries = ({
|
||||
brandSeriesGroupInfo,
|
||||
brandSeriesInfo,
|
||||
fromGNB,
|
||||
fromQuickMenu,
|
||||
handleItemFocus,
|
||||
order,
|
||||
shelfOrder,
|
||||
shelfTitle,
|
||||
spotlightId,
|
||||
selectedPatncNm,
|
||||
selectedPatnrId,
|
||||
selectedSeriesId,
|
||||
setSelectedSeriesId,
|
||||
}) => {
|
||||
const [filteredBrandSeriesGroupInfo, setFilteredSeriesGroupInfo] = useState();
|
||||
const [firstChk, setFirstChk] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedSeriesId) {
|
||||
return setFilteredSeriesGroupInfo(brandSeriesGroupInfo);
|
||||
}
|
||||
|
||||
setFilteredSeriesGroupInfo(
|
||||
brandSeriesGroupInfo.filter(
|
||||
({ seriesId }) => seriesId === selectedSeriesId
|
||||
)
|
||||
);
|
||||
}, [brandSeriesGroupInfo, selectedSeriesId]);
|
||||
|
||||
const _handleItemFocus = useCallback(() => {
|
||||
if (handleItemFocus) handleItemFocus(spotlightId, shelfOrder);
|
||||
|
||||
const c = Spotlight.getCurrent();
|
||||
if (firstChk === 0) {
|
||||
if (c) {
|
||||
let cAriaLabel = c.getAttribute("aria-label");
|
||||
if (cAriaLabel) {
|
||||
cAriaLabel = "series, Heading1," + cAriaLabel;
|
||||
c.setAttribute("aria-label", cAriaLabel);
|
||||
}
|
||||
}
|
||||
setFirstChk(1);
|
||||
} else if (firstChk === 1) {
|
||||
if (c) {
|
||||
let cAriaLabel = c.getAttribute("aria-label");
|
||||
if (cAriaLabel) {
|
||||
const newcAriaLabel = cAriaLabel.replace("series, Heading1,", "");
|
||||
c.setAttribute("aria-label", newcAriaLabel);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}, [handleItemFocus, firstChk]);
|
||||
|
||||
return (
|
||||
<Container
|
||||
className={css.container}
|
||||
data-shelf-order={order}
|
||||
data-wheel-point
|
||||
spotlightId={spotlightId}
|
||||
>
|
||||
{/* <NBCUSectionTitle title={$L(STRING_CONF.SERIES)} data-title="series" isBlack={true} /> */}
|
||||
<SeriesNav
|
||||
brandSeriesInfo={brandSeriesInfo}
|
||||
fromGNB={fromGNB}
|
||||
fromQuickMenu={fromQuickMenu}
|
||||
handleItemFocus={_handleItemFocus}
|
||||
selectedPatncNm={selectedPatncNm}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
selectedSeriesId={selectedSeriesId}
|
||||
setSelectedSeriesId={setSelectedSeriesId}
|
||||
/>
|
||||
{filteredBrandSeriesGroupInfo &&
|
||||
filteredBrandSeriesGroupInfo.map(
|
||||
(
|
||||
{
|
||||
brandSeriesProductInfo,
|
||||
patnrId,
|
||||
seriesId,
|
||||
seriesImgUrl,
|
||||
seriesNm,
|
||||
},
|
||||
contentsIndex
|
||||
) => (
|
||||
<SeriesContents
|
||||
brandSeriesProductInfo={brandSeriesProductInfo}
|
||||
filteredBrandLength={filteredBrandSeriesGroupInfo.length}
|
||||
contentsIndex={contentsIndex}
|
||||
handleItemFocus={_handleItemFocus}
|
||||
isCarousel={!selectedSeriesId}
|
||||
key={`${spotlightId}-${contentsIndex}`}
|
||||
patnrId={patnrId}
|
||||
selectedPatnrId={selectedPatnrId}
|
||||
selectedSeriesId={selectedSeriesId}
|
||||
seriesId={seriesId}
|
||||
seriesImgUrl={seriesImgUrl}
|
||||
seriesNm={seriesNm}
|
||||
spotlightId={spotlightId}
|
||||
shelfOrder={shelfOrder}
|
||||
shelfTitle={shelfTitle}
|
||||
selectedPatncNm={selectedPatncNm}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</Container>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(NBCUSeries);
|
||||
@@ -0,0 +1,12 @@
|
||||
@import "../../../../style/CommonStyle.module.less";
|
||||
@import "../../../../style/utils.module.less";
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
margin-bottom: 36px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 24px;
|
||||
padding-left: 60px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user