merge from feature/gnb, TODO: tabLayout 구현

This commit is contained in:
hyunwoo93.cha
2024-01-25 21:24:04 +09:00
parent c919e0b130
commit cdd6a774b6
6 changed files with 229 additions and 87 deletions

View File

@@ -1,3 +1,4 @@
import { Job } from "@enact/core/util";
import { Marquee, MarqueeController } from "@enact/sandstone/Marquee"; import { Marquee, MarqueeController } from "@enact/sandstone/Marquee";
import Spottable from "@enact/spotlight/Spottable"; import Spottable from "@enact/spotlight/Spottable";
import { getTargetByDirectionFromElement } from "@enact/spotlight/src/target"; import { getTargetByDirectionFromElement } from "@enact/spotlight/src/target";
@@ -13,13 +14,36 @@ const TabItemBase = ({
expanded = false, expanded = false,
selected = false, selected = false,
index = 0, index = 0,
target,
panel,
deActivateTab, deActivateTab,
className, className,
onClick,
...rest ...rest
}) => { }) => {
const [focused, setFocused] = useState(false); const [focused, setFocused] = useState(false);
const itemRef = useRef(); 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 });
}
});
onClick({ index, target });
},
[target, index, onClick]
);
const _onFocus = useCallback(() => { const _onFocus = useCallback(() => {
setFocused(true); setFocused(true);
}, [index]); }, [index]);
@@ -64,6 +88,7 @@ const TabItemBase = ({
onKeyDown={onKeyDown} onKeyDown={onKeyDown}
onFocus={_onFocus} onFocus={_onFocus}
onBlur={_onBlur} onBlur={_onBlur}
onClick={_onClick}
spotlightDisabled={isDivider} spotlightDisabled={isDivider}
> >
{icons && <div className={css.icon}>{renderIcon()}</div>} {icons && <div className={css.icon}>{renderIcon()}</div>}

View File

@@ -8,7 +8,7 @@
&.focused { &.focused {
color: #ffffff; color: #eee;
background: linear-gradient(#cb1253, #e15ba1); background: linear-gradient(#cb1253, #e15ba1);
border-radius: 42px; border-radius: 42px;
width: 402px; width: 402px;

View File

@@ -9,13 +9,16 @@ import React, {
import classNames from "classnames"; import classNames from "classnames";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
//아이콘 import { panel_names } from "../../utils/Config";
import { Job } from "@enact/core/util"; import TabItem from "./TabItem";
import css from "./TabLayout.module.less";
//enact //enact
import Skinnable from "@enact/sandstone/Skinnable"; import Skinnable from "@enact/sandstone/Skinnable";
import Spotlight from "@enact/spotlight"; import Spotlight from "@enact/spotlight";
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator"; import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
import { Cancelable } from "@enact/ui/Cancelable"; import { Cancelable } from "@enact/ui/Cancelable";
//아이콘
import { Job } from "@enact/core/util";
//이미지 //이미지
import shoptimeFullIcon from "../../../assets/icons/ic-lnb-logo-shoptime@3x.png"; import shoptimeFullIcon from "../../../assets/icons/ic-lnb-logo-shoptime@3x.png";
@@ -29,9 +32,9 @@ import MyPageIcon from "./iconComponents/MyPageIcon";
import OnSaleIcon from "./iconComponents/OnSaleIcon"; import OnSaleIcon from "./iconComponents/OnSaleIcon";
import SearchIcon from "./iconComponents/SearchIcon"; import SearchIcon from "./iconComponents/SearchIcon";
import TrendingNowIcon from "./iconComponents/TrendingNowIcon"; import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
import TabItem from "./TabItem";
import css from "./TabLayout.module.less"; //이미지
import { panel_names } from "../../utils/Config"; import { resetPanels } from "../../features/panels/panelsSlice";
const Container = SpotlightContainerDecorator( const Container = SpotlightContainerDecorator(
{ enterTo: "default-element" }, { enterTo: "default-element" },
@@ -84,6 +87,9 @@ const ACTIVATED_MAIN = 1;
const ACTIVATED_SUB = 2; const ACTIVATED_SUB = 2;
const EXTRA_AREA = 3; const EXTRA_AREA = 3;
const MAIN_TITLE = 0;
const SUB_TITLE = 1;
const PANELS_HAS_TAB = [ const PANELS_HAS_TAB = [
panel_names.CART_PANEL, panel_names.CART_PANEL,
panel_names.CATEGORY_PANEL, panel_names.CATEGORY_PANEL,
@@ -104,91 +110,149 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const [tabFocused, setTabFocused] = useState([false, false, false]); //COLLABSED_MAIN, ACTIVATED_MAIN, ACTIVATED_SUB const [tabFocused, setTabFocused] = useState([false, false, false]); //COLLABSED_MAIN, ACTIVATED_MAIN, ACTIVATED_SUB
const panelSwitching = useRef(null); const panelSwitching = useRef(null);
const { cursorVisible } = useSelector((state) => state.common.appStatus); const { cursorVisible } = useSelector((state) => state.common.appStatus);
const titles = useSelector((state) => state.home.menuData); const data = useSelector((state) => state.home.menuData?.data);
console.log("titles", titles);
// const items = useSelector((state) => state.menu.items);
const menuItems = useMemo( const menuItems = useMemo(
() => [ () => [
{ {
title: titles[1],
icons: CategoryIcon, icons: CategoryIcon,
children: [ title: "",
{
title: "123123",
target: [],
},
],
},
{
title: titles[0],
icons: MyPageIcon,
children: [
{
title: "123123",
target: [],
},
],
},
{
title: titles[2],
icons: SearchIcon,
children: [
{
title: "12323232",
target: [],
},
],
},
{
title: titles[3],
icons: HomeIcon,
children: [
{
title: "43534543",
target: [],
},
],
},
{
title: titles[8],
icons: FeaturedBrandIcon,
children: [
{
title: "dsadasd",
target: [],
},
],
},
{
title: titles[4],
icons: OnSaleIcon,
children: [ children: [
{ {
title: "", title: "",
target: [], target: [{ name: panel_names.CATEGORY_PANEL }],
},
],
},
{
icons: MyPageIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.MY_PAGE_PANEL }],
},
],
},
{
icons: SearchIcon,
title: "",
children: [
{
title: "12323232",
target: [{ name: panel_names.SEARCH_PANEL }],
},
],
},
{
icons: HomeIcon,
title: "",
children: [
{
title: "43534543",
target: [{ name: panel_names.HOME_PANEL }],
},
],
},
{
icons: FeaturedBrandIcon,
title: "",
children: [
{
title: "dsadasd",
target: [{ name: panel_names.FEATURED_BRANDS_PANEL }],
},
],
},
{
icons: OnSaleIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.ON_SALE_PANEL }],
}, },
], ],
}, },
{ {
title: titles[5],
icons: TrendingNowIcon, icons: TrendingNowIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.TRENDING_NOW_PANEL }],
},
],
}, },
{ {
title: titles[6],
icons: HotPicksIcon, icons: HotPicksIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.HOT_PICKS_PANEL }],
},
],
}, },
{ {
title: titles[7],
icons: CartIcon, icons: CartIcon,
title: "",
children: [
{
title: "",
target: [{ name: panel_names.CART_PANEL }],
},
],
}, },
// 메뉴 추가 필요 20240112 chw //메뉴 추가 필요 20240112 chw
], ],
[mainExpanded] [data]
); );
const getMenuData = (type) => {
let result = [];
switch (type) {
case "gnb":
data?.gnb.map((item) => {
result.push(item.menuNm);
});
console.log("#result", result);
return result;
case "homeCategory":
return "123123";
case "msgInfos":
return result;
case "mypage":
return result;
case "shortCategory":
return result;
case "shortFeaturedBrands":
return result;
}
};
const dataDivide = () => {
if (data) {
// console.log("data", data);
// Object.keys(data).map((key) => {
// title = getMenuData(key);
// return title;
// });
const title = getMenuData("gnb");
// const subTitle = getMenuData(menu);
for (let i = 0; i < menuItems.length; i++) {
menuItems[i].title = title[i];
menuItems[i].children.title = title[i];
}
}
console.log("#menuItems", menuItems);
return menuItems;
};
const makeTabmenu = useCallback(() => { const makeTabmenu = useCallback(() => {
const t = []; const t = [];
@@ -203,11 +267,12 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
} }
return t; return t;
}, []); }, [data]);
useEffect(() => { useEffect(() => {
dataDivide();
setTabs(makeTabmenu()); setTabs(makeTabmenu());
}, []); }, [data]);
const deActivateTab = useCallback(() => { const deActivateTab = useCallback(() => {
setTabFocused([false, false, false, false]); setTabFocused([false, false, false, false]);
@@ -220,7 +285,6 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
switch (type) { switch (type) {
case COLLABSED_MAIN: case COLLABSED_MAIN:
case ACTIVATED_MAIN: { case ACTIVATED_MAIN: {
console.log("#tabs[mainSelectedIndex]", tabs[mainSelectedIndex]);
if (!cursorVisible) { if (!cursorVisible) {
const parent = event.target.parentNode; const parent = event.target.parentNode;
const children = parent.childNodes; const children = parent.childNodes;
@@ -288,22 +352,23 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
const handleNavigation = useCallback( const handleNavigation = useCallback(
({ index, target }) => { ({ index, target }) => {
console.log(index, target);
setMainSelectedIndex(index); setMainSelectedIndex(index);
if (target) { if (target) {
// dispatch(resetPanels(target)); dispatch(resetPanels(target));
deActivateTab(); deActivateTab();
// panelSwitching.current = true;
// panelSwitchingJob.start(panelSwitching);
} else if (cursorVisible) { } else if (cursorVisible) {
setMainExpanded(true); setMainExpanded(true);
} }
}, },
[cursorVisible, deActivateTab, dispatch] [deActivateTab, dispatch]
); );
const onClickSubItem = useCallback( const onClickSubItem = useCallback(
({ index, target }) => { ({ index, target }) => {
if (target) { if (target) {
// dispatch(resetPanels(target)); dispatch(resetPanels(target));
deActivateTab(); deActivateTab();
panelSwitching.current = true; panelSwitching.current = true;
// panelSwitchingJob.start(panelSwitching); // panelSwitchingJob.start(panelSwitching);
@@ -370,7 +435,7 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
} }
return ( return (
<> <div className={css.tabLayoutWrap}>
{/* collabsed Main */} {/* collabsed Main */}
<Container <Container
className={css.tabWrap} className={css.tabWrap}
@@ -409,11 +474,13 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
onBlur={onTabBlur(ACTIVATED_MAIN)} onBlur={onTabBlur(ACTIVATED_MAIN)}
onMouseLeave={onTabBlur(ACTIVATED_MAIN)} onMouseLeave={onTabBlur(ACTIVATED_MAIN)}
> >
<img <h1 className={classNames(css.logo, mainExpanded && css.expanded)}>
className={classNames(css.logo, mainExpanded && css.expanded)} <img
src={mainExpanded ? shoptimeFullIcon : shopTimeIcon} src={mainExpanded ? shoptimeFullIcon : shopTimeIcon}
alt="" alt=""
/> />
</h1>
{tabActivated && {tabActivated &&
tabs.map((item, index) => ( tabs.map((item, index) => (
<TabItem <TabItem
@@ -448,7 +515,6 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
<TabItem <TabItem
key={"tabitemSubmenu" + index} key={"tabitemSubmenu" + index}
onClick={onClickSubItem} onClick={onClickSubItem}
{...item}
expanded={true} expanded={true}
index={index} index={index}
isSubItem={true} isSubItem={true}
@@ -473,6 +539,6 @@ export default function TabLayout({ topPanelName, onTabActivated }) {
)} )}
</CancelableDiv> </CancelableDiv>
} }
</> </div>
); );
} }

View File

@@ -1,3 +1,11 @@
.tabLayoutWrap{
width:100%;
height:100%;
position:absolute;
left:0;
top:0;
display:flex;
}
.expandedRootContainer { .expandedRootContainer {
position: absolute; position: absolute;
display: flex; display: flex;
@@ -14,8 +22,11 @@
} }
.tabWrap { .tabWrap {
width: 120px;height:100%;
//position:fixed;
left:0;
top:0;
background-color: #222222; background-color: #222222;
width: 120px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -36,6 +47,7 @@
box-shadow: 8px 0 36px rgba(33, 33, 32, 0.08); box-shadow: 8px 0 36px rgba(33, 33, 32, 0.08);
padding-bottom: unset; padding-bottom: unset;
justify-content: flex-start; justify-content: flex-start;
left:402px;
} }
&.extraArea { &.extraArea {
flex-grow: 1; flex-grow: 1;
@@ -50,13 +62,21 @@
.logo { .logo {
width: 54px; width: 54px;
height: 54px; height: 54px;
margin:0 0 84px 42px;
margin-left: 42px; transition: width 0.5s ease;
margin-bottom: 84px; overflow:hidden;
&.expanded { &.expanded {
width: 234px; width: 234px;
height: 54px; height: 54px;
> img{
width:234px;
height:54px;
}
}
> img{
width:54px;
height:54px;
} }
} }

View File

@@ -73,6 +73,7 @@ export const homeSlice = createSlice({
state.termsData = action.payload; state.termsData = action.payload;
}, },
updateMenuData: (state, action) => { updateMenuData: (state, action) => {
//임시코드
state.menuData = action.payload; state.menuData = action.payload;
}, },
}, },

View File

@@ -1,4 +1,6 @@
import Panels from "@enact/sandstone/Panels"; import Panels from "@enact/sandstone/Panels";
import platform from "@enact/core/platform";
import React, { useCallback, useEffect, useMemo, useState } from "react"; import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { addPanels, popPanel } from "../../features/panels/panelsSlice"; import { addPanels, popPanel } from "../../features/panels/panelsSlice";
@@ -69,7 +71,7 @@ export default function MainView() {
return ( return (
<Component <Component
{...panel.panelInfo} panelInfo={panel.panelInfo}
spotlightId={panel.name} spotlightId={panel.name}
isTabActivated={tabActivated} isTabActivated={tabActivated}
/> />
@@ -110,6 +112,34 @@ export default function MainView() {
} }
}, [showLoadingPanel.show, isTermAgreed, dispatch]); }, [showLoadingPanel.show, isTermAgreed, dispatch]);
const cursorStateChange = useCallback(
(ev) => {
dispatch(
changeAppStatus({
cursorVisible: ev.visibility || ev.detail.visibility,
})
);
},
[dispatch]
);
useEffect(() => {
document.addEventListener("cursorStateChange", cursorStateChange, false);
if (platform.platformName !== "webos") {
//for debug
dispatch(changeAppStatus({ cursorVisible: !platform.touchscreen }));
} else {
dispatch(
changeAppStatus({
cursorVisible: window.cursorEvent && window.cursorEvent.visibility,
})
);
}
return () => {
document.removeEventListener("cursorStateChange", cursorStateChange);
};
}, []);
return ( return (
<> <>
<PreloadImage <PreloadImage