diff --git a/com.twin.app.shoptime/assets/searchpanel/ico_search_submit.png b/com.twin.app.shoptime/assets/searchpanel/ico_search_submit.png new file mode 100644 index 00000000..6b42144f Binary files /dev/null and b/com.twin.app.shoptime/assets/searchpanel/ico_search_submit.png differ diff --git a/com.twin.app.shoptime/assets/searchpanel/sch-arr-l-f.png b/com.twin.app.shoptime/assets/searchpanel/sch-arr-l-f.png new file mode 100644 index 00000000..476b3b2c Binary files /dev/null and b/com.twin.app.shoptime/assets/searchpanel/sch-arr-l-f.png differ diff --git a/com.twin.app.shoptime/assets/searchpanel/sch-arr-l.png b/com.twin.app.shoptime/assets/searchpanel/sch-arr-l.png new file mode 100644 index 00000000..a824e54e Binary files /dev/null and b/com.twin.app.shoptime/assets/searchpanel/sch-arr-l.png differ diff --git a/com.twin.app.shoptime/assets/searchpanel/sch-arr-r-f.png b/com.twin.app.shoptime/assets/searchpanel/sch-arr-r-f.png new file mode 100644 index 00000000..f0e7c5b4 Binary files /dev/null and b/com.twin.app.shoptime/assets/searchpanel/sch-arr-r-f.png differ diff --git a/com.twin.app.shoptime/assets/searchpanel/sch-arr-r.png b/com.twin.app.shoptime/assets/searchpanel/sch-arr-r.png new file mode 100644 index 00000000..b2e3571f Binary files /dev/null and b/com.twin.app.shoptime/assets/searchpanel/sch-arr-r.png differ diff --git a/com.twin.app.shoptime/src/components/TIconButton/TIconButton.jsx b/com.twin.app.shoptime/src/components/TIconButton/TIconButton.jsx new file mode 100644 index 00000000..078ef871 --- /dev/null +++ b/com.twin.app.shoptime/src/components/TIconButton/TIconButton.jsx @@ -0,0 +1,106 @@ +import React, { useCallback, useRef, useState } from "react"; +import css from "./TIconButton.module.less"; +import Spottable from "@enact/spotlight/Spottable"; +import classNames from "classnames"; +import { useDispatch } from "react-redux"; +import { Job } from "@enact/core/util"; +import * as Config from "../../utils/Config"; +import { popPanel, resetPanels } from "../../features/panels/panelsSlice"; + +const SpottableComponent = Spottable("div"); + +const SIZES = { tiny: "tiny", small: "small" }; +const ICON_TYPES = { + none: "none", + back: "back", + home: "home", + leftArrow: "leftArrow", + rightArrow: "rightArrow", +}; + +export default function TIconButton({ + className, + iconType = ICON_TYPES.none, + size = "normal", + color, + spotlightId = undefined, + children, + onClick, + spotlightDisabled, + disabled, + ...rest +}) { + const dispatch = useDispatch(); + + const [pressed, setPressed] = useState(false); + + const clearPressedJob = useRef( + new Job((func) => { + setPressed(false); + + setTimeout(func, Config.TBUTTON_PRESS_DELAY); + }, Config.TBUTTON_PRESS_DELAY) + ); + + const _onClick = useCallback( + (event) => { + if (disabled) { + event.stopPropagation(); + return; + } + + setPressed(true); + + clearPressedJob.current.start(() => { + if (onClick) { + onClick(event); + } + + switch (iconType) { + case ICON_TYPES.back: { + dispatch(popPanel()); + break; + } + + case ICON_TYPES.home: { + dispatch(resetPanels()); + break; + } + } + }); + }, + [dispatch, iconType, onClick, disabled] + ); + + const _onBlur = useCallback(() => { + setPressed(false); + + clearPressedJob.current.stop(); + }, []); + + const _onFocus = useCallback(() => {}, []); + + return ( + + {children} + + ); +} + +export { ICON_TYPES, SIZES }; diff --git a/com.twin.app.shoptime/src/components/TIconButton/TIconButton.module.less b/com.twin.app.shoptime/src/components/TIconButton/TIconButton.module.less new file mode 100644 index 00000000..333191f3 --- /dev/null +++ b/com.twin.app.shoptime/src/components/TIconButton/TIconButton.module.less @@ -0,0 +1,34 @@ +@import "../../style/CommonStyle.module.less"; +@import "../../style/utils.module.less"; + +.tIconButton { + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; + box-sizing: border-box; +} + +.leftArrow { + background-image: url("../../../assets/searchpanel/sch-arr-l.png"); + background-position: center top; + width: 47px; + height: 92px; + + &:focus-within { + background-position: center bottom; + transform: scale(1.2); + } +} + +.rightArrow { + background-image: url("../../../assets/searchpanel/sch-arr-r.png"); + background-position: center top; + width: 47px; + height: 92px; + + &:focus-within { + background-position: center bottom; + transform: scale(1.2); + } +} diff --git a/com.twin.app.shoptime/src/components/TIconButton/package.json b/com.twin.app.shoptime/src/components/TIconButton/package.json new file mode 100644 index 00000000..d4233145 --- /dev/null +++ b/com.twin.app.shoptime/src/components/TIconButton/package.json @@ -0,0 +1,3 @@ +{ + "main": "TIconButton.jsx" +} \ No newline at end of file diff --git a/com.twin.app.shoptime/src/components/TInput/TInput.jsx b/com.twin.app.shoptime/src/components/TInput/TInput.jsx index c6c712a7..02a9db84 100644 --- a/com.twin.app.shoptime/src/components/TInput/TInput.jsx +++ b/com.twin.app.shoptime/src/components/TInput/TInput.jsx @@ -1,8 +1,13 @@ -import classNames from "classnames"; -import React from "react"; +import React, { forwardRef, useCallback, useRef, useEffect } from "react"; import css from "./TInput.module.less"; import { InputField } from "@enact/sandstone/Input"; -import { $L } from "../../utils/helperMethods"; +import Spottable from "@enact/spotlight/Spottable"; +import classNames from "classnames"; +import { SpotlightContainerDecorator } from "@enact/spotlight/SpotlightContainerDecorator"; + +const Container = SpotlightContainerDecorator("div"); + +const SpottableInputIcon = Spottable("div"); const KINDS = { withIcon: "withIcon" }; const ICONS = { search: "search" }; @@ -10,27 +15,33 @@ const BORDER = { none: "none" }; const COLOR = { transparent: "transparent" }; export default function TInput({ - kind = "", - icon = null, - border = null, - color = null, - className = null, + kind, + icon, + border, + color, + className, spotlightDisabled, ...rest }) { + const handleIconClick = useCallback(() => {}, []); + return ( - + + {kind === "withIcon" && ( + )} - spotlightDisabled={spotlightDisabled} - /> + ); } diff --git a/com.twin.app.shoptime/src/components/TInput/TInput.module.less b/com.twin.app.shoptime/src/components/TInput/TInput.module.less index a91afd68..9d32e8c0 100644 --- a/com.twin.app.shoptime/src/components/TInput/TInput.module.less +++ b/com.twin.app.shoptime/src/components/TInput/TInput.module.less @@ -1,29 +1,62 @@ @import "../../style/CommonStyle.module.less"; @import "../../style/utils.module.less"; -.input { - margin-right: 0; - margin-left: 0; - height: 100px !important; - padding: 20px 40px 20px 50px !important; - border-radius: 50px; - border: 5px solid #ccc; - background-color: #fff !important; +.container { + width: fit-content; + height: fit-content; + position: relative; - &:focus-within, - &:hover { - box-shadow: 0 0 0 2px #fefefe inset; - border: 5px solid @PRIMARY_COLOR_RED; + .input { + margin-right: 0; + margin-left: 0; + height: 100px !important; + padding: 20px 40px 20px 50px !important; + border-radius: 50px; + border: 5px solid #ccc; + background-color: #fff !important; + width: 100% !important; + + &:focus-within, + &:hover { + box-shadow: 0 0 0 2px #fefefe inset; + border: 5px solid @PRIMARY_COLOR_RED; + } + + > div { + display: none; + } + + > input { + font-family: @baseFont; + color: @COLOR_GRAY07 !important; + height: inherit !important; + line-height: inherit !important; + } } - > div { - display: none; + .withIcon { + > div { + display: none; + } } - > input { - font-family: @baseFont; - color: @COLOR_GRAY07 !important; - height: inherit !important; - line-height: inherit !important; + .search { + position: absolute; + background-repeat: no-repeat; + background-position: center top; + width: 41px; + height: 41px; + top: 50%; + right: 30px; + transform: translateY(-50%); + background-image: url("../../../assets/searchpanel/ico_search_submit.png"); + + &:focus-within, + &:hover { + width: 43px; + height: 43px; + transform: translateY(-50%) scale(1.1); + background-position: center bottom; + } } } diff --git a/com.twin.app.shoptime/src/utils/Config.js b/com.twin.app.shoptime/src/utils/Config.js index a357b1c3..313c8215 100644 --- a/com.twin.app.shoptime/src/utils/Config.js +++ b/com.twin.app.shoptime/src/utils/Config.js @@ -25,3 +25,6 @@ export const panel_names = { // debug DEBUG_PANEL: "debugpanel", }; + +//button +export const TBUTTON_PRESS_DELAY = 100; diff --git a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx index 098a6140..187f7b28 100644 --- a/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx +++ b/com.twin.app.shoptime/src/views/OnSalePanel/OnSalePanel.jsx @@ -12,7 +12,9 @@ import css from "./OnSalePanel.module.less"; export default function OnSalePanel() { const dispatch = useDispatch(); - const categoryInfos = useSelector((state) => state.onSale.onSaleData.categoryInfos); + const categoryInfos = useSelector( + (state) => state.onSale.onSaleData.categoryInfos + ); const saleInfos = useSelector((state) => state.onSale.onSaleData.saleInfos); const [currentLgCatCd, setCurrentLgCatCd] = useState(); @@ -34,7 +36,9 @@ export default function OnSalePanel() { useEffect(() => { if (currentLgCatCd) { - dispatch(getOnSaleInfo({ categoryIncFlag: "Y", lgCatCd: currentLgCatCd })); + dispatch( + getOnSaleInfo({ categoryIncFlag: "Y", lgCatCd: currentLgCatCd }) + ); } }, [currentLgCatCd]); @@ -56,7 +60,12 @@ export default function OnSalePanel() { return ( {saleProductInfos.map((saleProduct) => { - return ; + return ( + + ); })} ); diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx index 244a1fcd..35f91383 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.jsx @@ -1,16 +1,26 @@ -import React, { useCallback, useEffect, useState } from "react"; +import React, { useCallback, useEffect, useState, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; -import TInput from "../../components/TInput/TInput"; +import TInput, { KINDS, ICONS } from "../../components/TInput/TInput"; import TPanel from "../../components/TPanel/TPanel"; import TButton from "../../components/TButton/TButton"; import { $L } from "../../utils/helperMethods"; import css from "./SearchPanel.module.less"; +import TIconButton, { + ICON_TYPES, + SIZES, +} from "../../components/TIconButton/TIconButton"; +import classNames from "classnames"; + +import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; + +const Container = SpotlightContainerDecorator( + { enterTo: "last-focused" }, + "div" +); const ITEMS_PER_PAGE = 9; export default function SearchPanel() { - const dispatch = useDispatch(); - const recommandedKeywords = useSelector( (state) => state.myPage.recommandedKeywordData.data?.keywords ); @@ -35,25 +45,39 @@ export default function SearchPanel() { setCurrentPage((prev) => (prev > 1 ? prev - 1 : prev)); }, [currentPage]); + const hasPrevPage = currentPage > 1; + const hasNextPage = + currentPage * ITEMS_PER_PAGE < recommandedKeywords?.length; + return ( - -
+ + {hasPrevPage && ( + + )} + {paginatedKeywords.map((keyword, index) => ( -
{keyword.keywd}
+ + {keyword.keywd} + ))} -
-
- - PREV - - + {hasNextPage && ( + = recommandedKeywords?.length} - > - NEXT - -
+ /> + )}
); } diff --git a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.module.less b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.module.less index 988aa7b9..07c4846f 100644 --- a/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.module.less +++ b/com.twin.app.shoptime/src/views/SearchPanel/SearchPanel.module.less @@ -5,5 +5,60 @@ background-color: @BG_COLOR_01; width: 100%; height: 100%; - .flex(@direction: row); + + > section { + display: flex; + justify-content: center; + flex-direction: column; + } + + .input { + width: 880px; + margin: 0 auto 180px; + } + + .arrow { + position: absolute; + top: 59%; + } + + .arrowLeft { + left: 60px; + } + + .arrowRight { + right: 60px; + } + + .keywordsGrid { + display: grid; + grid-template-columns: repeat(3, 1fr); + grid-gap: 80px; + width: 100%; + place-items: center; + padding: 0 233px; + + .keywordBox { + width: 390px; + height: 97px; + border-radius: 10px; + box-shadow: 0 4px 8px 0 rgba(2, 3, 3, 0.2); + border: 1px solid #999; + background-color: #f5f5f5; + color: #333; + font-family: @baseFontBold; + font-size: 40px; + + > div { + overflow: unset; + } + + &:focus-within { + box-shadow: 0 0 50px 0 rgba(11, 8, 8, 0.5); + border: 4px solid #c70850; + color: #c70850; + background-color: #f5f5f5; + } + } + } }