[SearchPanel] 액션 추가/VirtualGridList 적용/컴포넌트화
This commit is contained in:
BIN
com.twin.app.shoptime/assets/fonts/tahoma/tahoma.ttf
Normal file
BIN
com.twin.app.shoptime/assets/fonts/tahoma/tahoma.ttf
Normal file
Binary file not shown.
BIN
com.twin.app.shoptime/assets/fonts/tahoma/tahomabd.ttf
Normal file
BIN
com.twin.app.shoptime/assets/fonts/tahoma/tahomabd.ttf
Normal file
Binary file not shown.
BIN
com.twin.app.shoptime/assets/searchpanel/bg_srch_curation.png
Normal file
BIN
com.twin.app.shoptime/assets/searchpanel/bg_srch_curation.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 11 KiB |
@@ -43,6 +43,7 @@ export const types = {
|
|||||||
// search actions
|
// search actions
|
||||||
GET_SEARCH: "GET_SEARCH",
|
GET_SEARCH: "GET_SEARCH",
|
||||||
RESET_SEARCH: "RESET_SEARCH",
|
RESET_SEARCH: "RESET_SEARCH",
|
||||||
|
GET_SEARCH_PROCESSED: "GET_SEARCH_PROCESSED",
|
||||||
|
|
||||||
// event actions
|
// event actions
|
||||||
GET_WELCOME_EVENT_INFO: "GET_WELCOME_EVENT_INFO",
|
GET_WELCOME_EVENT_INFO: "GET_WELCOME_EVENT_INFO",
|
||||||
|
|||||||
@@ -13,6 +13,21 @@ export const getSearch = (params) => (dispatch, getState) => {
|
|||||||
type: types.GET_SEARCH,
|
type: types.GET_SEARCH,
|
||||||
payload: response.data,
|
payload: response.data,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const processedData = response.data.data.result.results.reduce(
|
||||||
|
(acc, current) => {
|
||||||
|
acc.data[current.type] = current.docs;
|
||||||
|
acc.totalCount[current.type] = current.total_count;
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ data: {}, totalCount: {} }
|
||||||
|
);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: types.GET_SEARCH_PROCESSED,
|
||||||
|
payload: processedData,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const onFail = (error) => {
|
const onFail = (error) => {
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ import { types } from "../actions/actionTypes";
|
|||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
searchDatas: {},
|
searchDatas: {},
|
||||||
|
processedDatas: {
|
||||||
|
data: {},
|
||||||
|
totalCount: {},
|
||||||
|
},
|
||||||
searchPerformed: false,
|
searchPerformed: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -14,6 +18,13 @@ export const searchReducer = (state = initialState, action) => {
|
|||||||
searchPerformed: true,
|
searchPerformed: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
case types.GET_SEARCH_PROCESSED:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
processedDatas: action.payload,
|
||||||
|
searchPerformed: true,
|
||||||
|
};
|
||||||
|
|
||||||
case types.RESET_SEARCH:
|
case types.RESET_SEARCH:
|
||||||
return {
|
return {
|
||||||
...initialState,
|
...initialState,
|
||||||
|
|||||||
@@ -24,12 +24,22 @@
|
|||||||
font-family: "RobotoBold";
|
font-family: "RobotoBold";
|
||||||
src: url("../../assets/fonts/roboto/Roboto-Bold.woff") format("woff");
|
src: url("../../assets/fonts/roboto/Roboto-Bold.woff") format("woff");
|
||||||
}
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "Tahoma";
|
||||||
|
src: url("../../assets/fonts/tahoma/tahoma.ttf") format("ttf");
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "TahomaBold";
|
||||||
|
src: url("../../assets/fonts/tahoma/tahomabd.ttf") format("ttf");
|
||||||
|
}
|
||||||
@baseFont: "LGSmartUI";
|
@baseFont: "LGSmartUI";
|
||||||
@baseFontBold: "LGSmartUIBold";
|
@baseFontBold: "LGSmartUIBold";
|
||||||
@arialFont: "Arial";
|
@arialFont: "Arial";
|
||||||
@arialFontBold: "ArialBold";
|
@arialFontBold: "ArialBold";
|
||||||
@robotoFont: "Roboto";
|
@robotoFont: "Roboto";
|
||||||
@robotoFontBold: "RobotoBold";
|
@robotoFontBold: "RobotoBold";
|
||||||
|
@tahomaFont: "Tahoma";
|
||||||
|
@tahomaFontBold: "TahomaBold";
|
||||||
|
|
||||||
@globalHeight: 1080px;
|
@globalHeight: 1080px;
|
||||||
@globalWidth: 1920px;
|
@globalWidth: 1920px;
|
||||||
@@ -60,6 +70,7 @@
|
|||||||
@COLOR_BLACK: #000000;
|
@COLOR_BLACK: #000000;
|
||||||
@COLOR_NAVY: #2c343f;
|
@COLOR_NAVY: #2c343f;
|
||||||
@COLOR_SKYBLUE: #e7ebef;
|
@COLOR_SKYBLUE: #e7ebef;
|
||||||
|
@COLOR_LIGHT_SKYBLUE: #edeff3;
|
||||||
|
|
||||||
/* ----- 추가 CommonStyles (chw) ----- */
|
/* ----- 추가 CommonStyles (chw) ----- */
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,16 @@ export default function SearchPanel() {
|
|||||||
const searchDatas = useSelector(
|
const searchDatas = useSelector(
|
||||||
(state) => state.search.searchDatas.data?.result.results
|
(state) => state.search.searchDatas.data?.result.results
|
||||||
);
|
);
|
||||||
|
const {
|
||||||
|
theme: themeDatas,
|
||||||
|
show: showDatas,
|
||||||
|
item: itemDatas,
|
||||||
|
} = useSelector((state) => state.search.processedDatas.data);
|
||||||
|
const {
|
||||||
|
theme: themeCount,
|
||||||
|
show: showCount,
|
||||||
|
item: itemCount,
|
||||||
|
} = useSelector((state) => state.search.processedDatas.totalCount);
|
||||||
const searchPerformed = useSelector((state) => state.search.searchPerformed);
|
const searchPerformed = useSelector((state) => state.search.searchPerformed);
|
||||||
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
@@ -110,7 +120,15 @@ export default function SearchPanel() {
|
|||||||
/>
|
/>
|
||||||
{searchPerformed ? (
|
{searchPerformed ? (
|
||||||
searchDatas && searchDatas.length > 0 ? (
|
searchDatas && searchDatas.length > 0 ? (
|
||||||
<SearchResults contents={searchDatas} />
|
<SearchResults
|
||||||
|
themeDatas={themeDatas}
|
||||||
|
itemDatas={itemDatas}
|
||||||
|
showDatas={showDatas}
|
||||||
|
themeCount={themeCount}
|
||||||
|
showCount={showCount}
|
||||||
|
itemCount={itemCount}
|
||||||
|
query={searchQuery}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<NoSearchResults />
|
<NoSearchResults />
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { memo } from "react";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import css from "./SearchItemCard.module.less";
|
||||||
|
|
||||||
|
const ItemContainer = Spottable("div");
|
||||||
|
|
||||||
|
export default memo(function SearchItemCard({
|
||||||
|
dcPrice,
|
||||||
|
partnerLogo,
|
||||||
|
partnerName,
|
||||||
|
price,
|
||||||
|
reviewGrade,
|
||||||
|
soldout,
|
||||||
|
thumbnail,
|
||||||
|
title,
|
||||||
|
contentId,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ItemContainer className={css.card} {...rest}>
|
||||||
|
<div className={css.imageBox}>
|
||||||
|
<img src={thumbnail} alt={title} />
|
||||||
|
</div>
|
||||||
|
<div className={css.infoWrap}>
|
||||||
|
<p className={css.title}>{title}</p>
|
||||||
|
<div className={css.priceWrap}>
|
||||||
|
<span className={css.price}>{price}</span>
|
||||||
|
<strong className={css.dcPrice}>{dcPrice}</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ItemContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.card {
|
||||||
|
.size(@w: 561px, @h:150px);
|
||||||
|
background-color: @COLOR_LIGHT_SKYBLUE;
|
||||||
|
overflow: hidden;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
.flex();
|
||||||
|
|
||||||
|
.imageBox {
|
||||||
|
.size(@w: 150px, @h: 100%);
|
||||||
|
background-color: @COLOR_WHITE;
|
||||||
|
background-size: cover;
|
||||||
|
|
||||||
|
> img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.infoWrap {
|
||||||
|
.size(@w: calc(100% - 150px), @h: 100%);
|
||||||
|
padding-left: 24px;
|
||||||
|
.flex(@direction: column, @alignCenter: flex-start);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
.font(@fontFamily: @arialFont, @fontSize: 24px);
|
||||||
|
.elip(@clamp: 2);
|
||||||
|
line-height: 1.33;
|
||||||
|
letter-spacing: -0.6px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price {
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
.font(@fontFamily: @arialFont, @fontSize: 20px);
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dcPrice {
|
||||||
|
color: @PRIMARY_COLOR_RED;
|
||||||
|
.font(@fontFamily: @arialFontBold, @fontSize: 28px);
|
||||||
|
line-height: 0.86;
|
||||||
|
letter-spacing: -0.7px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border: 4px solid @PRIMARY_COLOR_RED;
|
||||||
|
box-shadow: 0 0 50px 0 rgba(11, 8, 8, 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
|
import { VirtualGridList } from "@enact/sandstone/VirtualList";
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
import ri from "@enact/ui/resolution";
|
||||||
|
|
||||||
|
import SearchItemCard from "./SearchItemCard/SearchItemCard";
|
||||||
|
import css from "./SearchItemResults.module.less";
|
||||||
|
|
||||||
|
const LIST_ITEM_CONF = {
|
||||||
|
ITEM_WIDTH: 561 * 2,
|
||||||
|
ITEM_HEIGHT: 150 * 2,
|
||||||
|
SPACING: 30 * 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function SearchItemResults({ itemDatas, itemCount, ...rest }) {
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
const itemData = itemDatas[index];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchItemCard {...rest} key={itemDatas.contentId} {...itemData} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[itemDatas]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className={css.container}>
|
||||||
|
{itemDatas && (
|
||||||
|
<VirtualGridList
|
||||||
|
className={css.grid}
|
||||||
|
dataSize={itemDatas.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemRenderer={renderItem}
|
||||||
|
itemSize={{
|
||||||
|
minWidth: ri.scale(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||||
|
minHeight: ri.scale(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||||
|
}}
|
||||||
|
spacing={ri.scale(LIST_ITEM_CONF.SPACING)}
|
||||||
|
scrollMode="translate"
|
||||||
|
horizontalScrollbar="hidden"
|
||||||
|
noScrollByWheel
|
||||||
|
// onScrollStop={handleScrollStop}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
@import "../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex();
|
||||||
|
margin: 30px 0 50px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
height: 150px;
|
||||||
|
overflow: unset;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,52 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
export default function SearchResults({ datas }) {
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
return <p>data</p>;
|
|
||||||
|
import SectionTitle from "../../../components/SectionTitle/SectionTitle";
|
||||||
|
import { $L } from "../../../utils/helperMethods";
|
||||||
|
import SearchItemResults from "./SearchItemResults/SearchItemResults";
|
||||||
|
import css from "./SearchResults.module.less";
|
||||||
|
import SearchShowResults from "./SearchShowResults/SearchShowResults";
|
||||||
|
import SearchThemeResults from "./SearchThemeResults/SearchThemeResults";
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ enterTo: "last-focused" },
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function SearchResults({
|
||||||
|
themeDatas,
|
||||||
|
itemDatas,
|
||||||
|
showDatas,
|
||||||
|
themeCount,
|
||||||
|
itemCount,
|
||||||
|
showCount,
|
||||||
|
query,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Container className={css.container}>
|
||||||
|
{themeDatas && (
|
||||||
|
<>
|
||||||
|
<SectionTitle title={$L("Hot Picks")} />
|
||||||
|
<SearchThemeResults themeDatas={themeDatas} themeCount={themeCount} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{showDatas && (
|
||||||
|
<>
|
||||||
|
<SectionTitle title={$L("Shows") + " (" + showCount + ")"} />
|
||||||
|
<SearchShowResults showDatas={showDatas} showCount={showCount} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{itemDatas && (
|
||||||
|
<>
|
||||||
|
<SectionTitle title={$L("Items") + " (" + itemCount + ")"} />
|
||||||
|
<SearchItemResults
|
||||||
|
itemDatas={itemDatas}
|
||||||
|
itemCount={itemCount}
|
||||||
|
query={query}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,3 @@
|
|||||||
@import "../../../style/CommonStyle.module.less";
|
|
||||||
@import "../../../style/utils.module.less";
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
background-color: yellowgreen;
|
padding: 94px 60px 0 60px;
|
||||||
|
|
||||||
&:focus-within {
|
|
||||||
border: 1px solid red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.container2 {
|
|
||||||
height: 240px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.itemList {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React, { memo } from "react";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import IcLiveShow from "../../../../../../assets/icon/tag/tag-liveshow.svg";
|
||||||
|
import css from "./SearchShowCard.module.less";
|
||||||
|
|
||||||
|
const CardContainer = Spottable("div");
|
||||||
|
|
||||||
|
export default memo(function SearchShowCard({
|
||||||
|
endTime,
|
||||||
|
liveFlag,
|
||||||
|
partnerId,
|
||||||
|
partnerLogo,
|
||||||
|
partnerName,
|
||||||
|
startTime,
|
||||||
|
thumbnail,
|
||||||
|
title,
|
||||||
|
contentId,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<CardContainer className={css.card} {...rest}>
|
||||||
|
<div className={css.imageBox}>
|
||||||
|
{liveFlag === "Y" && (
|
||||||
|
<span className={css.liveBadge}>
|
||||||
|
<img src={IcLiveShow} alt="LIVE" />
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
<img src={thumbnail} alt={title} />
|
||||||
|
</div>
|
||||||
|
<p className={css.title}>{title}</p>
|
||||||
|
</CardContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.card {
|
||||||
|
.size(@w: 344px, @h: 281px);
|
||||||
|
background-color: @COLOR_LIGHT_SKYBLUE;
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
transform: scale(0.9);
|
||||||
|
transition: all 0.15s ease-in-out;
|
||||||
|
|
||||||
|
.imageBox {
|
||||||
|
.size(@w: 100%, @h: 182px);
|
||||||
|
background-color: @COLOR_WHITE;
|
||||||
|
background-size: cover;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.liveBadge {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> img {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 182px);
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
.font(@fontFamily: @arialFont, @fontSize: 20px);
|
||||||
|
.elip(@clamp:1);
|
||||||
|
line-height: 1.2;
|
||||||
|
letter-spacing: -0.5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
border: 4px solid @PRIMARY_COLOR_RED;
|
||||||
|
background-color: @COLOR_WHITE;
|
||||||
|
box-shadow: 0 0 50px 0 rgba(11, 8, 8, 0.5);
|
||||||
|
.elip(@clamp:2);
|
||||||
|
line-height: 1.5;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
|
import VirtualGridList from "@enact/sandstone/VirtualList";
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
import ri from "@enact/ui/resolution";
|
||||||
|
|
||||||
|
import SearchShowCard from "./SearchShowCard/SearchShowCard";
|
||||||
|
import css from "./SearchShowResults.module.less";
|
||||||
|
|
||||||
|
const LIST_ITEM_CONF = {
|
||||||
|
ITEM_WIDTH: 344 * 2,
|
||||||
|
ITEM_HEIGHT: 281 * 2,
|
||||||
|
SPACING: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function SearchShowResults({ showDatas, showCount, ...rest }) {
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
const showData = showDatas[index];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchShowCard {...rest} key={showData.contentId} {...showData} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[showDatas]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className={css.container}>
|
||||||
|
{showDatas && (
|
||||||
|
<VirtualGridList
|
||||||
|
className={css.grid}
|
||||||
|
dataSize={showDatas.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemRenderer={renderItem}
|
||||||
|
itemSize={{
|
||||||
|
minWidth: ri.scale(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||||
|
minHeight: ri.scale(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||||
|
}}
|
||||||
|
spacing={ri.scale(LIST_ITEM_CONF.SPACING)}
|
||||||
|
scrollMode="translate"
|
||||||
|
horizontalScrollbar="hidden"
|
||||||
|
noScrollByWheel
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
@import "../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex();
|
||||||
|
margin: 30px 0 50px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
height: 281px;
|
||||||
|
overflow: unset;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React, { memo } from "react";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import css from "./SearchThemeCard.module.less";
|
||||||
|
|
||||||
|
const ThemeContainer = Spottable("div");
|
||||||
|
|
||||||
|
export default memo(function SearchThemeCard({
|
||||||
|
endTime,
|
||||||
|
keyword,
|
||||||
|
partnerLogo,
|
||||||
|
partnerName,
|
||||||
|
startTime,
|
||||||
|
title,
|
||||||
|
contentId,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<ThemeContainer className={css.card} {...rest}>
|
||||||
|
<h2 className={css.title}>{title}</h2>
|
||||||
|
<ul className={css.keywordWrap}>
|
||||||
|
{keyword &&
|
||||||
|
keyword.map((item, index) => (
|
||||||
|
<li key={index} className={css.keywordList}>
|
||||||
|
<span className={css.keyword}># {item}</span>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</ThemeContainer>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
@import "../../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.card {
|
||||||
|
.size(@w: 560px, @h: 140px);
|
||||||
|
background-image: url("../../../../../../assets/searchpanel/bg_srch_curation.png");
|
||||||
|
border: 2px solid #ccc;
|
||||||
|
overflow: hidden;
|
||||||
|
background-size: cover;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center top;
|
||||||
|
padding: 25px 20px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
.font(@fontFamily: @tahomaFontBold, @fontSize: 26px);
|
||||||
|
line-height: 1.31;
|
||||||
|
letter-spacing: -0.65px;
|
||||||
|
color: @COLOR_GRAY06;
|
||||||
|
font-weight: 900;
|
||||||
|
.elip(@clamp: 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.keywordWrap {
|
||||||
|
margin-top: 1px;
|
||||||
|
display: flex;
|
||||||
|
color: #c06;
|
||||||
|
.font(@fontFamily: @arialFontBold, @fontSize: 24px);
|
||||||
|
letter-spacing: -0.6px;
|
||||||
|
line-height: 1.67;
|
||||||
|
min-height: 26px;
|
||||||
|
|
||||||
|
.keywordList {
|
||||||
|
margin-right: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-within {
|
||||||
|
background-position: center bottom;
|
||||||
|
border: 4px solid @PRIMARY_COLOR_RED;
|
||||||
|
box-shadow: 0 0 50px 0 rgba(11, 8, 8, 0.5);
|
||||||
|
|
||||||
|
.title {
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keywordWrap {
|
||||||
|
color: @COLOR_WHITE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import React, { useCallback } from "react";
|
||||||
|
|
||||||
|
import { VirtualGridList } from "@enact/sandstone/VirtualList";
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
import ri from "@enact/ui/resolution";
|
||||||
|
|
||||||
|
import SearchThemeCard from "./SearchThemeCard/SearchThemeCard";
|
||||||
|
import css from "./SearchThemeResults.module.less";
|
||||||
|
|
||||||
|
const LIST_ITEM_CONF = {
|
||||||
|
ITEM_WIDTH: 560 * 2,
|
||||||
|
ITEM_HEIGHT: 140 * 2,
|
||||||
|
SPACING: 30 * 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
|
"div"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function SearchThemeResults({
|
||||||
|
themeDatas,
|
||||||
|
themeCount,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
const renderItem = useCallback(
|
||||||
|
({ index, ...rest }) => {
|
||||||
|
const themeData = themeDatas[index];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SearchThemeCard {...rest} key={themeData.contentId} {...themeData} />
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[themeDatas]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container className={css.container}>
|
||||||
|
{themeDatas && (
|
||||||
|
<VirtualGridList
|
||||||
|
className={css.grid}
|
||||||
|
dataSize={themeDatas.length}
|
||||||
|
direction="horizontal"
|
||||||
|
itemRenderer={renderItem}
|
||||||
|
itemSize={{
|
||||||
|
minWidth: ri.scale(LIST_ITEM_CONF.ITEM_WIDTH),
|
||||||
|
minHeight: ri.scale(LIST_ITEM_CONF.ITEM_HEIGHT),
|
||||||
|
}}
|
||||||
|
spacing={ri.scale(LIST_ITEM_CONF.SPACING)}
|
||||||
|
scrollMode="translate"
|
||||||
|
horizontalScrollbar="hidden"
|
||||||
|
noScrollByWheel
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
@import "../../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex();
|
||||||
|
margin: 30px 0 50px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid {
|
||||||
|
height: 141px;
|
||||||
|
overflow: unset;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
overflow: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user