subDepth icon 추가 및 tabLayout css 수정

This commit is contained in:
고동영
2024-01-31 15:59:46 +09:00
parent 8a408ff5aa
commit b2e4b63138
18 changed files with 322 additions and 133 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 794 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 571 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

View File

@@ -1,10 +1,13 @@
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import classNames from "classnames";
import compose from "ramda/src/compose";
import { Job } from "@enact/core/util";
import { Marquee, MarqueeController } from "@enact/sandstone/Marquee";
import Spottable from "@enact/spotlight/Spottable";
import { getTargetByDirectionFromElement } from "@enact/spotlight/src/target";
import classNames from "classnames";
import compose from "ramda/src/compose";
import { useCallback, useMemo, useRef, useState } from "react";
import css from "./TabItem.module.less";
const SpottableComponent = Spottable("div");
@@ -19,42 +22,52 @@ const TabItemBase = ({
deActivateTab,
className,
onClick,
mainExpandend,
lgCatCd,
isSubItem,
subTitle,
showSubTab = false,
...rest
}) => {
const [focused, setFocused] = useState(false);
// const [subFocused , setSubFocused] = useState(false)
const [pressed, setPressed] = useState(false);
const itemRef = useRef();
const clearPressedJob = useRef(
new Job((func) => {
// setPressed(false);
setTimeout(func, 100);
}, 100)
);
const _onClick = useCallback(
(ev) => {
// if(ev?.target?.nodeName === 'IMG'){
// return;
// }
clearPressedJob.current.start(() => {
if (onClick) {
onClick({ index, target });
}
});
setPressed(true);
onClick({ index, target });
},
[target, index, onClick]
[target, index, onClick, isSubItem]
);
useEffect(() => {}, [pressed]);
const _onFocus = useCallback(() => {
setFocused(true);
}, [index]);
const _onBlur = useCallback(() => {
setFocused(false);
}, []);
}, [focused]);
const isDivider = useMemo(() => {
return !title;
}, []);
const onKeyDown = useCallback(
(event) => {
if (event.key === "ArrowRight") {
@@ -69,14 +82,27 @@ const TabItemBase = ({
},
[deActivateTab]
);
const renderIcon = useCallback(() => {
if (icons) {
const Component = icons;
return <Component iconType={focused ? "expanded" : "normal"} />;
return (
<Component
iconType={
focused
? "focused"
: selected
? "selected"
: expanded
? "expanded"
: "normal"
}
/>
);
} else {
return null;
}
}, [focused, selected, expanded]);
}, [focused, expanded]);
delete rest.hasChildren;
delete rest.getChildren;
@@ -85,8 +111,11 @@ const TabItemBase = ({
ref={itemRef}
className={classNames(
css.tabItem,
focused && css.focused
//!isDivider && selected && css.selected
focused && css.focused,
pressed && css.pressed,
isSubItem && css.subDepth,
pressed && css.arrow,
!isDivider && selected && css.selected
)}
onKeyDown={onKeyDown}
onFocus={_onFocus}
@@ -94,13 +123,21 @@ const TabItemBase = ({
onClick={_onClick}
spotlightDisabled={isDivider}
>
{icons && <div className={css.icon}>{renderIcon()}</div>}
<div className={classNames(css.layout, focused && css.focused)}>
{icons && <div className={css.icon}>{renderIcon()}</div>}
<div className={classNames(isSubItem && css.subWrap)}>
<span className={classNames(css[`category-icon-${lgCatCd}`])} />
{expanded && title && (
<Marquee marqueeOn={"focus"} className={classNames(css.text)}>
{title}
</Marquee>
)}
{expanded && (
<Marquee
marqueeOn={"focus"}
className={classNames(css.text, isSubItem && css.subItem)}
>
{title}
</Marquee>
)}
</div>
</div>
</SpottableComponent>
);
};

View File

@@ -1,25 +1,80 @@
@import "../../style/utils.module.less";
@import "../../style/CommonStyle.module.less";
@ICON_SIZE: 48px;
.tabItem{
padding: 18px 12px 18px 42px;
font-size: 36px;
display: flex;
color: #606060;
align-items: center;
height: 84px;
padding-left: 42px;
padding-right: 24px;
&.focused {
color: #eee;
background: linear-gradient(to right, #cb1253, #e15ba1);
border-radius: 42px;
width: 402px;
z-index: 1;
margin-left: 30px;
position:relative;
> div{
margin-left:-30px;
}
&.pressed {
color: #eee;
background: linear-gradient(#cb1253, #e15ba1);
background: linear-gradient(to right, #cb1253, #e15ba1);
border-radius: 42px;
width: 402px;
z-index: 1;
margin-left: 30px;
position:relative;
}
&.selected{
// margin-left:0;
}
}
&.arrow, &.selected {
&::after {
content: "";
.size(@w:36px, @h:36px);
.position(@position: absolute, @top: 24px, @right: 18px);
background-image: url('../../../assets/icons/ic-lnb-right-arrow.png');
background-size: 36px 36px;
}
}
&.selected {
color: #eee;
}
&.subDepth{
width: 386px;
height: 78px;
margin-left: 0;
&.focused {
background: rgba(255, 255, 255, .1);
border-radius: 0px;
border-right: 6px solid #c70850;
> div {
padding-left: 30px;
}}}
.icon {
position: relative;
min-width: @ICON_SIZE;
height: @ICON_SIZE;
> img {
position: absolute;
top: 50%;
@@ -39,15 +94,107 @@
}
.text {
width: 100%;
line-height: 36px;
padding-left: 18px;
padding-top: 6px;
flex-grow: 1;
flex-shrink: 1;
overflow: hidden;
line-height: 1.2;
padding-left: 11px;
.font(@fontFamily:@baseFontBold, @fontSize:36px);
&.subItem {
.font (@fontFamily:@baseFontBold, @fontSize:30px);
width: 245px;
}
}
.subWrap{
.flex();
span {
.size(@w: 40px, @h:40px);
background-size: cover;
&.category-icon-1017 {
// LG Electronics
background-image: url("../../../assets/category/ic-category-lgelectronics-nor@3x.png");
}
// Garden and Outdoors
&.category-icon-1008 {
background-image: url("../../../assets/icons/ic-category-garden-nor.png");
}
// Fashion
&.category-icon-1000 {
background-image: url("../../../assets/icons/ic-category-fashion-nor.png");
}
// Beauty
&.category-icon-1003 {
background-image: url("../../../assets/icons/ic-category-beauty-nor.png");
}
// Jewelry
&.category-icon-1004 {
background-image: url("../../../assets/icons/ic-category-jewelry-nor.png");
}
// Home
&.category-icon-1006 {
background-image: url("../../../assets/icons/ic-category-home-nor.png");
}
// Kitchen & Food
&.category-icon-1007 {
background-image: url("../../../assets/icons/ic-category-kitchen-nor.png");
}
// Accessories
&.category-icon-1014 {
background-image: url("../../../assets/icons/ic-category-accessories-nor.png");
}
// Heaclth & Fitness
&.category-icon-1009 {
background-image: url("../../../assets/icons/ic-category-health-nor.png");
}
// Entertainment
&.category-icon-1012 {
background-image: url("../../../assets/icons/ic-category-enter-nor.png");
}
// Crafts & Sewing
&.category-icon-1011 {
background-image: url("../../../assets/icons/ic-category-cw-nor.png");
}
// Electronics
&.category-icon-1010 {
background-image: url("../../../assets/icons/ic-category-electronics-nor.png");
}
// Clearance
&.category-icon-1013 {
background-image: url("../../../assets/icons/ic-category-clearance-nor.png");
}
}
}
.layout {
display: flex;
&.focused, &.selected {
// margin-left: -30px;
}
}
.marqueeWrap {
width: 100%;
}

View File

@@ -9,20 +9,19 @@ import React, {
import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux";
import { panel_names } from "../../utils/Config";
import TabItem from "./TabItem";
import css from "./TabLayout.module.less";
//아이콘
import { Job } from "@enact/core/util";
//enact
import Skinnable from "@enact/sandstone/Skinnable";
import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { Cancelable } from "@enact/ui/Cancelable";
//아이콘
import { Job } from "@enact/core/util";
//이미지
import shoptimeFullIcon from "../../../assets/icons/ic-lnb-logo-shoptime@3x.png";
import shopTimeIcon from "../../../assets/icons/ic-lnb-shoptime-symbol@3x.png";
import { resetPanels } from "../../features/panels/panelsSlice";
import { panel_names } from "../../utils/Config";
import CartIcon from "./iconComponents/CartIcon";
import CategoryIcon from "./iconComponents/CategoryIcon";
import FeaturedBrandIcon from "./iconComponents/FeaturedBrandIcon";
@@ -32,9 +31,8 @@ import MyPageIcon from "./iconComponents/MyPageIcon";
import OnSaleIcon from "./iconComponents/OnSaleIcon";
import SearchIcon from "./iconComponents/SearchIcon";
import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
//이미지
import { resetPanels } from "../../features/panels/panelsSlice";
import TabItem from "./TabItem";
import css from "./TabLayout.module.less";
const Container = SpotlightContainerDecorator(
{ enterTo: "default-element" },
@@ -52,9 +50,10 @@ const CancelableDiv = Cancelable(
);
class TabMenuItem {
constructor(icons = "", title = "", target, children = []) {
constructor(icons = "", title = "", id, target, children = []) {
this.icons = icons;
this.title = title;
this.id = id;
this.target = target;
this.children = []; //TabMenuItem
if (children && children.length > 0) {
@@ -62,6 +61,7 @@ class TabMenuItem {
const tabmenu = new TabMenuItem(
children[i].icons,
children[i].title,
children[i].id,
children[i].target,
children[i].children
);
@@ -110,91 +110,80 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const dispatch = useDispatch();
const [mainExpanded, setMainExpanded] = useState(false);
const [mainSelectedIndex, setMainSelectedIndex] = useState(-1);
const [focused, setFocused] = useState(false);
const [tabs, setTabs] = useState([]);
const [tabFocused, setTabFocused] = useState([false, false, false]); //COLLABSED_MAIN, ACTIVATED_MAIN, ACTIVATED_SUB
const panelSwitching = useRef(null);
const { cursorVisible } = useSelector((state) => state.common.appStatus);
const data = useSelector((state) => state.home.menuData?.data);
const panels = useSelector((state) => state.panels.panels);
const menuItems = useMemo(
() => [
const menuItems = useMemo(() => {
return [
{
icons: CategoryIcon,
title: "",
children: [],
},
{
icons: MyPageIcon,
title: "",
children: [],
},
{
icons: SearchIcon,
title: "",
target: [{ name: panel_names.SEARCH_PANEL }],
},
{
icons: HomeIcon,
title: "",
target: [{ name: panel_names.HOME_PANEL }],
},
{
icons: FeaturedBrandIcon,
title: "",
children: [],
},
{
icons: OnSaleIcon,
title: "",
target: [{ name: panel_names.ON_SALE_PANEL }],
},
{
icons: TrendingNowIcon,
title: "",
target: [{ name: panel_names.TRENDING_NOW_PANEL }],
},
{
icons: HotPicksIcon,
title: "",
target: [{ name: panel_names.HOT_PICKS_PANEL }],
},
{
icons: CartIcon,
title: "",
target: [{ name: panel_names.CART_PANEL }],
},
//메뉴 추가 필요 20240112 chw
],
[data]
);
];
}, []);
const getMenuData = (type) => {
let result = [];
switch (type) {
case "Category":
data?.homeCategory.map((item) => {
result.push(item.lgCatNm);
});
return result;
result = data?.homeCategory.map((item) => ({
id: item.lgCatCd,
title: item.lgCatNm,
}));
break;
case "GNB":
data?.gnb.map((item) => {
result.push(item.menuNm);
});
return result;
result = data?.gnb.map((item) => ({
title: item.menuNm,
}));
break;
case "Featured Brands":
data?.shortFeaturedBrands.map((item) => {
result.push(item.patncLogoPath);
});
return result;
result = data?.shortFeaturedBrands.map((item) => ({
title: item.patncLogoPath,
}));
break;
case "My Page":
data?.mypage.map((item) => {
result.push(item.menuNm);
});
return result;
result = data?.mypage.map((item) => ({
title: item.menuNm,
}));
break;
}
return null;
return result;
};
const dataDivide = useCallback(() => {
@@ -216,22 +205,20 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
Cart: 8,
};
return order[a] - order[b];
return order[a.title] - order[b.title];
});
for (let i = 0; i < mainTitle.length; i++) {
menuItems[i].title = mainTitle[i];
}
for (let j = 0; j < keys.length; j++) {
const currentKey = keys[j];
const subTitle = getMenuData(currentKey);
const subData = getMenuData(currentKey);
if (subTitle && subTitle.length > 0) {
if (subData && subData.length > 0) {
for (let i = 0; i < mainTitle.length; i++) {
if (mainTitle[i] === currentKey) {
menuItems[i].children = subTitle.map((title) => ({
title,
menuItems[i].title = mainTitle[i].title;
if (mainTitle[i].title === currentKey) {
menuItems[i].children = subData.map((subItem) => ({
id: subItem.id,
title: subItem.title,
}));
}
}
@@ -247,6 +234,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const tabmenu = new TabMenuItem(
menuItems[i].icons,
menuItems[i].title,
menuItems[i].id,
menuItems[i].target,
menuItems[i].children
);
@@ -287,7 +275,8 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
break;
}
case ACTIVATED_SUB: {
setMainExpanded(false);
if (cursorVisible) {
}
break;
}
case EXTRA_AREA: {
@@ -303,7 +292,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
return prev;
});
},
[cursorVisible, deActivateTab]
[cursorVisible, deActivateTab, focused]
);
const onTabBlur = useCallback(
@@ -337,6 +326,14 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
[cursorVisible]
);
const onFocus = () => {
setFocused(true);
};
const onBlur = () => {
setFocused(false);
};
const handleNavigation = useCallback(
({ index, target }) => {
setMainSelectedIndex(index);
@@ -355,10 +352,9 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const onClickSubItem = useCallback(
({ index, target }) => {
if (target) {
dispatch(resetPanels(target));
deActivateTab();
panelSwitching.current = true;
// panelSwitchingJob.start(panelSwitching);
panelSwitchingJob.start(panelSwitching);
}
},
[dispatch, deActivateTab]
@@ -416,27 +412,24 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
}, [tabActivated, showTab]);
useEffect(() => {}, [showSubTab, mainSelectedIndex]);
if (!showTab) {
return null;
}
return (
<div className={classNames(css.tabLayoutWrap, !tabActivated && css.hide)}>
<div className={css.tabLayoutWrap}>
{/* collabsed Main */}
<Container
className={css.tabWrap}
className={classNames(css.tabWrap, css.basicLayout)}
onFocus={onTabHasFocus(COLLABSED_MAIN)}
onMouseOver={onTabHasFocus(COLLABSED_MAIN)}
onBlur={onTabBlur(COLLABSED_MAIN)}
onMouseLeave={onTabBlur(COLLABSED_MAIN)}
>
<img className={css.logo} src={shopTimeIcon} alt="" />
<img src={shopTimeIcon} alt="" />
{tabs.map((item, index) => (
<TabItem
key={"tabitem" + index}
expanded={false}
selected={mainSelectedIndex === index}
index={index}
onClick={handleNavigation}
icons={item.icons}
@@ -455,29 +448,35 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
>
{/* expanded Main */}
<MainContainer
className={classNames(css.tabWrap, mainExpanded && css.expanded)}
className={classNames(
css.tabWrap,
mainExpanded && css.expanded,
css.basicLayout
)}
onFocus={onTabHasFocus(ACTIVATED_MAIN)}
onMouseOver={onTabHasFocus(COLLABSED_MAIN)}
onBlur={onTabBlur(ACTIVATED_MAIN)}
onMouseLeave={onTabBlur(ACTIVATED_MAIN)}
>
<h1 className={classNames(css.logo, mainExpanded && css.expanded)}>
<img
src={mainExpanded ? shoptimeFullIcon : shopTimeIcon}
alt=""
/>
</h1>
<img src={mainExpanded ? shoptimeFullIcon : shopTimeIcon} alt="" />
{tabActivated &&
tabs.map((item, index) => (
<TabItem
{...item}
onFocus={onFocus}
onBlur={onBlur}
key={"tabitemExpanded" + index}
onClick={handleNavigation}
deActivateTab={deActivateTab}
icons={item.icons}
expanded={mainExpanded}
selected={mainSelectedIndex === index}
selected={
(panels.length === 0 && index === 0) ||
(Array.isArray(item.target) &&
item.target[0]?.name &&
panels[0]?.name === item.target[0]?.name)
}
title={item.title}
index={index}
/>
@@ -498,7 +497,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
onMouseLeave={onTabBlur(ACTIVATED_SUB)}
>
{showSubTab &&
tabs[mainSelectedIndex].children.map((item, index) => {
tabs[mainSelectedIndex]?.children.map((item, index) => {
return (
<TabItem
key={"tabitemSubmenu" + index}
@@ -506,9 +505,10 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
expanded={true}
index={index}
isSubItem={true}
mainExpanded={mainExpanded}
showSubTab={showSubTab}
deActivateTab={deActivateTab}
title={item.title}
lgCatCd={item.id}
/>
);
})}

View File

@@ -1,3 +1,6 @@
@import "../../style/utils.module.less";
@import "../../style/CommonStyle.module.less";
.tabLayoutWrap {
width: 100%;
height: 100%;
@@ -5,6 +8,7 @@
left: 0;
top: 0;
display: flex;
&.hide {
width: auto;
}
@@ -18,40 +22,55 @@
left: 0;
z-index: 1;
&.hide {
width: auto;
z-index: 0;
}
}
.tabWrap {
width: 120px;
height: 100%;
//position:fixed;
left: 0;
top: 0;
background-color: #222222;
display: flex;
flex-direction: column;
justify-content: center;
// padding-top: 104px;
// padding-bottom: 104px;
z-index: 1;
flex-grow: 0;
transition: width 0.5s ease;
> img {
width: 54px;
height: 54px;
margin: -40px 24px 84px 42px
}
&.expanded {
width: 402px;
> img {
width: 234px;
height: 54px;
}
}
&.secondDepthLayout {
width: 386px;
height: calc(100%);
opacity: 0.95;
box-shadow: 8px 0 36px rgba(33, 33, 32, 0.08);
padding-bottom: unset;
justify-content: flex-start;
left: 402px;
padding-top: 71px;
z-index: 0;
justify-content: flex-start;
}
&.extraArea {
flex-grow: 1;
@@ -61,25 +80,9 @@
&.hide {
width: 0;
}
}
.logo {
width: 54px;
height: 54px;
margin: 0 0 84px 42px;
transition: width 0.5s ease;
overflow: hidden;
&.expanded {
width: 234px;
height: 54px;
> img {
width: 234px;
height: 54px;
}
}
> img {
width: 54px;
height: 54px;
}
}

View File

@@ -3,7 +3,9 @@ export const convertThemeColor = (iconType) => {
const theme = {
light: {
normal: "#353535",
expanded: "#FEFEFE",
expanded: "#353535",
selected: "#FEFEFE",
focused: "#FEFEFE",
},
};