ONSALE, FEATURED BRANDS
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -1,3 +1,71 @@
|
|||||||
.app {
|
/* Reset */
|
||||||
/* styles can be put here */
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: #1a1a1a;
|
||||||
|
}
|
||||||
|
body,
|
||||||
|
div,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
table,
|
||||||
|
th,
|
||||||
|
td,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
li,
|
||||||
|
dl,
|
||||||
|
dt,
|
||||||
|
dd,
|
||||||
|
p,
|
||||||
|
form,
|
||||||
|
input,
|
||||||
|
fieldset {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6 {
|
||||||
|
font-size: 100%;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
details,
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
hgroup,
|
||||||
|
menu,
|
||||||
|
nav,
|
||||||
|
section,
|
||||||
|
header {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: none;
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,12 @@ export const URLS = {
|
|||||||
|
|
||||||
//home controller
|
//home controller
|
||||||
GET_HOME_TERMS: "/lgsp/v1/home/terms.lge",
|
GET_HOME_TERMS: "/lgsp/v1/home/terms.lge",
|
||||||
GET_HOME_MENU: "/lgsp/v1/home/menu.lge",
|
|
||||||
|
//brand-controller
|
||||||
|
GET_BRAND_LIST: "/lgsp/v1/brand/info.lge",
|
||||||
|
GET_BRAND_LAYOUT_INFO: "/lgsp/v1/brand/shelf.lge",
|
||||||
|
GET_BRAND_LIVE_CHANNEL_INFO: "/lgsp/v1/brand/live.lge",
|
||||||
|
GET_BRAND_TODAYS_DEALS: "/lgsp/v1/brand/tsv.lge",
|
||||||
|
|
||||||
//on-sale controller
|
//on-sale controller
|
||||||
GET_ON_SALE_INFO: "/lgsp/v1/onsale/onsale.lge",
|
GET_ON_SALE_INFO: "/lgsp/v1/onsale/onsale.lge",
|
||||||
|
|||||||
@@ -8,8 +8,16 @@ export async function getAuthenticationCode() {
|
|||||||
|
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error : ", error);
|
const { response } = error;
|
||||||
throw error;
|
|
||||||
|
if (response) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
const statusText = response.statusText;
|
||||||
|
|
||||||
|
console.error(`${statusCode} Error, ${statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
96
com.twin.app.shoptime/src/api/featuredBrands.js
Normal file
96
com.twin.app.shoptime/src/api/featuredBrands.js
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import { URLS } from "./apiConfig";
|
||||||
|
import api from "./axiosConfig";
|
||||||
|
|
||||||
|
// Featured Brands 정보 조회 IF-LGSP-304
|
||||||
|
export async function getBrandList() {
|
||||||
|
try {
|
||||||
|
const response = await api.get(URLS.GET_BRAND_LIST);
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error) {
|
||||||
|
const { response } = error;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
const statusText = response.statusText;
|
||||||
|
|
||||||
|
console.error(`${statusCode} Error, ${statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Featured Brands LAYOUT (shelf) 정보 조회 IF-LGSP-305
|
||||||
|
export async function getBrandLayoutInfo(props) {
|
||||||
|
const { patnrId } = props;
|
||||||
|
try {
|
||||||
|
const response = await api.get(URLS.GET_BRAND_LAYOUT_INFO, {
|
||||||
|
params: {
|
||||||
|
patnrId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error) {
|
||||||
|
const { response } = error;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
const statusText = response.statusText;
|
||||||
|
|
||||||
|
console.error(`${statusCode} Error, ${statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Featured Brands Live 채널 정보 조회 IF-LGSP-306
|
||||||
|
export async function getBrandLiveChannelInfo(props) {
|
||||||
|
const { patnrId } = props;
|
||||||
|
try {
|
||||||
|
const response = await api.get(URLS.GET_BRAND_LIVE_CHANNEL_INFO, {
|
||||||
|
params: {
|
||||||
|
patnrId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error) {
|
||||||
|
const { response } = error;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
const statusText = response.statusText;
|
||||||
|
|
||||||
|
console.error(`${statusCode} Error, ${statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Featured Brands Today's deals 정보 조회 IF-LGSP-307
|
||||||
|
export async function getBrandTSVInfo(props) {
|
||||||
|
const { patnrId } = props;
|
||||||
|
try {
|
||||||
|
const response = await api.get(URLS.GET_BRAND_TODAYS_DEALS, {
|
||||||
|
params: {
|
||||||
|
patnrId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data.data;
|
||||||
|
} catch (error) {
|
||||||
|
const { response } = error;
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
const statusCode = response.status;
|
||||||
|
const statusText = response.statusText;
|
||||||
|
|
||||||
|
console.error(`${statusCode} Error, ${statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw new Error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,41 @@
|
|||||||
import Spotlight from "@enact/spotlight";
|
|
||||||
import classNames from "classnames";
|
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
useMemo,
|
useMemo,
|
||||||
useRef,
|
useRef,
|
||||||
useState,
|
useState,
|
||||||
} from "react";
|
} from 'react';
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
|
||||||
import TabItem from "./TabItem";
|
import classNames from 'classnames';
|
||||||
import css from "./TabLayout.module.less";
|
import {
|
||||||
//enact
|
useDispatch,
|
||||||
import Skinnable from "@enact/sandstone/Skinnable";
|
useSelector,
|
||||||
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
} from 'react-redux';
|
||||||
import { Cancelable } from "@enact/ui/Cancelable";
|
|
||||||
//아이콘
|
//아이콘
|
||||||
import { Job } from "@enact/core/util";
|
import { Job } from '@enact/core/util';
|
||||||
import CartIcon from "./iconComponents/CartIcon";
|
//enact
|
||||||
import CategoryIcon from "./iconComponents/CategoryIcon";
|
import Skinnable from '@enact/sandstone/Skinnable';
|
||||||
import FeaturedBrandIcon from "./iconComponents/FeaturedBrandIcon";
|
import Spotlight from '@enact/spotlight';
|
||||||
import HomeIcon from "./iconComponents/HomeIcon";
|
import SpotlightContainerDecorator
|
||||||
import HotPicksIcon from "./iconComponents/HotPicksIcon";
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
import MyPageIcon from "./iconComponents/MyPageIcon";
|
import { Cancelable } from '@enact/ui/Cancelable';
|
||||||
import OnSaleIcon from "./iconComponents/OnSaleIcon";
|
|
||||||
import SearchIcon from "./iconComponents/SearchIcon";
|
|
||||||
import TrendingNowIcon from "./iconComponents/TrendingNowIcon";
|
|
||||||
//이미지
|
//이미지
|
||||||
import shoptimeFullIcon from "../../../assets/icons/ic-lnb-logo-shoptime@3x.png";
|
import shoptimeFullIcon
|
||||||
import shopTimeIcon from "../../../assets/icons/ic-lnb-shoptime-symbol@3x.png";
|
from '../../../assets/icons/ic-lnb-logo-shoptime@3x.png';
|
||||||
|
import shopTimeIcon from '../../../assets/icons/ic-lnb-shoptime-symbol@3x.png';
|
||||||
|
import CartIcon from './iconComponents/CartIcon';
|
||||||
|
import CategoryIcon from './iconComponents/CategoryIcon';
|
||||||
|
import FeaturedBrandIcon from './iconComponents/FeaturedBrandIcon';
|
||||||
|
import HomeIcon from './iconComponents/HomeIcon';
|
||||||
|
import HotPicksIcon from './iconComponents/HotPicksIcon';
|
||||||
|
import MyPageIcon from './iconComponents/MyPageIcon';
|
||||||
|
import OnSaleIcon from './iconComponents/OnSaleIcon';
|
||||||
|
import SearchIcon from './iconComponents/SearchIcon';
|
||||||
|
import TrendingNowIcon from './iconComponents/TrendingNowIcon';
|
||||||
|
import TabItem from './TabItem';
|
||||||
|
import css from './TabLayout.module.less';
|
||||||
|
|
||||||
const Container = SpotlightContainerDecorator(
|
const Container = SpotlightContainerDecorator(
|
||||||
{ enterTo: "default-element" },
|
{ enterTo: "default-element" },
|
||||||
@@ -270,6 +278,7 @@ 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));
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import css from "./Banner.module.less";
|
||||||
|
|
||||||
|
export default function Banner({ selectedBrandInfo, topImgInfo }) {
|
||||||
|
const { logoImgAlt, logoImgPath, patncNm } = selectedBrandInfo;
|
||||||
|
const { topImgAlt, topImgNm, topImgPath } = topImgInfo;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={css.container}>
|
||||||
|
<div>
|
||||||
|
<img src={logoImgPath} alt={`${logoImgAlt} ${topImgNm}`} />
|
||||||
|
<h2>{patncNm}</h2>
|
||||||
|
</div>
|
||||||
|
<img src={topImgPath} alt={topImgAlt} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
.flex(@justifyCenter: flex-start, @alignCenter: flex-end);
|
||||||
|
.size(@w: 100%, @h: 108px);
|
||||||
|
|
||||||
|
div {
|
||||||
|
.flex();
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
// @@ Todo, padding-left 전체적으로 적용유무 수정
|
||||||
|
padding-left: 60px;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #fff;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
.size(@w: 60px, @h: 60px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> img {
|
||||||
|
.position(@position: absolute);
|
||||||
|
width: 100%;
|
||||||
|
height: 438px;
|
||||||
|
object-fit: cover;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "Banner.jsx",
|
||||||
|
"styles": [
|
||||||
|
"Banner.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,107 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import {
|
||||||
|
getBrandLayoutInfo,
|
||||||
|
getBrandList,
|
||||||
|
getBrandLiveChannelInfo,
|
||||||
|
} from "../../api/featuredBrands";
|
||||||
import TPanel from "../../components/TPanel/TPanel";
|
import TPanel from "../../components/TPanel/TPanel";
|
||||||
|
import Banner from "./Banner/Banner";
|
||||||
|
import css from "./FeaturedBrandsPanel.module.less";
|
||||||
|
import QuickMenu from "./QuickMenu/QuickMenu";
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
key, value and dataType of BrandList
|
||||||
|
|
||||||
|
expsOrd: 1 / number
|
||||||
|
logoImgAlt: "qvc" / string
|
||||||
|
logoImgNm: "us_qvc.png" / string
|
||||||
|
logoImgPath: "http://qt2-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/us_qvc.png" / string
|
||||||
|
newFlag: "N" / string
|
||||||
|
patncLogoPath: "http://qt2-ngfts.lge.com/fts/gftsDownload.lge?biz_code=LGSHOPPING&func_code=IMAGE&file_path=/lgshopping/image/small_logo_qvc.png" / string
|
||||||
|
patncNm: "QVC" / string
|
||||||
|
patnrId: "1" / string
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
export default function FeaturedBrandsPanel() {
|
export default function FeaturedBrandsPanel() {
|
||||||
return <TPanel>Featured Brands</TPanel>;
|
// @@ Todo, provided by GNB as props or global state
|
||||||
|
const [brandList, setBrandList] = useState([]);
|
||||||
|
|
||||||
|
// @@ Todo, provided by GNB as props or global state
|
||||||
|
const [selectedBrandId, setSelectedBrandId] = useState("1");
|
||||||
|
|
||||||
|
const [selectedBrandInfo, setSelectedBrandInfo] = useState({});
|
||||||
|
const [topImgInfo, setTopImgInfo] = useState({});
|
||||||
|
|
||||||
|
const handleQuickMenu = (patnrId) => {
|
||||||
|
const brandInfo = brandList.find((brand) => brand.patnrId === patnrId);
|
||||||
|
setSelectedBrandInfo(brandInfo);
|
||||||
|
setSelectedBrandId(patnrId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchBrandList = async () => {
|
||||||
|
try {
|
||||||
|
const data = await getBrandList();
|
||||||
|
console.log("Brand List:", data);
|
||||||
|
if (data) {
|
||||||
|
setBrandList(data.brandList);
|
||||||
|
setSelectedBrandInfo(() =>
|
||||||
|
data.brandList.find(({ patnrId }) => patnrId === selectedBrandId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching Brand List:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchBrandLayoutInfo = async (patnrId) => {
|
||||||
|
try {
|
||||||
|
const data = await getBrandLayoutInfo({ patnrId });
|
||||||
|
console.log("Brand Layout Info:", data);
|
||||||
|
if (data) {
|
||||||
|
setTopImgInfo(data.topImgInfo);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching Brand Layout Info:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchBrandLiveChannelInfo = async (patnrId) => {
|
||||||
|
try {
|
||||||
|
const data = await getBrandLiveChannelInfo({ patnrId });
|
||||||
|
console.log("Brand Live Channel Info:", data);
|
||||||
|
if (data) {
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching Brand Live Channel Info:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// @@ Todo, provided by GNB as props or global state
|
||||||
|
setSelectedBrandId("1");
|
||||||
|
fetchBrandList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchBrandLayoutInfo(selectedBrandId);
|
||||||
|
fetchBrandLiveChannelInfo(selectedBrandId);
|
||||||
|
}, [selectedBrandId]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
/* scenario page 98 */
|
||||||
|
<TPanel className={css.container}>
|
||||||
|
{brandList && brandList.length > 1 && (
|
||||||
|
<QuickMenu
|
||||||
|
brandList={brandList}
|
||||||
|
onQuickMenuClick={handleQuickMenu}
|
||||||
|
selectedBrandId={selectedBrandId}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Banner selectedBrandInfo={selectedBrandInfo} topImgInfo={topImgInfo} />
|
||||||
|
</TPanel>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.container {
|
||||||
|
margin-left: 120px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import React, { useEffect } from 'react';
|
||||||
|
|
||||||
|
import Spotlight from '@enact/spotlight';
|
||||||
|
import SpotlightContainerDecorator
|
||||||
|
from '@enact/spotlight/SpotlightContainerDecorator';
|
||||||
|
import Spottable from '@enact/spotlight/Spottable';
|
||||||
|
|
||||||
|
import { $L } from '../../../utils/helperMethods';
|
||||||
|
import css from './QuickMenu.module.less';
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
|
"nav"
|
||||||
|
);
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable("li");
|
||||||
|
|
||||||
|
export default function QuickMenu({
|
||||||
|
brandList,
|
||||||
|
selectedBrandId,
|
||||||
|
onQuickMenuClick,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
const handleClick = (patnrId) => {
|
||||||
|
if (selectedBrandId === patnrId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onQuickMenuClick(patnrId);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const element = document.getElementById(selectedBrandId);
|
||||||
|
Spotlight.focus(element);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container {...rest} className={css.container}>
|
||||||
|
<ul>
|
||||||
|
{brandList &&
|
||||||
|
brandList.map(({ logoImgAlt, logoImgPath, newFlag, patnrId }) => {
|
||||||
|
return (
|
||||||
|
<SpottableComponent
|
||||||
|
className={patnrId === selectedBrandId && css.selected}
|
||||||
|
id={patnrId}
|
||||||
|
key={patnrId}
|
||||||
|
onClick={() => handleClick(patnrId)}
|
||||||
|
>
|
||||||
|
{newFlag === "Y" && (
|
||||||
|
<span className={css.newBagde}>{$L("NEW")}</span>
|
||||||
|
)}
|
||||||
|
<span className={css.outline} />
|
||||||
|
<img src={logoImgPath} alt={logoImgAlt} />
|
||||||
|
</SpottableComponent>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex(@justifyCenter:flex start);
|
||||||
|
.size(@w: 100%, @h: 180px);
|
||||||
|
padding: 30px 60px;
|
||||||
|
background-color: #e7e7e7;
|
||||||
|
|
||||||
|
ul {
|
||||||
|
.flex(@justifyCenter: flex-start);
|
||||||
|
gap: 18px;
|
||||||
|
|
||||||
|
/* normal */
|
||||||
|
li {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.newBagde {
|
||||||
|
.position(@position: absolute, @top: 0, @right: 0, @bottom: auto, @left: auto);
|
||||||
|
z-index: 10;
|
||||||
|
.size(@w: 60px, @h: 30px);
|
||||||
|
background-color: #f00;
|
||||||
|
color: #fff;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-family: Arial;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
.position(@position: absolute, @top: 0, @right: auto, @bottom: auto, @left: 0);
|
||||||
|
.size(@w: 138px, @h:138px);
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
.size(@w: 120px, @h: 120px);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* focused */
|
||||||
|
&:focus {
|
||||||
|
border-radius: 60px;
|
||||||
|
.focusDropShadow();
|
||||||
|
|
||||||
|
.outline {
|
||||||
|
background-image: url("../../../../assets/images/partners/ic-tab-partners-focus@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
.size(@w: 138px, @h: 138px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* selected */
|
||||||
|
&.selected {
|
||||||
|
img {
|
||||||
|
.size(@w: 138px, @h: 138px);
|
||||||
|
}
|
||||||
|
.outline {
|
||||||
|
background-image: url("../../../../assets/images/partners/ic-tab-partners-selected@3x.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "QuickMenu.jsx",
|
||||||
|
"styles": [
|
||||||
|
"QuickMenu.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import Scroller from "@enact/sandstone/Scroller";
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import css from "./CategoryNav.module.less";
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { right: "" }, enterTo: "last-focused" },
|
||||||
|
"nav"
|
||||||
|
);
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable("li");
|
||||||
|
|
||||||
|
export default function CategoryNav({
|
||||||
|
categoryInfos,
|
||||||
|
currentLgCatCdIndex,
|
||||||
|
onCategoryNavClick,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Container {...rest} className={css.container}>
|
||||||
|
<Scroller
|
||||||
|
direction="horizontal"
|
||||||
|
horizontalScrollbar="hidden"
|
||||||
|
noScrollByWheel={true}
|
||||||
|
scrollMode="translate"
|
||||||
|
>
|
||||||
|
<ul>
|
||||||
|
{categoryInfos &&
|
||||||
|
categoryInfos.map(({ lgCatNm, lgCatCd }, index) => {
|
||||||
|
return (
|
||||||
|
<SpottableComponent
|
||||||
|
className={classNames(
|
||||||
|
css.category,
|
||||||
|
currentLgCatCdIndex === index && css.selected
|
||||||
|
)}
|
||||||
|
key={lgCatCd}
|
||||||
|
onClick={() => onCategoryNavClick(lgCatCd, index)}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<span className={css[`category-icon-${lgCatCd}`]} />
|
||||||
|
</div>
|
||||||
|
<strong>{lgCatNm}</strong>
|
||||||
|
</SpottableComponent>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</Scroller>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 120px;
|
||||||
|
|
||||||
|
// @@ Todo, z-index 관련 추후 수정 염두
|
||||||
|
z-index: 10;
|
||||||
|
width: calc(100% - 120px);
|
||||||
|
background-color: @BG_COLOR_01;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 28px;
|
||||||
|
// @@ font 관련 업데이트 후 수정
|
||||||
|
// .font(@fontFamily: @baseFontBold, @fontSize: 28px);
|
||||||
|
|
||||||
|
ul {
|
||||||
|
display: flex;
|
||||||
|
gap: 30px;
|
||||||
|
margin-top: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.category {
|
||||||
|
/* normal */
|
||||||
|
position: relative;
|
||||||
|
.flex(@direction: column);
|
||||||
|
min-width: 210px;
|
||||||
|
color: #1a1a1a;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
div {
|
||||||
|
.flex();
|
||||||
|
.size(@w: 94px, @h: 94px);
|
||||||
|
margin-bottom: 18px;
|
||||||
|
border-radius: 48px;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
border: 2px solid #1a1a1a;
|
||||||
|
|
||||||
|
span {
|
||||||
|
.size(@w: 80px, @h:80px);
|
||||||
|
background-position: center;
|
||||||
|
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/category/ic-category-garden-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fashion
|
||||||
|
&.category-icon-1000 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-fashion-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beauty
|
||||||
|
&.category-icon-1003 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-beauty-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jewelry
|
||||||
|
&.category-icon-1004 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-jewelry-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Home
|
||||||
|
&.category-icon-1006 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-home-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kitchen & Food
|
||||||
|
&.category-icon-1007 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-kitchen-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessories
|
||||||
|
&.category-icon-1014 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-accessories-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heaclth & Fitness
|
||||||
|
&.category-icon-1009 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-health-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crafts & Sewing
|
||||||
|
&.category-icon-1011 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-cw-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Electronics
|
||||||
|
&.category-icon-1010 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-electronics-nor@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearance
|
||||||
|
&.category-icon-1013 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-clearance-nor@3x.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
height: 60px;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
display: block;
|
||||||
|
.size(@w: 100%, @h:6px);
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* focused */
|
||||||
|
&:focus {
|
||||||
|
// color: #c70850;
|
||||||
|
|
||||||
|
div {
|
||||||
|
background-color: #fff;
|
||||||
|
border: solid 2px #c70850;
|
||||||
|
box-shadow: 0 0 25px 0 rgba(2, 3, 3, 0.8);
|
||||||
|
|
||||||
|
span {
|
||||||
|
// LG Electronics
|
||||||
|
&.category-icon-1017 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-lgelectronics-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Garden and Outdoors
|
||||||
|
&.category-icon-1008 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-garden-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fashion
|
||||||
|
&.category-icon-1000 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-fashion-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Beauty
|
||||||
|
&.category-icon-1003 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-beauty-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Jewelry
|
||||||
|
&.category-icon-1004 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-jewelry-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Home
|
||||||
|
&.category-icon-1006 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-home-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kitchen & Food
|
||||||
|
&.category-icon-1007 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-kitchen-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessories
|
||||||
|
&.category-icon-1014 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-accessories-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Heaclth & Fitness
|
||||||
|
&.category-icon-1009 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-health-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Crafts & Sewing
|
||||||
|
&.category-icon-1011 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-cw-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Electronics
|
||||||
|
&.category-icon-1010 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-electronics-foc@3x.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clearance
|
||||||
|
&.category-icon-1013 {
|
||||||
|
background-image: url("../../../../assets/category/ic-category-clearance-foc@3x.png");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #c70850;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
background-color: #c70850;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* selected */
|
||||||
|
.selected {
|
||||||
|
div {
|
||||||
|
background-color: #c70850;
|
||||||
|
border: solid 2px #c70850;
|
||||||
|
}
|
||||||
|
|
||||||
|
strong {
|
||||||
|
color: #c70850;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "CategoryNav.jsx",
|
||||||
|
"styles": [
|
||||||
|
"CategoryNav.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -1,5 +1,87 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
|
||||||
|
import { getOnSaleInfo } from "../../api/onSaleApi";
|
||||||
import TPanel from "../../components/TPanel/TPanel";
|
import TPanel from "../../components/TPanel/TPanel";
|
||||||
|
import CategoryNav from "./CategoryNav/CategoryNav";
|
||||||
|
import css from "./OnSalePanel.module.less";
|
||||||
|
import OnSaleProductCard from "./OnSaleProductCard/OnSaleProductCard";
|
||||||
|
import OnSaleProductsGrid from "./OnSaleProductsGrid/OnSaleProductsGrid";
|
||||||
|
|
||||||
export default function OnSalePanel() {
|
export default function OnSalePanel() {
|
||||||
return <TPanel>OnSale</TPanel>;
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
const [currentLgCatCdIndex, setCurrentLgCatCdIndex] = useState(0);
|
||||||
|
const [lgCatCd, setLgCatCd] = useState("");
|
||||||
|
const [categoryInfos, setCategoryInfos] = useState([]);
|
||||||
|
const [saleInfos, setSaleInfos] = useState([]);
|
||||||
|
const [saleProductInfos, setSaleProductInfos] = useState([]);
|
||||||
|
|
||||||
|
const handleCategoryNav = (lgCatCd, index) => {
|
||||||
|
if (currentLgCatCdIndex === index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCurrentLgCatCdIndex(index);
|
||||||
|
setLgCatCd(lgCatCd);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getOnSaleInfoData = async (lgCatCd) => {
|
||||||
|
try {
|
||||||
|
const onSaleInfoData = await getOnSaleInfo({
|
||||||
|
lgCatCd,
|
||||||
|
categoryIncFlag: "Y",
|
||||||
|
});
|
||||||
|
console.log("On Sale Data:", onSaleInfoData);
|
||||||
|
|
||||||
|
if (onSaleInfoData) {
|
||||||
|
if (lgCatCd === "") {
|
||||||
|
setCategoryInfos(onSaleInfoData.categoryInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSaleInfos(onSaleInfoData.saleInfos);
|
||||||
|
|
||||||
|
let saleProducts = [];
|
||||||
|
|
||||||
|
for (let index = 0; index < onSaleInfoData.saleInfos.length; index++) {
|
||||||
|
saleProducts.push(onSaleInfoData.saleInfos[index].saleProductInfos);
|
||||||
|
}
|
||||||
|
|
||||||
|
setSaleProductInfos(saleProducts);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error fetching on sale:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getOnSaleInfoData(lgCatCd);
|
||||||
|
}, [lgCatCd, currentLgCatCdIndex]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TPanel className={css.container}>
|
||||||
|
<CategoryNav
|
||||||
|
categoryInfos={categoryInfos}
|
||||||
|
currentLgCatCdIndex={currentLgCatCdIndex}
|
||||||
|
onCategoryNavClick={handleCategoryNav}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<section className={css.onSaleProducts}>
|
||||||
|
{saleInfos.map(({ saleNm }, index) => {
|
||||||
|
return (
|
||||||
|
<OnSaleProductsGrid key={saleNm} saleNm={saleNm}>
|
||||||
|
{saleProductInfos[index].map((saleProduct) => {
|
||||||
|
return (
|
||||||
|
<OnSaleProductCard
|
||||||
|
key={saleProduct.prdtId}
|
||||||
|
saleProduct={saleProduct}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</OnSaleProductsGrid>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</section>
|
||||||
|
</TPanel>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
@import "../../style/CommonStyle.module.less";
|
||||||
|
@import "../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
font-family: @baseFont;
|
||||||
|
|
||||||
|
.onSaleProducts {
|
||||||
|
margin-top: 236px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import Spottable from "@enact/spotlight/Spottable";
|
||||||
|
|
||||||
|
import css from "./OnSaleProductCard.module.less";
|
||||||
|
|
||||||
|
const SpottableComponent = Spottable("li");
|
||||||
|
|
||||||
|
export default function OnSaleProductCard({ saleProduct, ...rest }) {
|
||||||
|
const { imgUrl, prdtId, prdtNm, priceInfo } = saleProduct;
|
||||||
|
|
||||||
|
const originalPrice = priceInfo.split("|")[0];
|
||||||
|
const salePrice = priceInfo.split("|")[1];
|
||||||
|
const salePercentage = priceInfo.split("|").reverse()[0];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SpottableComponent
|
||||||
|
{...rest}
|
||||||
|
className={css.container}
|
||||||
|
spotlightId={prdtId}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<img src={imgUrl} alt={prdtNm} />
|
||||||
|
{salePercentage && <span>{salePercentage}</span>}
|
||||||
|
</div>
|
||||||
|
<div className={css.test}>
|
||||||
|
<h3>{prdtNm}</h3>
|
||||||
|
<p>
|
||||||
|
{salePrice}
|
||||||
|
<span>{originalPrice}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</SpottableComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
position: relative;
|
||||||
|
.flex(@direction: column);
|
||||||
|
.size(@w: 260px, @h: 375px);
|
||||||
|
margin: 0 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
background-color: #e3e7ee;
|
||||||
|
|
||||||
|
div:nth-child(1) {
|
||||||
|
position: relative;
|
||||||
|
.size(@w: 260px, @h: 260px);
|
||||||
|
|
||||||
|
img {
|
||||||
|
.size(@w: 260px, @h: 260px);
|
||||||
|
object-fit: cover;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> span {
|
||||||
|
.position(@position: absolute, @top: auto, @right: auto, @bottom: 12px, @left: 12px);
|
||||||
|
.size(@w: 44px, @h: 44px);
|
||||||
|
border-radius: 44px;
|
||||||
|
background-color: #c70850;
|
||||||
|
color: #fff;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 20px;
|
||||||
|
line-height: 44px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div:nth-child(2) {
|
||||||
|
.flex(@direction: column, @alignCenter: flex-start);
|
||||||
|
gap: 10px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
display: -webkit-box;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 26px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
color: #c70850;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 24px;
|
||||||
|
|
||||||
|
span {
|
||||||
|
margin-left: 5px;
|
||||||
|
color: #767676;
|
||||||
|
font-size: 18px;
|
||||||
|
text-decoration: line-through;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
.position(@position: absolute, @top: -12px, @right: auto, @bottom: auto, @left: -12px);
|
||||||
|
display: block;
|
||||||
|
.size(@w: 276px, @h: 390px);
|
||||||
|
border: 4px solid transparent;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: #fcfcfc;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
border: 4px solid #c70850;
|
||||||
|
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0),
|
||||||
|
0px 9px 15px 0 rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "OnSaleProductCard.jsx",
|
||||||
|
"styles": [
|
||||||
|
"OnSaleProductCard.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import SpotlightContainerDecorator from "@enact/spotlight/SpotlightContainerDecorator";
|
||||||
|
|
||||||
|
import css from "./OnSaleProductsGrid.module.less";
|
||||||
|
|
||||||
|
const Container = SpotlightContainerDecorator(
|
||||||
|
{ leaveFor: { left: "", right: "" }, enterTo: "last-focused" },
|
||||||
|
"li"
|
||||||
|
);
|
||||||
|
|
||||||
|
export default function OnSaleProductsGrid({ saleNm, children }) {
|
||||||
|
return (
|
||||||
|
<Container className={css.container}>
|
||||||
|
<h2>{saleNm}</h2>
|
||||||
|
<ul>{children}</ul>
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
@import "../../../style/CommonStyle.module.less";
|
||||||
|
@import "../../../style/utils.module.less";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
.flex(@direction:column, @alignCenter:flex-start);
|
||||||
|
gap: 40px;
|
||||||
|
width: 100%;
|
||||||
|
padding: 40px 0 20px 0;
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin-left: 60px;
|
||||||
|
font-family: @baseFontBold;
|
||||||
|
font-size: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
.flex();
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"main": "OnSaleProductsGrid.jsx",
|
||||||
|
"styles": [
|
||||||
|
"OnSaleProductsGrid.module.less"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user