mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 12:24:18 +00:00
Merge pull request #49 from KieIO/m7-lytran
M7 Ly: Fix UI, update from common
This commit is contained in:
@@ -26,6 +26,7 @@ module.exports = withCommerceConfig({
|
|||||||
images: {
|
images: {
|
||||||
// todo: replace domains for images
|
// todo: replace domains for images
|
||||||
domains: ['user-images.githubusercontent.com'],
|
domains: ['user-images.githubusercontent.com'],
|
||||||
|
minimumCacheTTL: 60,
|
||||||
},
|
},
|
||||||
i18n: {
|
i18n: {
|
||||||
locales: ['en-US', 'es'],
|
locales: ['en-US', 'es'],
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
import { Layout, RecipeDetail } from 'src/components/common'
|
import { Layout, RecipeDetail, RecommendedRecipes, RelevantBlogPosts } from 'src/components/common'
|
||||||
import { ProductInfoDetail, RecommendedRecipes, ReleventProducts, ViewedProducts } from 'src/components/modules/product-detail'
|
import { ProductInfoDetail, ReleventProducts, ViewedProducts } from 'src/components/modules/product-detail'
|
||||||
import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'
|
import { BLOGS_DATA_TEST, INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'
|
||||||
|
|
||||||
export default function Slug() {
|
export default function Slug() {
|
||||||
return <>
|
return <>
|
||||||
@@ -10,6 +10,7 @@ export default function Slug() {
|
|||||||
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
||||||
<ReleventProducts />
|
<ReleventProducts />
|
||||||
<ViewedProducts />
|
<ViewedProducts />
|
||||||
|
<RelevantBlogPosts data={BLOGS_DATA_TEST} title="relevent blog posts"/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
pages/recipe/[slug].tsx
Normal file
12
pages/recipe/[slug].tsx
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
import { Layout, RecipeDetail, RecommendedRecipes } from 'src/components/common'
|
||||||
|
import { INGREDIENT_DATA_TEST, RECIPE_DATA_TEST } from 'src/utils/demo-data'
|
||||||
|
|
||||||
|
export default function Slug() {
|
||||||
|
return <div className="page-recipe-detail">
|
||||||
|
<RecipeDetail ingredients={INGREDIENT_DATA_TEST} />
|
||||||
|
<RecommendedRecipes data={RECIPE_DATA_TEST} />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
Slug.Layout = Layout
|
@@ -78,6 +78,11 @@ export default function Test() {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className="shape-common-border">
|
||||||
|
<div className="inner">
|
||||||
|
Lorem ipsum dolor sit amet.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{/* <BlogDetailPage /> */}
|
{/* <BlogDetailPage /> */}
|
||||||
|
|
||||||
{/* <RecipeListPage/> */}
|
{/* <RecipeListPage/> */}
|
||||||
|
@@ -11,6 +11,17 @@ const option = {
|
|||||||
breakpoints: {}
|
breakpoints: {}
|
||||||
}
|
}
|
||||||
const Banner = memo(({ data }: Props) => {
|
const Banner = memo(({ data }: Props) => {
|
||||||
|
if (data.length === 1) {
|
||||||
|
const item = data[0]
|
||||||
|
return <BannerItem
|
||||||
|
title={item.title}
|
||||||
|
imgLink={item.imgLink}
|
||||||
|
subtitle={item.subtitle}
|
||||||
|
buttonLabel={item.buttonLabel}
|
||||||
|
linkButton={item.linkButton}
|
||||||
|
size={item.size}
|
||||||
|
/>
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<CarouselCommon<BannerItemProps>
|
<CarouselCommon<BannerItemProps>
|
||||||
data={data}
|
data={data}
|
||||||
|
@@ -1,16 +1,15 @@
|
|||||||
@import "../../../../styles/utilities";
|
@import "../../../../styles/utilities";
|
||||||
|
|
||||||
.bannerItem {
|
.bannerItem {
|
||||||
@apply bg-primary-light custom-border-radius-lg overflow-hidden;
|
@apply bg-primary-light shape-common-lg overflow-hidden;
|
||||||
@screen md {
|
padding: 0;
|
||||||
border: 1px solid var(--primary);
|
|
||||||
}
|
|
||||||
&.large {
|
&.large {
|
||||||
margin-bottom: 2.8rem;
|
margin-bottom: 2.8rem;
|
||||||
.inner {
|
.inner {
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center bottom;
|
||||||
@screen xl {
|
@screen xl {
|
||||||
@apply bg-right-bottom;
|
background-position: right bottom;
|
||||||
background-size: unset;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,13 +18,10 @@
|
|||||||
background-size: 90%;
|
background-size: 90%;
|
||||||
background-position: right -500% bottom 0%;
|
background-position: right -500% bottom 0%;
|
||||||
.content {
|
.content {
|
||||||
background-image: linear-gradient(
|
background-image: linear-gradient(to right, rgb(227, 242, 233) 63%, rgb(227, 242, 233, 0));
|
||||||
to right,
|
|
||||||
rgb(227, 242, 233, 0.9),
|
padding: 2rem;
|
||||||
rgb(227, 242, 233, 0.5) 80%,
|
padding-bottom: 4rem;
|
||||||
rgb(227, 242, 233, 0)
|
|
||||||
);
|
|
||||||
padding: 1.6rem;
|
|
||||||
max-width: 37rem;
|
max-width: 37rem;
|
||||||
@screen md {
|
@screen md {
|
||||||
max-width: 49.6rem;
|
max-width: 49.6rem;
|
||||||
@@ -38,9 +34,6 @@
|
|||||||
}
|
}
|
||||||
.subHeading {
|
.subHeading {
|
||||||
@apply sub-headline;
|
@apply sub-headline;
|
||||||
@screen md {
|
|
||||||
@apply caption;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,16 +1,18 @@
|
|||||||
@import "../../../styles/utilities";
|
@import "../../../styles/utilities";
|
||||||
|
|
||||||
.buttonCommon {
|
.buttonCommon {
|
||||||
@apply custom-border-radius bg-primary transition-all duration-200 text-white font-bold;
|
@apply shape-common;
|
||||||
|
.inner {
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
@apply bg-primary transition-all duration-200 text-white font-bold;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 1rem 2rem;
|
|
||||||
@screen md {
|
@screen md {
|
||||||
padding: 0.8rem 1.6rem;
|
padding: 1.6rem 1.6rem;
|
||||||
}
|
}
|
||||||
@screen lg {
|
@screen lg {
|
||||||
padding: 0.8rem 3.2rem;
|
padding: 1.6rem 3.2rem;
|
||||||
}
|
}
|
||||||
&:disabled {
|
&:disabled {
|
||||||
filter: brightness(0.9);
|
filter: brightness(0.9);
|
||||||
@@ -30,9 +32,10 @@
|
|||||||
&:focus-visible {
|
&:focus-visible {
|
||||||
outline: 2px solid var(--text-active);
|
outline: 2px solid var(--text-active);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.loading {
|
&.loading {
|
||||||
&::before {
|
.inner {
|
||||||
|
&::after {
|
||||||
content: "";
|
content: "";
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 1.6rem;
|
width: 1.6rem;
|
||||||
@@ -44,45 +47,66 @@
|
|||||||
margin-right: 0.8rem;
|
margin-right: 0.8rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.light {
|
&.light {
|
||||||
@apply text-base bg-white;
|
@apply shape-common-border;
|
||||||
border: 1px solid var(--text-active);
|
|
||||||
&.loading {
|
|
||||||
&::before {
|
&::before {
|
||||||
|
background-color: var(--text-active);
|
||||||
|
}
|
||||||
|
.inner {
|
||||||
|
@apply text-base bg-white;
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
.inner {
|
||||||
|
&::after {
|
||||||
border-top-color: var(--primary);
|
border-top-color: var(--primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.lightBorderNone {
|
&.lightBorderNone {
|
||||||
|
.inner {
|
||||||
@apply bg-white text-primary;
|
@apply bg-white text-primary;
|
||||||
|
}
|
||||||
&.loading {
|
&.loading {
|
||||||
&::before {
|
.inner::after {
|
||||||
border-top-color: var(--primary);
|
border-top-color: var(--primary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.ghost {
|
&.ghost {
|
||||||
|
@apply shape-common-border;
|
||||||
|
.inner {
|
||||||
@apply bg-white text-primary;
|
@apply bg-white text-primary;
|
||||||
border: 1px solid var(--primary);
|
}
|
||||||
&.loading {
|
|
||||||
&::before {
|
&::before {
|
||||||
|
background-color: var(--primary);
|
||||||
|
}
|
||||||
|
&.loading {
|
||||||
|
.inner::after {
|
||||||
border-top-color: var(--text-active);
|
border-top-color: var(--text-active);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.onlyIcon {
|
&.onlyIcon {
|
||||||
padding: 0.8rem;
|
.inner {
|
||||||
|
padding: 1rem;
|
||||||
|
@screen md {
|
||||||
|
padding: 1.6rem;
|
||||||
|
}
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.large {
|
&.large {
|
||||||
padding: 1rem 1.5rem;
|
.inner {
|
||||||
|
padding: 1rem 1.6rem;
|
||||||
&.onlyIcon {
|
&.onlyIcon {
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
@@ -95,8 +119,9 @@
|
|||||||
@screen lg {
|
@screen lg {
|
||||||
padding: 1.6rem 4.8rem;
|
padding: 1.6rem 4.8rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
&.loading {
|
&.loading {
|
||||||
&::before {
|
.inner::before {
|
||||||
width: 2.4rem;
|
width: 2.4rem;
|
||||||
height: 2.4rem;
|
height: 2.4rem;
|
||||||
}
|
}
|
||||||
@@ -104,19 +129,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.preserve {
|
&.preserve {
|
||||||
|
.inner {
|
||||||
flex-direction: row-reverse;
|
flex-direction: row-reverse;
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0 0 0 1.6rem;
|
margin: 0 0 0 1.6rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.icon {
|
.icon {
|
||||||
margin: 0 1.6rem 0 0;
|
margin: 0 1.6rem 0 0;
|
||||||
svg path {
|
svg {
|
||||||
|
height: 2rem;
|
||||||
|
path {
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% {
|
0% {
|
||||||
|
@@ -27,10 +27,12 @@ const ButtonCommon = memo(({ type = 'primary', size = 'default', loading = false
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
|
<div className={s.inner}>
|
||||||
{
|
{
|
||||||
icon && <span className={s.icon}>{icon}</span>
|
icon && <span className={s.icon}>{icon}</span>
|
||||||
}
|
}
|
||||||
<span className={s.label}>{children}</span>
|
<span className={s.label}>{children}</span>
|
||||||
|
</div>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@@ -15,6 +15,7 @@ export interface CarouselCommonProps<T> {
|
|||||||
option: TOptionsEvents
|
option: TOptionsEvents
|
||||||
keenClassname?: string
|
keenClassname?: string
|
||||||
isPadding?: boolean
|
isPadding?: boolean
|
||||||
|
defaultComponentProps?: object
|
||||||
}
|
}
|
||||||
|
|
||||||
const CarouselCommon = <T,>({
|
const CarouselCommon = <T,>({
|
||||||
@@ -25,6 +26,7 @@ const CarouselCommon = <T,>({
|
|||||||
isPadding = false,
|
isPadding = false,
|
||||||
isArrow = true,
|
isArrow = true,
|
||||||
isDot = false,
|
isDot = false,
|
||||||
|
defaultComponentProps,
|
||||||
option: { slideChanged,slidesPerView, ...sliderOption },
|
option: { slideChanged,slidesPerView, ...sliderOption },
|
||||||
}: CarouselCommonProps<T>) => {
|
}: CarouselCommonProps<T>) => {
|
||||||
const [currentSlide, setCurrentSlide] = React.useState(0)
|
const [currentSlide, setCurrentSlide] = React.useState(0)
|
||||||
@@ -68,11 +70,14 @@ const CarouselCommon = <T,>({
|
|||||||
[s.isPadding]: isPadding,
|
[s.isPadding]: isPadding,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{data?.map((props, index) => (
|
{data?.map((props, index) => {
|
||||||
|
const allProps = defaultComponentProps ? { ...props, ...defaultComponentProps } : props
|
||||||
|
return (
|
||||||
<div className="keen-slider__slide" key={`${itemKey}-${index}`}>
|
<div className="keen-slider__slide" key={`${itemKey}-${index}`}>
|
||||||
<Component {...props} />
|
<Component {...allProps} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
)
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
{slider && isArrow && (
|
{slider && isArrow && (
|
||||||
<>
|
<>
|
||||||
|
@@ -4,9 +4,6 @@
|
|||||||
.cartDrawer {
|
.cartDrawer {
|
||||||
@apply flex flex-col h-full;
|
@apply flex flex-col h-full;
|
||||||
.body {
|
.body {
|
||||||
@apply overflow-y-auto overflow-x-hidden h-full custom-scroll;
|
@apply flex flex-col justify-center overflow-y-auto overflow-x-hidden h-full custom-scroll;
|
||||||
}
|
|
||||||
.bottom {
|
|
||||||
padding-top: 1.6rem;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -23,7 +23,7 @@ const CartDrawer = ({ visible, onClose }: Props) => {
|
|||||||
<ProductsInCart data={PRODUCT_CART_DATA_TEST}/>
|
<ProductsInCart data={PRODUCT_CART_DATA_TEST}/>
|
||||||
<CartRecommendation />
|
<CartRecommendation />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.bottom}>
|
<div>
|
||||||
<CartMessage />
|
<CartMessage />
|
||||||
<CartCheckoutButton />
|
<CartCheckoutButton />
|
||||||
</div>
|
</div>
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
.cartCheckoutButton {
|
.cartCheckoutButton {
|
||||||
|
display: block;
|
||||||
padding: 1.6rem;
|
padding: 1.6rem;
|
||||||
|
width: 100%;
|
||||||
button {
|
button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@@ -1,12 +1,16 @@
|
|||||||
import React, { memo } from 'react';
|
import React, { memo } from 'react';
|
||||||
import { ButtonCommon } from 'src/components/common';
|
import { ButtonCommon } from 'src/components/common';
|
||||||
import s from './CartCheckoutButton.module.scss';
|
import s from './CartCheckoutButton.module.scss';
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { ROUTE } from 'src/utils/constanst.utils';
|
||||||
|
|
||||||
const CartCheckoutButton = memo(() => {
|
const CartCheckoutButton = memo(() => {
|
||||||
return (
|
return (
|
||||||
<div className={s.cartCheckoutButton}>
|
<Link href={ROUTE.CHECKOUT}>
|
||||||
|
<a className={s.cartCheckoutButton}>
|
||||||
<ButtonCommon size='large'>Check out - Rp 120.500</ButtonCommon>
|
<ButtonCommon size='large'>Check out - Rp 120.500</ButtonCommon>
|
||||||
</div>
|
</a>
|
||||||
|
</Link>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
@import '../../../../../styles/utilities';
|
@import "../../../../../styles/utilities";
|
||||||
|
|
||||||
.cartRecommendation {
|
.cartRecommendation {
|
||||||
@apply w-full bg-background-gray;
|
@apply w-full bg-background-gray;
|
||||||
|
padding-bottom: 5.4rem;
|
||||||
.top {
|
.top {
|
||||||
@apply flex justify-between items-center;
|
@apply flex justify-between items-center;
|
||||||
padding: 1.6rem;
|
padding: 1.6rem;
|
||||||
@@ -12,14 +13,10 @@
|
|||||||
.productCardWarpper {
|
.productCardWarpper {
|
||||||
padding-left: 1.6rem;
|
padding-left: 1.6rem;
|
||||||
:global(.customArrow) {
|
:global(.customArrow) {
|
||||||
@apply bg-line;
|
@apply bg-line shadow-md;
|
||||||
@screen lg {
|
opacity: 0.8;
|
||||||
&:global(.leftArrow) {
|
|
||||||
left: calc(-6.4rem - 2rem);
|
|
||||||
}
|
|
||||||
&:global(.rightArrow) {
|
&:global(.rightArrow) {
|
||||||
right: calc(-6.4rem - 2rem);
|
right: 1rem;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -7,14 +7,20 @@ import { PRODUCT_DATA_TEST } from 'src/utils/demo-data';
|
|||||||
import s from './CartRecommendation.module.scss';
|
import s from './CartRecommendation.module.scss';
|
||||||
|
|
||||||
const option: TOptionsEvents = {
|
const option: TOptionsEvents = {
|
||||||
slidesPerView: 2,
|
slidesPerView: 1.5,
|
||||||
mode: 'free',
|
mode: 'free',
|
||||||
breakpoints: {
|
breakpoints: {
|
||||||
'(min-width: 640px)': {
|
'(min-width: 640px)': {
|
||||||
slidesPerView: 1,
|
slidesPerView: 1.5,
|
||||||
},
|
},
|
||||||
'(min-width: 768px)': {
|
'(min-width: 768px)': {
|
||||||
slidesPerView: 2.5,
|
slidesPerView: 2.5,
|
||||||
|
},
|
||||||
|
'(min-width: 1008px)': {
|
||||||
|
slidesPerView: 2.2,
|
||||||
|
},
|
||||||
|
'(min-width: 1440px)': {
|
||||||
|
slidesPerView: 2.5,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -34,6 +40,7 @@ const CartRecommendation = () => {
|
|||||||
Component={ProductCard}
|
Component={ProductCard}
|
||||||
itemKey="cart-recommendation"
|
itemKey="cart-recommendation"
|
||||||
option={option}
|
option={option}
|
||||||
|
defaultComponentProps={{ isSingleButton: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -41,6 +41,8 @@ const Header = memo(({ toggleFilter }: props) => {
|
|||||||
} else {
|
} else {
|
||||||
setIsFullHeader(true)
|
setIsFullHeader(true)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
setIsFullHeader(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
window.addEventListener('scroll', handleScroll)
|
window.addEventListener('scroll', handleScroll)
|
||||||
@@ -51,31 +53,29 @@ const Header = memo(({ toggleFilter }: props) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<div className={classNames({
|
||||||
|
[s.headerSticky]: true,
|
||||||
|
[s.show]: !isFullHeader
|
||||||
|
})}>
|
||||||
|
<HeaderMenu
|
||||||
|
toggleFilter={toggleFilter}
|
||||||
|
toggleCart={toggleCart}
|
||||||
|
openModalAuthen={openModalAuthen}
|
||||||
|
openModalInfo={openModalInfo} />
|
||||||
|
</div>
|
||||||
|
|
||||||
<header ref={headeFullRef} className={classNames({ [s.header]: true, [s.full]: isFullHeader })}>
|
<header ref={headeFullRef} className={classNames({ [s.header]: true, [s.full]: isFullHeader })}>
|
||||||
<HeaderHighLight />
|
<HeaderHighLight />
|
||||||
<div className={s.menu}>
|
<div className={s.menu}>
|
||||||
<HeaderMenu
|
<HeaderMenu
|
||||||
toggleFilter={toggleFilter}
|
toggleFilter={toggleFilter}
|
||||||
toggleCart={toggleCart}
|
toggleCart={toggleCart}
|
||||||
isFull={isFullHeader}
|
|
||||||
openModalAuthen={openModalAuthen}
|
openModalAuthen={openModalAuthen}
|
||||||
openModalInfo={openModalInfo} />
|
openModalInfo={openModalInfo} />
|
||||||
<HeaderSubMenu />
|
<HeaderSubMenu />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|
||||||
<div className={classNames({
|
|
||||||
[s.headerSticky]: true,
|
|
||||||
[s.show]: !isFullHeader
|
|
||||||
})}>
|
|
||||||
<HeaderMenu isFull={isFullHeader}
|
|
||||||
toggleFilter={toggleFilter}
|
|
||||||
toggleCart={toggleCart}
|
|
||||||
openModalAuthen={openModalAuthen}
|
|
||||||
openModalInfo={openModalInfo} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<HeaderSubMenuMobile />
|
<HeaderSubMenuMobile />
|
||||||
<ModalAuthenticate visible={visibleModalAuthen} closeModal={closeModalAuthen} />
|
<ModalAuthenticate visible={visibleModalAuthen} closeModal={closeModalAuthen} />
|
||||||
<ModalCreateUserInfo demoVisible={visibleModalInfo} demoCloseModal={closeModalInfo} />
|
<ModalCreateUserInfo demoVisible={visibleModalInfo} demoCloseModal={closeModalInfo} />
|
||||||
|
@@ -7,6 +7,7 @@
|
|||||||
padding-top: 0.8rem;
|
padding-top: 0.8rem;
|
||||||
padding-bottom: 0.8rem;
|
padding-bottom: 0.8rem;
|
||||||
color: var(--white);
|
color: var(--white);
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
.menu {
|
.menu {
|
||||||
@apply flex items-center list-none;
|
@apply flex items-center list-none;
|
||||||
padding: 0.8rem 0;
|
padding: 0.8rem 0;
|
||||||
|
@@ -7,10 +7,6 @@
|
|||||||
@apply flex justify-between items-center;
|
@apply flex justify-between items-center;
|
||||||
padding-top: 0.8rem;
|
padding-top: 0.8rem;
|
||||||
padding-bottom: 0.8rem;
|
padding-bottom: 0.8rem;
|
||||||
&.full {
|
|
||||||
padding-top: 2.4rem;
|
|
||||||
padding-bottom: 2.4rem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.left {
|
.left {
|
||||||
.top {
|
.top {
|
||||||
@@ -47,6 +43,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.btnCart {
|
||||||
|
all: unset;
|
||||||
|
cursor: pointer;
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid #000;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
svg path {
|
||||||
|
fill: var(--primary);
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.menu {
|
.menu {
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
@screen md {
|
@screen md {
|
||||||
@@ -70,19 +79,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.btnCart {
|
|
||||||
all: unset;
|
|
||||||
cursor: pointer;
|
|
||||||
&:focus-visible {
|
|
||||||
outline: 2px solid #000;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
svg path {
|
|
||||||
fill: var(--primary);
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@screen xl {
|
@screen xl {
|
||||||
|
@@ -10,7 +10,6 @@ import s from './HeaderMenu.module.scss'
|
|||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
interface Props {
|
interface Props {
|
||||||
children?: any,
|
children?: any,
|
||||||
isFull: boolean,
|
|
||||||
openModalAuthen: () => void,
|
openModalAuthen: () => void,
|
||||||
openModalInfo: () => void,
|
openModalInfo: () => void,
|
||||||
toggleFilter: () => void,
|
toggleFilter: () => void,
|
||||||
@@ -19,7 +18,7 @@ interface Props {
|
|||||||
|
|
||||||
const FILTER_PAGE = [ROUTE.HOME, ROUTE.PRODUCTS]
|
const FILTER_PAGE = [ROUTE.HOME, ROUTE.PRODUCTS]
|
||||||
|
|
||||||
const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo, toggleFilter, toggleCart }: Props) => {
|
const HeaderMenu = memo(({ openModalAuthen, openModalInfo, toggleFilter, toggleCart }: Props) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const optionMenu = useMemo(() => [
|
const optionMenu = useMemo(() => [
|
||||||
{
|
{
|
||||||
@@ -41,7 +40,7 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo, toggleFilter,
|
|||||||
|
|
||||||
], [openModalAuthen])
|
], [openModalAuthen])
|
||||||
return (
|
return (
|
||||||
<section className={classNames({ [s.headerMenu]: true, [s.full]: isFull })}>
|
<section className={s.headerMenu}>
|
||||||
<div className={s.left}>
|
<div className={s.left}>
|
||||||
<div className={s.top}>
|
<div className={s.top}>
|
||||||
<Logo />
|
<Logo />
|
||||||
@@ -53,7 +52,7 @@ const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo, toggleFilter,
|
|||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<button className={s.iconCart}>
|
<button className={`${s.iconCart} ${s.btnCart}`} onClick={toggleCart}>
|
||||||
<IconBuy />
|
<IconBuy />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -5,6 +5,7 @@
|
|||||||
@screen md {
|
@screen md {
|
||||||
@apply block;
|
@apply block;
|
||||||
padding-bottom: 2.4rem;
|
padding-bottom: 2.4rem;
|
||||||
|
margin-top: 1.6rem;
|
||||||
transform: none;
|
transform: none;
|
||||||
height: unset;
|
height: unset;
|
||||||
@screen lg {
|
@screen lg {
|
||||||
|
@@ -4,30 +4,32 @@
|
|||||||
@apply fixed w-full bg-white;
|
@apply fixed w-full bg-white;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
padding: 2rem 1rem;
|
padding: 0 1rem 1rem;
|
||||||
border-top: 1px solid var(--border-line);
|
border-top: 1px solid var(--border-line);
|
||||||
box-shadow: -5px 6px 10px rgba(0, 0, 0, 0.2);
|
box-shadow: -5px 6px 10px rgba(0, 0, 0, 0.2);
|
||||||
z-index: 9999;
|
z-index: 9999;
|
||||||
.menu {
|
.menu {
|
||||||
@apply grid grid-cols-4;
|
@apply grid grid-cols-5;
|
||||||
li {
|
li {
|
||||||
a {
|
a {
|
||||||
@apply transition-all duration-200 no-underline;
|
@apply transition-all duration-200 no-underline;
|
||||||
&:hover {
|
-webkit-tap-highlight-color: unset;
|
||||||
color: var(--primary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.menuItem {
|
.menuItem {
|
||||||
@apply flex flex-col justify-center items-center sm-label;
|
@apply flex flex-col justify-center items-center sm-label;
|
||||||
|
padding-top: 1rem;
|
||||||
|
border-top: 2px solid transparent;
|
||||||
.icon {
|
.icon {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
height: 3rem;
|
||||||
svg path {
|
svg path {
|
||||||
fill: currentColor;
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.active {
|
&.active {
|
||||||
@apply text-primary;
|
@apply text-primary;
|
||||||
|
border-top: 2px solid var(--primary);
|
||||||
}
|
}
|
||||||
&.dot {
|
&.dot {
|
||||||
.icon {
|
.icon {
|
||||||
|
@@ -2,7 +2,7 @@ import classNames from 'classnames'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { useRouter } from 'next/router'
|
import { useRouter } from 'next/router'
|
||||||
import { memo } from 'react'
|
import { memo } from 'react'
|
||||||
import { IconHeart, IconHome, IconShopping, IconUser } from 'src/components/icons'
|
import { IconHeart, IconHome, IconNoti, IconShopping, IconUser } from 'src/components/icons'
|
||||||
import { ACCOUNT_TAB, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
import { ACCOUNT_TAB, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||||
import s from './HeaderSubMenuMobile.module.scss'
|
import s from './HeaderSubMenuMobile.module.scss'
|
||||||
|
|
||||||
@@ -11,7 +11,6 @@ const OPTION_MENU = [
|
|||||||
link: ROUTE.HOME,
|
link: ROUTE.HOME,
|
||||||
name: 'Home',
|
name: 'Home',
|
||||||
icon: <IconHome />,
|
icon: <IconHome />,
|
||||||
isMarked: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
link: ROUTE.PRODUCTS,
|
link: ROUTE.PRODUCTS,
|
||||||
@@ -25,6 +24,12 @@ const OPTION_MENU = [
|
|||||||
icon: <IconHeart />,
|
icon: <IconHeart />,
|
||||||
isMarked: false,
|
isMarked: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
link: `${ROUTE.ACCOUNT}?${QUERY_KEY.TAB}=${ACCOUNT_TAB.NOTIFICATION}`,
|
||||||
|
name: 'Notifications',
|
||||||
|
icon: <IconNoti />,
|
||||||
|
isMarked: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
link: ROUTE.ACCOUNT,
|
link: ROUTE.ACCOUNT,
|
||||||
name: 'Account',
|
name: 'Account',
|
||||||
|
@@ -6,16 +6,17 @@ import { BLUR_DATA_IMG } from 'src/utils/constanst.utils'
|
|||||||
export interface ImgWithLinkProps {
|
export interface ImgWithLinkProps {
|
||||||
src: string,
|
src: string,
|
||||||
alt?: string,
|
alt?: string,
|
||||||
|
blurDataURL?: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImgWithLink = ({ src, alt }: ImgWithLinkProps) => {
|
const ImgWithLink = ({ src, alt, blurDataURL = BLUR_DATA_IMG }: ImgWithLinkProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.imgWithLink}>
|
<div className={s.imgWithLink}>
|
||||||
<Image src={src} alt={alt}
|
<Image src={src} alt={alt}
|
||||||
layout="fill"
|
layout="fill"
|
||||||
className={s.imgWithLink}
|
className={s.imgWithLink}
|
||||||
placeholder="blur"
|
placeholder="blur"
|
||||||
blurDataURL={BLUR_DATA_IMG}
|
blurDataURL={blurDataURL}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@@ -17,8 +17,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.inputCommon {
|
.inputCommon {
|
||||||
@apply block w-full transition-all duration-200 rounded bg-white;
|
@apply block w-full transition-all duration-200 bg-white;
|
||||||
padding: 1.2rem 1.6rem;
|
border-radius: .8rem;
|
||||||
|
padding: 1.6rem;
|
||||||
border: 1px solid var(--border-line);
|
border: 1px solid var(--border-line);
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus,
|
||||||
@@ -31,24 +32,6 @@
|
|||||||
&::placeholder {
|
&::placeholder {
|
||||||
@apply text-label;
|
@apply text-label;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.custom {
|
|
||||||
@apply custom-border-radius;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background: var(--gray);
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
border: 1px solid var(--primary);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.bgTransparent {
|
|
||||||
background: rgb(227, 242, 233, 0.3);
|
|
||||||
color: var(--white);
|
|
||||||
&::placeholder {
|
|
||||||
color: var(--white);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.preserve {
|
&.preserve {
|
||||||
@@ -91,4 +74,27 @@
|
|||||||
color: var(--negative);
|
color: var(--negative);
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.custom {
|
||||||
|
@apply shape-common;
|
||||||
|
.inputCommon {
|
||||||
|
border: none;
|
||||||
|
background: var(--background-gray);
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
@apply shadow-md;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.bgTransparent {
|
||||||
|
.inputCommon {
|
||||||
|
background: rgb(227, 242, 233, 0.3);
|
||||||
|
color: var(--white);
|
||||||
|
&::placeholder {
|
||||||
|
color: var(--white);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
import React, { forwardRef, useImperativeHandle, useMemo, useRef } from 'react';
|
||||||
import { IconCheck, IconError, IconPassword, IconPasswordCross } from 'src/components/icons';
|
import { IconCheck, IconError } from 'src/components/icons';
|
||||||
import { KEY } from 'src/utils/constanst.utils';
|
import { KEY } from 'src/utils/constanst.utils';
|
||||||
import s from './InputCommon.module.scss';
|
import s from './InputCommon.module.scss';
|
||||||
|
|
||||||
@@ -63,6 +63,9 @@ const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleTyp
|
|||||||
return (
|
return (
|
||||||
<div className={classNames({
|
<div className={classNames({
|
||||||
[s.inputWrap]: true,
|
[s.inputWrap]: true,
|
||||||
|
[s[styleType]]: true,
|
||||||
|
[s.bgTransparent]: backgroundTransparent
|
||||||
|
|
||||||
})}>
|
})}>
|
||||||
<div className={classNames({
|
<div className={classNames({
|
||||||
[s.inputInner]: true,
|
[s.inputInner]: true,
|
||||||
@@ -78,11 +81,7 @@ const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleTyp
|
|||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onKeyDown={handleKeyDown}
|
onKeyDown={handleKeyDown}
|
||||||
className={classNames({
|
className={s.inputCommon}
|
||||||
[s.inputCommon]: true,
|
|
||||||
[s[styleType]]: true,
|
|
||||||
[s.bgTransparent]: backgroundTransparent
|
|
||||||
})}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
|
@@ -3,9 +3,14 @@
|
|||||||
.listProductWithInfo {
|
.listProductWithInfo {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
border-top: 1rem solid var(--gray);
|
border-top: 1rem solid var(--gray);
|
||||||
border-bottom: 1rem solid var(--gray);
|
|
||||||
padding-top: 6rem;
|
padding-top: 6rem;
|
||||||
padding-bottom: 6rem;
|
padding-bottom: 6rem;
|
||||||
|
&.borderBottom {
|
||||||
|
border-bottom: 1rem solid var(--gray);
|
||||||
|
@screen lg {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
@screen lg {
|
@screen lg {
|
||||||
@apply flex spacing-horizontal-left;
|
@apply flex spacing-horizontal-left;
|
||||||
padding-top: 5.6rem;
|
padding-top: 5.6rem;
|
||||||
@@ -17,8 +22,11 @@
|
|||||||
@apply spacing-horizontal-left;
|
@apply spacing-horizontal-left;
|
||||||
@screen lg {
|
@screen lg {
|
||||||
max-width: 75%;
|
max-width: 75%;
|
||||||
@apply custom-border-radius-lg bg-white;
|
padding: 0 0.8rem;
|
||||||
padding: 4rem .8rem;
|
> div > div {
|
||||||
|
@apply shape-common-lg bg-white;
|
||||||
|
padding: 4rem 0;
|
||||||
|
}
|
||||||
:global(.customArrow) {
|
:global(.customArrow) {
|
||||||
@screen lg {
|
@screen lg {
|
||||||
&:global(.leftArrow) {
|
&:global(.leftArrow) {
|
||||||
@@ -31,18 +39,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
@screen xl {
|
@screen xl {
|
||||||
padding: 4rem 2.4rem;
|
padding: 0 2.4rem;
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
:global(.customArrow) {
|
|
||||||
@screen lg {
|
|
||||||
&:global(.leftArrow) {
|
|
||||||
left: calc(-6.4rem + 1rem);
|
|
||||||
}
|
|
||||||
&:global(.rightArrow) {
|
|
||||||
right: calc(-6.4rem + 1rem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
import { TOptionsEvents } from 'keen-slider';
|
import { TOptionsEvents } from 'keen-slider';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import CarouselCommon from '../CarouselCommon/CarouselCommon';
|
import CarouselCommon from '../CarouselCommon/CarouselCommon';
|
||||||
@@ -9,6 +10,7 @@ interface Props {
|
|||||||
data: ProductCardProps[],
|
data: ProductCardProps[],
|
||||||
title: string,
|
title: string,
|
||||||
subtitle?: string,
|
subtitle?: string,
|
||||||
|
hasBorderBottomMobile?: boolean,
|
||||||
}
|
}
|
||||||
const OPTION_DEFAULT: TOptionsEvents = {
|
const OPTION_DEFAULT: TOptionsEvents = {
|
||||||
slidesPerView: 2,
|
slidesPerView: 2,
|
||||||
@@ -18,20 +20,29 @@ const OPTION_DEFAULT: TOptionsEvents = {
|
|||||||
slidesPerView: 3,
|
slidesPerView: 3,
|
||||||
},
|
},
|
||||||
'(min-width: 768px)': {
|
'(min-width: 768px)': {
|
||||||
slidesPerView: 4,
|
|
||||||
},
|
|
||||||
'(min-width: 1024px)': {
|
|
||||||
slidesPerView: 3,
|
slidesPerView: 3,
|
||||||
},
|
},
|
||||||
|
'(min-width: 1008px)': {
|
||||||
|
slidesPerView: 3.5,
|
||||||
|
},
|
||||||
|
'(min-width: 1024px)': {
|
||||||
|
slidesPerView: 2.5,
|
||||||
|
},
|
||||||
'(min-width: 1280px)': {
|
'(min-width: 1280px)': {
|
||||||
|
slidesPerView: 3.5,
|
||||||
|
},
|
||||||
|
'(min-width: 1440px)': {
|
||||||
slidesPerView: 4.5,
|
slidesPerView: 4.5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListProductWithInfo = ({ data, title, subtitle }: Props) => {
|
const ListProductWithInfo = ({ data, title, subtitle, hasBorderBottomMobile }: Props) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.listProductWithInfo}>
|
<div className={classNames({
|
||||||
|
[s.listProductWithInfo]: true,
|
||||||
|
[s.borderBottom]: hasBorderBottomMobile,
|
||||||
|
})}>
|
||||||
<InfoProducts
|
<InfoProducts
|
||||||
title={title}
|
title={title}
|
||||||
subtitle={subtitle}
|
subtitle={subtitle}
|
||||||
|
@@ -71,7 +71,8 @@
|
|||||||
@apply block shadow-md;
|
@apply block shadow-md;
|
||||||
}
|
}
|
||||||
.menuIner {
|
.menuIner {
|
||||||
@apply rounded list-none bg-white;
|
@apply list-none bg-white;
|
||||||
|
border-radius: 0.8rem;
|
||||||
border: 1px solid var(--text-active);
|
border: 1px solid var(--text-active);
|
||||||
margin-top: 0.4rem;
|
margin-top: 0.4rem;
|
||||||
> li {
|
> li {
|
||||||
|
@@ -1,9 +1,7 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import Link from 'next/link';
|
|
||||||
import React, { useRef } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import { useModalCommon } from 'src/components/hooks/useModalCommon';
|
import { STATE_OPTIONS } from 'src/utils/constanst.utils';
|
||||||
import { CustomInputCommon } from 'src/utils/type.utils';
|
import { CustomInputCommon } from 'src/utils/type.utils';
|
||||||
import { Inputcommon } from '..';
|
import { Inputcommon, SelectCommon } from '..';
|
||||||
import ButtonCommon from '../ButtonCommon/ButtonCommon';
|
import ButtonCommon from '../ButtonCommon/ButtonCommon';
|
||||||
import ModalCommon from '../ModalCommon/ModalCommon';
|
import ModalCommon from '../ModalCommon/ModalCommon';
|
||||||
import s from './ModalCreateUserInfo.module.scss';
|
import s from './ModalCreateUserInfo.module.scss';
|
||||||
@@ -27,8 +25,7 @@ const ModalCreateUserInfo = ({ demoVisible: visible, demoCloseModal: closeModal
|
|||||||
<Inputcommon placeholder='Street Address' ref={firstInputRef} />
|
<Inputcommon placeholder='Street Address' ref={firstInputRef} />
|
||||||
<Inputcommon placeholder='City' />
|
<Inputcommon placeholder='City' />
|
||||||
<div className={s.line}>
|
<div className={s.line}>
|
||||||
{/* todo: select, not input */}
|
<SelectCommon option={STATE_OPTIONS} type="custom" size="large" placeholder='State'/>
|
||||||
<Inputcommon placeholder='State' />
|
|
||||||
<Inputcommon placeholder='Zip code' />
|
<Inputcommon placeholder='Zip code' />
|
||||||
</div>
|
</div>
|
||||||
<Inputcommon placeholder='Phone (delivery contact)' />
|
<Inputcommon placeholder='Phone (delivery contact)' />
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
.productCardWarpper {
|
.productCardWarpper {
|
||||||
max-width: 20.8rem;
|
max-width: 22.4rem;
|
||||||
min-height: 31.8rem;
|
min-height: 31.8rem;
|
||||||
padding: 1.2rem 1.2rem 0 1.2rem;
|
padding: 1.2rem 1.2rem 0 1.2rem;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@@ -16,6 +16,12 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@apply flex justify-center items-center;
|
@apply flex justify-center items-center;
|
||||||
|
> div {
|
||||||
|
min-height: 13rem;
|
||||||
|
img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
img {
|
img {
|
||||||
@apply inline;
|
@apply inline;
|
||||||
}
|
}
|
||||||
@@ -57,10 +63,26 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cardBot {
|
.cardBot {
|
||||||
min-height: 4rem;
|
|
||||||
@apply flex justify-between items-center;
|
@apply flex justify-between items-center;
|
||||||
|
min-height: 4rem;
|
||||||
|
margin-top: 1.6rem;
|
||||||
.cardIcon {
|
.cardIcon {
|
||||||
margin-right: 0.8rem;
|
margin-right: 0.8rem;
|
||||||
}
|
}
|
||||||
|
.cardButton {
|
||||||
|
width: 100%;
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
> div {
|
||||||
|
span {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 1;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow-y: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,7 +1,9 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { IconBuy } from 'src/components/icons'
|
||||||
import { ROUTE } from 'src/utils/constanst.utils'
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
import { ProductProps } from 'src/utils/types.utils'
|
import { ProductProps } from 'src/utils/types.utils'
|
||||||
|
import { ImgWithLink } from '..'
|
||||||
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
||||||
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
|
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
|
||||||
import ItemWishList from '../ItemWishList/ItemWishList'
|
import ItemWishList from '../ItemWishList/ItemWishList'
|
||||||
@@ -11,6 +13,7 @@ import ProductNotSell from './ProductNotSell/ProductNotSell'
|
|||||||
|
|
||||||
export interface ProductCardProps extends ProductProps {
|
export interface ProductCardProps extends ProductProps {
|
||||||
buttonText?: string
|
buttonText?: string
|
||||||
|
isSingleButton?: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProductCard = ({
|
const ProductCard = ({
|
||||||
@@ -21,6 +24,7 @@ const ProductCard = ({
|
|||||||
buttonText = 'Buy Now',
|
buttonText = 'Buy Now',
|
||||||
imageSrc,
|
imageSrc,
|
||||||
isNotSell,
|
isNotSell,
|
||||||
|
isSingleButton,
|
||||||
}: ProductCardProps) => {
|
}: ProductCardProps) => {
|
||||||
if (isNotSell) {
|
if (isNotSell) {
|
||||||
return <div className={`${s.productCardWarpper} ${s.notSell}`}>
|
return <div className={`${s.productCardWarpper} ${s.notSell}`}>
|
||||||
@@ -34,7 +38,7 @@ const ProductCard = ({
|
|||||||
<div className={s.cardTop}>
|
<div className={s.cardTop}>
|
||||||
<Link href={`${ROUTE.PRODUCT_DETAIL}/test`}>
|
<Link href={`${ROUTE.PRODUCT_DETAIL}/test`}>
|
||||||
<div className={s.productImage}>
|
<div className={s.productImage}>
|
||||||
<img src={imageSrc} alt="image" />
|
<ImgWithLink src={imageSrc} alt={name}/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<div className={s.productLabel}>
|
<div className={s.productLabel}>
|
||||||
@@ -56,12 +60,22 @@ const ProductCard = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={s.cardBot}>
|
<div className={s.cardBot}>
|
||||||
|
{
|
||||||
|
isSingleButton ?
|
||||||
|
<div className={s.cardButton}>
|
||||||
|
<ButtonCommon type="light" icon={<IconBuy />}>Add to cart</ButtonCommon>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<>
|
||||||
<div className={s.cardIcon}>
|
<div className={s.cardIcon}>
|
||||||
<ButtonIconBuy />
|
<ButtonIconBuy />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.cardButton}>
|
<div className={s.cardButton}>
|
||||||
<ButtonCommon type="light">{buttonText}</ButtonCommon>
|
<ButtonCommon type="light">{buttonText}</ButtonCommon>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
@@ -1,8 +1,12 @@
|
|||||||
@import "../../../../styles/utilities";
|
@import "../../../../styles/utilities";
|
||||||
|
|
||||||
.imgWrap {
|
.imgWrap {
|
||||||
|
> div {
|
||||||
|
min-height: 13rem;
|
||||||
img {
|
img {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
object-fit: contain
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,7 +15,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
@apply flex justify-center items-center custom-border-radius bg-info-light text-center;
|
@apply flex justify-center items-center shape-common bg-info-light text-center;
|
||||||
padding: .8rem 1.6rem;
|
padding: .8rem 1.6rem;
|
||||||
margin-top: 1.6rem;
|
margin-top: 1.6rem;
|
||||||
color: var(--info);
|
color: var(--info);
|
||||||
|
@@ -19,11 +19,15 @@ const OPTION_DEFAULT: TOptionsEvents = {
|
|||||||
slidesPerView: 3,
|
slidesPerView: 3,
|
||||||
},
|
},
|
||||||
'(min-width: 768px)': {
|
'(min-width: 768px)': {
|
||||||
slidesPerView: 4,
|
slidesPerView: 3,
|
||||||
},
|
},
|
||||||
'(min-width: 1024px)': {
|
'(min-width: 1008px)': {
|
||||||
|
slidesPerView: 3.5,
|
||||||
|
},
|
||||||
|
'(min-width: 1280px)': {
|
||||||
slidesPerView: 4.5,
|
slidesPerView: 4.5,
|
||||||
},'(min-width: 1280px)': {
|
},
|
||||||
|
'(min-width: 1440px)': {
|
||||||
slidesPerView: 5.5,
|
slidesPerView: 5.5,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@@ -1,19 +1,24 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
import { RecipeProps } from 'src/utils/types.utils'
|
import { RecipeProps } from 'src/utils/types.utils'
|
||||||
import s from './RecipeCard.module.scss'
|
import s from './RecipeCard.module.scss'
|
||||||
export interface RecipeCardProps extends RecipeProps { }
|
export interface RecipeCardProps extends RecipeProps { }
|
||||||
|
|
||||||
const RecipeCard = ({ imageSrc, title, description }: RecipeCardProps) => {
|
const RecipeCard = ({ imageSrc, title, description, slug }: RecipeCardProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={s.recipeCardWarpper}>
|
<div className={s.recipeCardWarpper}>
|
||||||
<Link href="#">
|
<Link href={`${ROUTE.RECIPE_DETAIL}/${slug}`}>
|
||||||
|
<a>
|
||||||
<div className={s.image}>
|
<div className={s.image}>
|
||||||
<img src={imageSrc} alt="image recipe" />
|
<img src={imageSrc} alt="image recipe" />
|
||||||
</div>
|
</div>
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<Link href="#">
|
<Link href={`${ROUTE.RECIPE_DETAIL}/${slug}`}>
|
||||||
|
<a>
|
||||||
<div className={s.title}>{title}</div>
|
<div className={s.title}>{title}</div>
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
<div className={s.description}>{description}</div>
|
<div className={s.description}>{description}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -2,13 +2,16 @@
|
|||||||
|
|
||||||
.recipeDetailInfo {
|
.recipeDetailInfo {
|
||||||
@apply spacing-horizontal;
|
@apply spacing-horizontal;
|
||||||
margin: 5.6rem auto;
|
margin: 0 auto 5.6rem;
|
||||||
@screen md {
|
@screen md {
|
||||||
@apply flex;
|
@apply flex;
|
||||||
|
margin: 5.6rem auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.img {
|
.img {
|
||||||
width: fit-content;
|
width: 100%;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
min-height: 50rem;
|
||||||
|
|
||||||
@screen sm-only {
|
@screen sm-only {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
@@ -16,13 +19,16 @@
|
|||||||
@screen lg {
|
@screen lg {
|
||||||
max-width: 60rem;
|
max-width: 60rem;
|
||||||
}
|
}
|
||||||
|
> div {
|
||||||
|
min-height: 64rem;
|
||||||
img {
|
img {
|
||||||
@apply w-full;
|
// object-fit: contain;
|
||||||
object-fit: contain;
|
// @apply w-full;
|
||||||
max-height: 64rem;
|
min-height: 64rem;
|
||||||
border-radius: 2.4rem;
|
border-radius: 2.4rem;
|
||||||
@screen md {
|
// @screen md {
|
||||||
max-height: 90rem;
|
// max-height: 90rem;
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,6 +61,9 @@
|
|||||||
list-style: disc;
|
list-style: disc;
|
||||||
margin-left: 2rem;
|
margin-left: 2rem;
|
||||||
}
|
}
|
||||||
|
a {
|
||||||
|
color: var(--info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import { ImgWithLink } from 'src/components/common'
|
||||||
import RecipeBriefInfo from '../RecipeBriefInfo/RecipeBriefInfo'
|
import RecipeBriefInfo from '../RecipeBriefInfo/RecipeBriefInfo'
|
||||||
import s from './RecipeDetailInfo.module.scss'
|
import s from './RecipeDetailInfo.module.scss'
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ const RecipeDetailInfo = ({ }: Props) => {
|
|||||||
return (
|
return (
|
||||||
<section className={s.recipeDetailInfo}>
|
<section className={s.recipeDetailInfo}>
|
||||||
<div className={s.img}>
|
<div className={s.img}>
|
||||||
<img src="https://user-images.githubusercontent.com/76729908/131634880-8ae1437b-d3f8-421e-a546-d5a4f9a28e5f.png" alt="Recipe" />
|
<ImgWithLink src="https://user-images.githubusercontent.com/76729908/131634880-8ae1437b-d3f8-421e-a546-d5a4f9a28e5f.png" alt="Recipe" />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.recipeInfo}>
|
<div className={s.recipeInfo}>
|
||||||
<div className={s.top}>
|
<div className={s.top}>
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
@import "../../../../styles/utilities";
|
@import "../../../styles/utilities";
|
||||||
|
|
||||||
.recommendedRecipes {
|
.recommendedRecipes {
|
||||||
margin: 6rem auto;
|
margin: 6rem auto;
|
@@ -28,7 +28,7 @@
|
|||||||
}
|
}
|
||||||
&.custom {
|
&.custom {
|
||||||
.selectTrigger {
|
.selectTrigger {
|
||||||
@apply border-2;
|
border-width: 1px;
|
||||||
border-color: var(--border-line);
|
border-color: var(--border-line);
|
||||||
color: var(--text-label);
|
color: var(--text-label);
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
@apply border-solid border border-current;
|
@apply border-solid border border-current;
|
||||||
}
|
}
|
||||||
&.custom {
|
&.custom {
|
||||||
@apply border-2;
|
border-width: 1px;
|
||||||
border-color: var(--border-line);
|
border-color: var(--border-line);
|
||||||
color: var(--text-label);
|
color: var(--text-label);
|
||||||
}
|
}
|
||||||
|
@@ -46,3 +46,4 @@ export { default as TabCommon} from './TabCommon/TabCommon'
|
|||||||
export { default as StaticImage} from './StaticImage/StaticImage'
|
export { default as StaticImage} from './StaticImage/StaticImage'
|
||||||
export { default as EmptyCommon} from './EmptyCommon/EmptyCommon'
|
export { default as EmptyCommon} from './EmptyCommon/EmptyCommon'
|
||||||
export { default as CustomShapeSvg} from './CustomShapeSvg/CustomShapeSvg'
|
export { default as CustomShapeSvg} from './CustomShapeSvg/CustomShapeSvg'
|
||||||
|
export { default as RecommendedRecipes} from './RecommendedRecipes/RecommendedRecipes'
|
||||||
|
11
src/components/icons/IconNoti.tsx
Normal file
11
src/components/icons/IconNoti.tsx
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const IconNoti = () => {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="24" viewBox="0 0 20 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.0003 13.3763V9.66634C16.9986 8.01332 16.412 6.41422 15.3444 5.15224C14.2767 3.89027 12.7969 3.04684 11.167 2.77134V1.49967C11.167 1.19026 11.0441 0.893509 10.8253 0.674717C10.6065 0.455924 10.3097 0.333008 10.0003 0.333008C9.6909 0.333008 9.39416 0.455924 9.17537 0.674717C8.95657 0.893509 8.83366 1.19026 8.83366 1.49967V2.77134C7.20375 3.04684 5.72394 3.89027 4.65627 5.15224C3.58861 6.41422 3.002 8.01332 3.00033 9.66634V13.3763C2.31952 13.617 1.72982 14.0624 1.31209 14.6514C0.89435 15.2404 0.669022 15.9442 0.666992 16.6663V18.9997C0.666992 19.3091 0.789909 19.6058 1.0087 19.8246C1.22749 20.0434 1.52424 20.1663 1.83366 20.1663H5.49699C5.76566 21.1549 6.35216 22.0277 7.16602 22.6499C7.97988 23.2721 8.97587 23.6092 10.0003 23.6092C11.0248 23.6092 12.0208 23.2721 12.8346 22.6499C13.6485 22.0277 14.235 21.1549 14.5037 20.1663H18.167C18.4764 20.1663 18.7732 20.0434 18.9919 19.8246C19.2107 19.6058 19.3337 19.3091 19.3337 18.9997V16.6663C19.3316 15.9442 19.1063 15.2404 18.6886 14.6514C18.2708 14.0624 17.6811 13.617 17.0003 13.3763ZM5.33366 9.66634C5.33366 8.42866 5.82532 7.24168 6.70049 6.36651C7.57566 5.49134 8.76265 4.99967 10.0003 4.99967C11.238 4.99967 12.425 5.49134 13.3002 6.36651C14.1753 7.24168 14.667 8.42866 14.667 9.66634V13.1663H5.33366V9.66634ZM10.0003 21.333C9.59313 21.3305 9.19366 21.2216 8.84163 21.0169C8.48959 20.8122 8.19725 20.519 7.99366 20.1663H12.007C11.8034 20.519 11.5111 20.8122 11.159 21.0169C10.807 21.2216 10.4075 21.3305 10.0003 21.333ZM17.0003 17.833H3.00033V16.6663C3.00033 16.3569 3.12324 16.0602 3.34203 15.8414C3.56083 15.6226 3.85757 15.4997 4.16699 15.4997H15.8337C16.1431 15.4997 16.4398 15.6226 16.6586 15.8414C16.8774 16.0602 17.0003 16.3569 17.0003 16.6663V17.833Z" fill="#5B9A74" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconNoti
|
@@ -33,3 +33,4 @@ export { default as IconMinus } from './IconMinus'
|
|||||||
export { default as IconCirclePlus } from './IconCirclePlus'
|
export { default as IconCirclePlus } from './IconCirclePlus'
|
||||||
export { default as IconDoneCheckout } from './IconDoneCheckout'
|
export { default as IconDoneCheckout } from './IconDoneCheckout'
|
||||||
export { default as IconFilter } from './IconFilter'
|
export { default as IconFilter } from './IconFilter'
|
||||||
|
export { default as IconNoti } from './IconNoti'
|
@@ -11,14 +11,14 @@
|
|||||||
@apply grid;
|
@apply grid;
|
||||||
grid-template-columns: 1fr 1.8fr;
|
grid-template-columns: 1fr 1.8fr;
|
||||||
.left {
|
.left {
|
||||||
@apply relative flex items-end justify-center custom-border-radius-lg;
|
@apply relative flex items-end justify-center shape-common-lg;
|
||||||
margin-right: 1.6rem;
|
margin-right: 1.6rem;
|
||||||
.imgWrap {
|
.imgWrap {
|
||||||
@apply absolute w-full h-full;
|
@apply absolute w-full h-full;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
> div {
|
> div {
|
||||||
@apply w-full h-full custom-border-radius-lg;
|
@apply w-full h-full shape-common-lg;
|
||||||
}
|
}
|
||||||
img {
|
img {
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
@@ -1,9 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { Banner } from 'src/components/common'
|
import { Banner, StaticImage } from 'src/components/common'
|
||||||
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
import BannerImgRight from './assets/banner_full.png'
|
import BannerImgRight from './assets/banner_full.png'
|
||||||
import HomeBannerImg from './assets/home_banner.png'
|
import HomeBannerImg from './assets/home_banner.png'
|
||||||
import s from './HomeBanner.module.scss'
|
import s from './HomeBanner.module.scss'
|
||||||
import Image from 'next/image'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
@@ -15,7 +15,7 @@ const HomeBanner = ({ }: Props) => {
|
|||||||
<div className={s.homeBanner}>
|
<div className={s.homeBanner}>
|
||||||
<section className={s.left}>
|
<section className={s.left}>
|
||||||
<div className={s.imgWrap}>
|
<div className={s.imgWrap}>
|
||||||
<Image src={HomeBannerImg} placeholder='blur' />
|
<StaticImage src={HomeBannerImg} />
|
||||||
</div>
|
</div>
|
||||||
<div className={s.text}>
|
<div className={s.text}>
|
||||||
Freshness<br />guaranteed
|
Freshness<br />guaranteed
|
||||||
@@ -28,12 +28,14 @@ const HomeBanner = ({ }: Props) => {
|
|||||||
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
||||||
imgLink: BannerImgRight.src,
|
imgLink: BannerImgRight.src,
|
||||||
size: "small",
|
size: "small",
|
||||||
|
linkButton: ROUTE.PRODUCTS,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Save 15% on your first order 2",
|
title: "Save 15% on your first order 2",
|
||||||
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
||||||
imgLink: BannerImgRight.src,
|
imgLink: BannerImgRight.src,
|
||||||
size: "small",
|
size: "small",
|
||||||
|
linkButton: ROUTE.PRODUCTS,
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
.categoryItem {
|
.categoryItem {
|
||||||
.categoryItemImage {
|
.categoryItemImage {
|
||||||
@apply transition-all duration-200;
|
@apply flex justify-center items-center transition-all duration-200;
|
||||||
width: 10.6rem;
|
width: 10.6rem;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-height: 14rem;
|
max-height: 14rem;
|
||||||
|
@@ -4,6 +4,7 @@ import s from './CategoryItem.module.scss'
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import { StaticImage } from 'src/components/common';
|
||||||
|
|
||||||
interface CategoryItem {
|
interface CategoryItem {
|
||||||
image: StaticImageData,
|
image: StaticImageData,
|
||||||
@@ -17,7 +18,7 @@ const CategoryItem = ({ image, name, link }: CategoryItem) => {
|
|||||||
<div className={classNames(s.categoryItemImage)}>
|
<div className={classNames(s.categoryItemImage)}>
|
||||||
<Link href={link}>
|
<Link href={link}>
|
||||||
<a>
|
<a>
|
||||||
<Image src={image} />
|
<StaticImage src={image} />
|
||||||
</a>
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
margin: 3rem auto;
|
margin: 3rem auto;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
@apply relative spacing-horizontal;
|
@apply relative spacing-horizontal w-full;
|
||||||
|
|
||||||
padding-top: 1.6rem;
|
padding-top: 1.6rem;
|
||||||
padding-bottom: 1.6rem;
|
padding-bottom: 1.6rem;
|
||||||
@@ -15,7 +15,7 @@
|
|||||||
}
|
}
|
||||||
@screen md {
|
@screen md {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
margin: 5.6rem auto;
|
margin: 12.8rem auto;
|
||||||
|
|
||||||
&::before,
|
&::before,
|
||||||
&::after {
|
&::after {
|
||||||
|
@@ -0,0 +1,8 @@
|
|||||||
|
.productImgItem {
|
||||||
|
@apply w-full h-full;
|
||||||
|
min-height: 30rem;
|
||||||
|
img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { ImgWithLink } from 'src/components/common'
|
||||||
|
import s from './ProductImgItem.module.scss'
|
||||||
|
|
||||||
|
export interface ProductImgItemProps {
|
||||||
|
src: string
|
||||||
|
alt?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ProductImgItem = ({ src, alt }: ProductImgItemProps) => {
|
||||||
|
return (
|
||||||
|
<section className={s.productImgItem}>
|
||||||
|
<ImgWithLink src={src} alt={alt} />
|
||||||
|
</section >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProductImgItem
|
@@ -6,4 +6,7 @@
|
|||||||
@screen lg {
|
@screen lg {
|
||||||
max-width: 60rem;
|
max-width: 60rem;
|
||||||
}
|
}
|
||||||
|
> div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { CarouselCommon, ImgWithLink } from 'src/components/common'
|
import { CarouselCommon } from 'src/components/common'
|
||||||
import { ImgWithLinkProps } from 'src/components/common/ImgWithLink/ImgWithLink'
|
import ProductImgItem, { ProductImgItemProps } from '../ProductImgItem/ProductImgItem'
|
||||||
import s from './ProductImgs.module.scss'
|
import s from './ProductImgs.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -9,6 +9,10 @@ interface Props {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const DATA = [
|
const DATA = [
|
||||||
|
{
|
||||||
|
src: 'https://user-images.githubusercontent.com/76729908/133026929-199799fc-bd75-4445-a24d-15c0e41796eb.png',
|
||||||
|
alt: 'Meat',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png',
|
src: 'https://user-images.githubusercontent.com/76729908/130574371-3b75fa72-9552-4605-aba9-a4b31cd9dce7.png',
|
||||||
alt: 'Broccoli',
|
alt: 'Broccoli',
|
||||||
@@ -26,10 +30,10 @@ const option = {
|
|||||||
const ProductImgs = ({ }: Props) => {
|
const ProductImgs = ({ }: Props) => {
|
||||||
return (
|
return (
|
||||||
<section className={s.productImgs}>
|
<section className={s.productImgs}>
|
||||||
<CarouselCommon<ImgWithLinkProps>
|
<CarouselCommon<ProductImgItemProps>
|
||||||
data={DATA}
|
data={DATA}
|
||||||
itemKey="product-detail-img"
|
itemKey="product-detail-img"
|
||||||
Component={ImgWithLink}
|
Component={ProductImgItem}
|
||||||
option={option}
|
option={option}
|
||||||
isDot={true}
|
isDot={true}
|
||||||
/>
|
/>
|
||||||
@@ -38,3 +42,4 @@ const ProductImgs = ({ }: Props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default ProductImgs
|
export default ProductImgs
|
||||||
|
|
||||||
|
@@ -64,6 +64,12 @@
|
|||||||
margin-left: 0.8rem;
|
margin-left: 0.8rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
svg {
|
||||||
|
height: 2rem;
|
||||||
|
path {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
@apply w-full;
|
@apply w-full;
|
||||||
|
@@ -8,6 +8,7 @@ const ViewedProducts = () => {
|
|||||||
title="viewed Products"
|
title="viewed Products"
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
||||||
data={PRODUCT_DATA_TEST}
|
data={PRODUCT_DATA_TEST}
|
||||||
|
hasBorderBottomMobile={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
export { default as ProductInfoDetail } from './ProductInfoDetail/ProductInfoDetail'
|
export { default as ProductInfoDetail } from './ProductInfoDetail/ProductInfoDetail'
|
||||||
export { default as ViewedProducts } from './ViewedProducts/ViewedProducts'
|
export { default as ViewedProducts } from './ViewedProducts/ViewedProducts'
|
||||||
export { default as ReleventProducts } from './ReleventProducts/ReleventProducts'
|
export { default as ReleventProducts } from './ReleventProducts/ReleventProducts'
|
||||||
export { default as RecommendedRecipes } from './RecommendedRecipes/RecommendedRecipes'
|
|
||||||
|
@@ -16,7 +16,7 @@ const ProductListBanner = ({ }: Props) => {
|
|||||||
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
||||||
imgLink: BannerRight.src,
|
imgLink: BannerRight.src,
|
||||||
size: "large",
|
size: "large",
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
6
src/styles/_pages.scss
Normal file
6
src/styles/_pages.scss
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
.page-recipe-detail {
|
||||||
|
margin-bottom: 5.4rem;
|
||||||
|
@screen lg {
|
||||||
|
margin-bottom: 12.8rem;
|
||||||
|
}
|
||||||
|
}
|
@@ -121,12 +121,13 @@
|
|||||||
|
|
||||||
.shape-common-border {
|
.shape-common-border {
|
||||||
position: relative;
|
position: relative;
|
||||||
$border: 2px;
|
$border: 1px;
|
||||||
margin: $border;
|
margin: $border;
|
||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
background: var(--white);
|
background: var(--white);
|
||||||
clip-path: url(#svg-custom-shape);
|
clip-path: url(#svg-custom-shape);
|
||||||
|
margin: 1px;
|
||||||
}
|
}
|
||||||
&::before {
|
&::before {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -152,6 +153,7 @@
|
|||||||
|
|
||||||
.inner {
|
.inner {
|
||||||
padding: 2rem;
|
padding: 2rem;
|
||||||
|
margin: 1px;
|
||||||
clip-path: url(#svg-custom-shape-lg);
|
clip-path: url(#svg-custom-shape-lg);
|
||||||
}
|
}
|
||||||
&::before {
|
&::before {
|
||||||
|
@@ -5,3 +5,5 @@
|
|||||||
|
|
||||||
@import "~tailwindcss/utilities";
|
@import "~tailwindcss/utilities";
|
||||||
@import './utilities';
|
@import './utilities';
|
||||||
|
|
||||||
|
@import './pages'
|
||||||
|
@@ -9,19 +9,25 @@ export const SOCIAL_LINKS = {
|
|||||||
|
|
||||||
export const ROUTE = {
|
export const ROUTE = {
|
||||||
HOME: '/',
|
HOME: '/',
|
||||||
|
ABOUT: '/about',
|
||||||
|
ACCOUNT: '/account',
|
||||||
|
|
||||||
PRODUCTS: '/products',
|
PRODUCTS: '/products',
|
||||||
PRODUCT_DETAIL: '/product',
|
PRODUCT_DETAIL: '/product',
|
||||||
ABOUT: '/about',
|
|
||||||
|
BLOGS: '/blogs',
|
||||||
BLOG_DETAIL: '/blog',
|
BLOG_DETAIL: '/blog',
|
||||||
ACCOUNT: '/account',
|
|
||||||
RECIPES: '/recipes',
|
RECIPES: '/recipes',
|
||||||
|
RECIPE_DETAIL: '/recipe',
|
||||||
|
|
||||||
BUSSINESS: '/bussiness',
|
BUSSINESS: '/bussiness',
|
||||||
CONTACT: '/contact',
|
CONTACT: '/contact',
|
||||||
|
CHECKOUT: '/checkout',
|
||||||
FAQ: '/faq',
|
FAQ: '/faq',
|
||||||
CUSTOMER_SERVICE: '/customer-service',
|
CUSTOMER_SERVICE: '/customer-service',
|
||||||
TERM_CONDITION: '/term-condition',
|
TERM_CONDITION: '/term-condition',
|
||||||
PRIVACY_POLICY: '/privacy-policy',
|
PRIVACY_POLICY: '/privacy-policy',
|
||||||
BLOGS: '/blogs',
|
|
||||||
FORGOT_PASSWORD: '/forgot-password'
|
FORGOT_PASSWORD: '/forgot-password'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,6 +35,7 @@ export const ACCOUNT_TAB = {
|
|||||||
CUSTOMER_INFO: '',
|
CUSTOMER_INFO: '',
|
||||||
ORDER: 'orders',
|
ORDER: 'orders',
|
||||||
FAVOURITE: 'wishlist',
|
FAVOURITE: 'wishlist',
|
||||||
|
NOTIFICATION: 'notification',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const QUERY_KEY = {
|
export const QUERY_KEY = {
|
||||||
@@ -117,3 +124,14 @@ export const FEATURED = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
export const DEFAULT_BLOG_PAGE_SIZE=6;
|
export const DEFAULT_BLOG_PAGE_SIZE=6;
|
||||||
|
|
||||||
|
export const STATE_OPTIONS = [
|
||||||
|
{
|
||||||
|
name: 'Hồ Chí Minh',
|
||||||
|
value: 'Hồ Chí Minh',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Hà Nội',
|
||||||
|
value: 'Hà Nội',
|
||||||
|
},
|
||||||
|
]
|
@@ -1,5 +1,5 @@
|
|||||||
export function isMobile() {
|
export function isMobile() {
|
||||||
return window.innerWidth <= 768
|
return window.innerWidth < 768
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeItem<T>(arr: Array<T>, value: T): Array<T> {
|
export function removeItem<T>(arr: Array<T>, value: T): Array<T> {
|
||||||
|
@@ -106,9 +106,6 @@ module.exports = {
|
|||||||
fontSize: {
|
fontSize: {
|
||||||
base: ['16px', '24px'],
|
base: ['16px', '24px'],
|
||||||
},
|
},
|
||||||
borderRadius: {
|
|
||||||
rounded: '.8rem',
|
|
||||||
},
|
|
||||||
screens: {
|
screens: {
|
||||||
'sm-only': {'min': '0', 'max': '767px'},
|
'sm-only': {'min': '0', 'max': '767px'},
|
||||||
'sm': '640px',
|
'sm': '640px',
|
||||||
|
Reference in New Issue
Block a user