fix: fix css component MenuNavigation and fix conflic
@ -1 +0,0 @@
|
||||
Subproject commit 3c7aa8e862bfd8d44719be44c6c0a31ab01524a3
|
9989
package-lock.json
generated
@ -27,6 +27,8 @@
|
||||
"classnames": "^2.3.1",
|
||||
"cookie": "^0.4.1",
|
||||
"email-validator": "^2.0.4",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-next": "^11.1.2",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"js-cookie": "^2.2.1",
|
||||
"keen-slider": "^5.5.1",
|
||||
@ -66,6 +68,7 @@
|
||||
"@types/node": "^15.12.4",
|
||||
"@types/react": "^17.0.8",
|
||||
"deepmerge": "^4.2.2",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"graphql": "^15.5.1",
|
||||
"husky": "^6.0.0",
|
||||
"lint-staged": "^11.0.0",
|
||||
|
@ -1,6 +1,5 @@
|
||||
|
||||
import { Layout } from 'src/components/common';
|
||||
import { MenuNavigation,MenuFilter} from 'src/components/common';
|
||||
import { HomeBanner, HomeCategories, HomeCTA, HomeSubscribe, HomeVideo } from 'src/components/modules/home';
|
||||
import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||
const CATEGORY = [
|
||||
@ -32,13 +31,11 @@ const CATEGORY = [
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
{/* <HomeBanner />
|
||||
<HomeBanner />
|
||||
<HomeCategories/>
|
||||
<HomeVideo />
|
||||
<HomeCTA />
|
||||
<HomeSubscribe /> */}
|
||||
<MenuFilter categories={CATEGORY} heading="Categories"/>
|
||||
<MenuNavigation categories={CATEGORY} heading="Categories"/>
|
||||
<HomeSubscribe />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
81
pages/test.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
|
||||
import { Layout } from 'src/components/common';
|
||||
import { RecipesListPage } from 'src/components/modules/recipes';
|
||||
import { BlogDetailImg } from 'src/components/modules/blogs';
|
||||
import BlogDetail from '../src/components/modules/blogs/BlogDetailImg/img/blogdetail.png';
|
||||
import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||
import MenuNavigation from 'src/components/common/MenuNavigation/MenuNavigation';
|
||||
const CATEGORY = [
|
||||
{
|
||||
name: 'All',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=${OPTION_ALL}`,
|
||||
},
|
||||
{
|
||||
name: 'Veggie',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=veggie`,
|
||||
},
|
||||
{
|
||||
name: 'Seafood',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=seafood`,
|
||||
},
|
||||
{
|
||||
name: 'Frozen',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=frozen`,
|
||||
},
|
||||
{
|
||||
name: 'Coffee Bean',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=coffee-bean`,
|
||||
},
|
||||
{
|
||||
name: 'Sauce',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.CATEGORY}=sauce`,
|
||||
},
|
||||
];
|
||||
// const BRANDS = [
|
||||
|
||||
// {
|
||||
// name: 'Maggi',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=veggie`,
|
||||
// },
|
||||
// {
|
||||
// name: 'Chomilex',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chomilex`,
|
||||
// },
|
||||
// {
|
||||
// name: 'Chinsu',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.BRAND}=chinsu`,
|
||||
// }
|
||||
// ];
|
||||
|
||||
// const FEATURED = [
|
||||
|
||||
// {
|
||||
// name: 'Best Sellers',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=best-sellers`,
|
||||
// },
|
||||
// {
|
||||
// name: 'Sales',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=sales`,
|
||||
// },
|
||||
// {
|
||||
// name: 'New Item',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=new-item`,
|
||||
// },
|
||||
// {
|
||||
// name: 'Viewed',
|
||||
// link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.FEATURED}=viewed`,
|
||||
// }
|
||||
// ]
|
||||
export default function Test() {
|
||||
return (
|
||||
<>
|
||||
{/* <RecipesListPage/> */}
|
||||
{/* <MenuNavigationProductList categories={CATEGORY} brands={BRANDS} featured={FEATURED}/> */}
|
||||
{/* <MenuFilter categories={CATEGORY} heading="Categories"/> */}
|
||||
{/* <MenuNavigation categories={CATEGORY} heading="Categories"/> */}
|
||||
<MenuNavigation categories={CATEGORY} heading="Categories"/>
|
||||
{/* <BlogDetailImg image={BlogDetail}/> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
BIN
public/assets/bannerrecipes.png
Normal file
After Width: | Height: | Size: 780 KiB |
@ -0,0 +1,5 @@
|
||||
@import '../../../styles/utilities';
|
||||
|
||||
.breadcrumbCommon {
|
||||
color: var(--text-base);
|
||||
}
|
66
src/components/common/BreadcrumbCommon/BreadcrumbCommon.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import React from 'react'
|
||||
import s from './BreadcrumbCommon.module.scss'
|
||||
|
||||
import BreadcrumbItem from './components/BreadcrumbItem/BreadcrumbItem'
|
||||
import BreadcrumbSeparator from './components/BreadcrumbSeparator/BreadcrumbSeparator'
|
||||
|
||||
interface BreadcrumbCommonProps {
|
||||
crumbs: { link:string, name:string }[];
|
||||
showHomePage?: boolean;
|
||||
}
|
||||
|
||||
const BreadcrumbCommon = ({ crumbs, showHomePage=true } : BreadcrumbCommonProps) => {
|
||||
console.log(crumbs);
|
||||
return (
|
||||
<section className={s.breadcrumbCommon}>
|
||||
{
|
||||
showHomePage && crumbs[0].link==="/" && crumbs.map((crumb, i) => {
|
||||
if (i === 0) {
|
||||
return (
|
||||
<BreadcrumbItem key={crumb.name} text={crumb.name} href={crumb.link} />
|
||||
)
|
||||
}
|
||||
if (i === crumbs.length-1) {
|
||||
return (
|
||||
<BreadcrumbSeparator key={crumb.name}>
|
||||
<span>{crumb.name}</span>
|
||||
</BreadcrumbSeparator>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<BreadcrumbSeparator key={crumb.name}>
|
||||
<BreadcrumbItem text={crumb.name} href={crumb.link} />
|
||||
</BreadcrumbSeparator>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
{
|
||||
!showHomePage && crumbs.map((crumb, i) => {
|
||||
if (i === 0) {
|
||||
return
|
||||
}
|
||||
if (i === 1) {
|
||||
return (
|
||||
<BreadcrumbItem key={crumb.name} text={crumb.name} href={crumb.link} />
|
||||
)
|
||||
}
|
||||
if (i === crumbs.length-1) {
|
||||
return (
|
||||
<BreadcrumbSeparator key={crumb.name}>
|
||||
<span>{crumb.name}</span>
|
||||
</BreadcrumbSeparator>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<BreadcrumbSeparator key={crumb.name}>
|
||||
<BreadcrumbItem text={crumb.name} href={crumb.link} />
|
||||
</BreadcrumbSeparator>
|
||||
)
|
||||
})
|
||||
}
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
export default BreadcrumbCommon
|
@ -0,0 +1,17 @@
|
||||
import React from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
interface BreadcrumbItemProps {
|
||||
text: string;
|
||||
href: string;
|
||||
}
|
||||
|
||||
const BreadcrumbItem = ({ text, href }: BreadcrumbItemProps) => {
|
||||
return (
|
||||
<Link href={href}>
|
||||
<a>{text}</a>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default BreadcrumbItem
|
@ -0,0 +1,15 @@
|
||||
import React from 'react'
|
||||
|
||||
interface BreadcrumbSeparatorProps {
|
||||
children?: React.ReactNode
|
||||
}
|
||||
|
||||
const BreadcrumbSeparator = ({ children }: BreadcrumbSeparatorProps) => {
|
||||
return (
|
||||
<span>
|
||||
/ {children}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export default BreadcrumbSeparator
|
@ -30,8 +30,8 @@ const MenuFilter = ({heading,categories,type,onChangeValue}:Props)=> {
|
||||
},[active])
|
||||
|
||||
return (
|
||||
<section className={classNames(s.menuFilterWrapper)}>
|
||||
<h2 className={classNames(s.menuFilterHeading)}>{heading}</h2>
|
||||
<section className={s.menuFilterWrapper}>
|
||||
<h2 className={s.menuFilterHeading}>{heading}</h2>
|
||||
<ul className={s.menuFilterList}>
|
||||
{
|
||||
categories.map(item => <li key={item.name}>
|
||||
|
@ -13,6 +13,8 @@
|
||||
li{
|
||||
margin: 0.8rem 0;
|
||||
a{
|
||||
display:block;
|
||||
width:100%;
|
||||
color:var(--text-base);
|
||||
&:hover {
|
||||
@apply text-primary;
|
||||
|
@ -13,8 +13,8 @@ const MenuNavigation = ({heading,categories}:Props)=> {
|
||||
const router = useRouter()
|
||||
|
||||
return (
|
||||
<section className={classNames(s.menuNavigationWrapper)}>
|
||||
<h2 className={classNames(s.menuNavigationHeading)}>{heading}({categories.length})</h2>
|
||||
<section className={s.menuNavigationWrapper}>
|
||||
<h2 className={s.menuNavigationHeading}>{heading}({categories.length})</h2>
|
||||
<ul className={s.menuNavigationList}>
|
||||
{
|
||||
categories.map(item => <li key={item.name}
|
||||
|
@ -0,0 +1,22 @@
|
||||
.warpper{
|
||||
.item{
|
||||
@apply inline-flex items-center justify-center cursor-pointer;
|
||||
background-color: var(--gray);
|
||||
margin: 0 0.4rem;
|
||||
width: 3.2rem;
|
||||
height: 3.2rem;
|
||||
&.active{
|
||||
@apply border border-solid;
|
||||
border-color: var(--text-active);
|
||||
background-color: var(--white);
|
||||
}
|
||||
&.disable{
|
||||
svg{
|
||||
path{
|
||||
fill: var(--disabled)
|
||||
}
|
||||
}
|
||||
@apply text-disabled cursor-not-allowed;
|
||||
}
|
||||
}
|
||||
}
|
74
src/components/common/PaginationCommon/PaginationCommon.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import classNames from 'classnames'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { ArrowLeftSmall, ArrowRightSmall } from 'src/components/icons'
|
||||
import PaginationItem from './components/PaginationItem'
|
||||
import s from './PaginationCommon.module.scss'
|
||||
interface PaginationCommonProps {
|
||||
defaultCurrent?: number
|
||||
pageSize: number
|
||||
total: number
|
||||
onChange?: (page: number, pageSize: number) => void
|
||||
}
|
||||
|
||||
const PaginationCommon = ({
|
||||
total,
|
||||
pageSize,
|
||||
defaultCurrent,
|
||||
onChange,
|
||||
}: PaginationCommonProps) => {
|
||||
const [pageNum, setPageNum] = useState<number>(0)
|
||||
const [currentPage, setCurrentPage] = useState<number>(0)
|
||||
useEffect(() => {
|
||||
setPageNum(Math.ceil(total / pageSize))
|
||||
}, [total, pageSize])
|
||||
|
||||
useEffect(() => {
|
||||
if (defaultCurrent) {
|
||||
setCurrentPage(defaultCurrent)
|
||||
}
|
||||
}, [defaultCurrent])
|
||||
|
||||
const onPageClick = (page: number) => {
|
||||
setCurrentPage(page)
|
||||
onChange && onChange(page, pageSize)
|
||||
}
|
||||
|
||||
const onPrevClick = () => {
|
||||
setCurrentPage(currentPage - 1 < 0 ? 0 : currentPage - 1)
|
||||
}
|
||||
|
||||
const onNextClick = () => {
|
||||
setCurrentPage((currentPage + 1) > (pageNum - 1) ? (pageNum - 1) : currentPage + 1)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={s.warpper}>
|
||||
<div
|
||||
className={classNames(s.item, { [`${s.disable}`]: currentPage <= 0 })}
|
||||
onClick={onPrevClick}
|
||||
>
|
||||
<ArrowLeftSmall disable={currentPage <= 0} />
|
||||
</div>
|
||||
{[...Array(pageNum).keys()].map((index) => {
|
||||
return (
|
||||
<PaginationItem
|
||||
page={index}
|
||||
onClick={onPageClick}
|
||||
key={`${index}-item`}
|
||||
active={index === currentPage}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
<div
|
||||
className={classNames(s.item, {
|
||||
[`${s.disable}`]: currentPage >= pageNum - 1,
|
||||
})}
|
||||
onClick={onNextClick}
|
||||
>
|
||||
<ArrowRightSmall disable={currentPage >= pageNum} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationCommon
|
@ -0,0 +1,21 @@
|
||||
import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
import s from "../PaginationCommon.module.scss"
|
||||
interface PaginationItemProps {
|
||||
onClick:(page:number)=>void
|
||||
page:number
|
||||
active:boolean
|
||||
}
|
||||
|
||||
const PaginationItem = ({onClick, page, active}: PaginationItemProps) => {
|
||||
const onPageClick = () => {
|
||||
onClick && onClick(page)
|
||||
}
|
||||
return (
|
||||
<div onClick={onPageClick} className={classNames(s.item,{[`${s.active}`]:active})}>
|
||||
{page+1}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PaginationItem
|
18
src/components/icons/ArrowLeftSmall.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
const ArrowLeft = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="8"
|
||||
height="12"
|
||||
viewBox="0 0 8 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M3.28982 6.00019L6.82982 2.46019C7.01607 2.27283 7.12061 2.01938 7.12061 1.75519C7.12061 1.49101 7.01607 1.23756 6.82982 1.05019C6.73686 0.956464 6.62626 0.88207 6.5044 0.831301C6.38254 0.780533 6.25183 0.754395 6.11982 0.754395C5.98781 0.754395 5.8571 0.780533 5.73524 0.831301C5.61339 0.88207 5.50278 0.956464 5.40982 1.05019L1.16982 5.29019C1.07609 5.38316 1.0017 5.49376 0.950931 5.61562C0.900162 5.73747 0.874023 5.86818 0.874023 6.00019C0.874023 6.1322 0.900162 6.26291 0.950931 6.38477C1.0017 6.50663 1.07609 6.61723 1.16982 6.71019L5.40982 11.0002C5.50326 11.0929 5.61408 11.1662 5.73592 11.216C5.85775 11.2657 5.98821 11.291 6.11982 11.2902C6.25143 11.291 6.38189 11.2657 6.50373 11.216C6.62557 11.1662 6.73638 11.0929 6.82982 11.0002C7.01607 10.8128 7.12061 10.5594 7.12061 10.2952C7.12061 10.031 7.01607 9.77756 6.82982 9.59019L3.28982 6.00019Z"
|
||||
fill="#141414"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default ArrowLeft
|
18
src/components/icons/ArrowRightSmall.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
const ArrowRight = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="8"
|
||||
height="12"
|
||||
viewBox="0 0 8 12"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.8297 5.29019L2.5897 1.05019C2.49674 0.956464 2.38613 0.88207 2.26428 0.831301C2.14242 0.780533 2.01171 0.754395 1.8797 0.754395C1.74769 0.754395 1.61698 0.780533 1.49512 0.831301C1.37326 0.88207 1.26266 0.956464 1.1697 1.05019C0.983448 1.23756 0.878906 1.49101 0.878906 1.75519C0.878906 2.01938 0.983448 2.27283 1.1697 2.46019L4.7097 6.00019L1.1697 9.54019C0.983448 9.72756 0.878906 9.98101 0.878906 10.2452C0.878906 10.5094 0.983448 10.7628 1.1697 10.9502C1.26314 11.0429 1.37395 11.1162 1.49579 11.166C1.61763 11.2157 1.74809 11.241 1.8797 11.2402C2.01131 11.241 2.14177 11.2157 2.26361 11.166C2.38544 11.1162 2.49626 11.0429 2.5897 10.9502L6.8297 6.71019C6.92343 6.61723 6.99782 6.50663 7.04859 6.38477C7.09936 6.26291 7.1255 6.1322 7.1255 6.00019C7.1255 5.86818 7.09936 5.73747 7.04859 5.61562C6.99782 5.49376 6.92343 5.38316 6.8297 5.29019Z"
|
||||
fill="#141414"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default ArrowRight
|
12
src/components/icons/IconHide.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react'
|
||||
|
||||
const IconHide = () => {
|
||||
return (
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M18 6L6 18" stroke="#2F2F2F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6 6L18 18" stroke="#2F2F2F" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconHide
|
@ -9,3 +9,6 @@ export { default as IconHome } from './IconHome'
|
||||
export { default as IconShopping } from './IconShopping'
|
||||
export { default as IconHeart } from './IconHeart'
|
||||
export { default as IconVector } from './IconVector'
|
||||
export { default as IconHide } from './IconHide'
|
||||
export { default as ArrowLeftSmall } from './ArrowLeftSmall'
|
||||
export { default as ArrowRightSmall } from './ArrowRightSmall'
|
16
src/components/modules/blogs/BlogContent/BlogContent.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import { DateTime } from "src/components/common";
|
||||
|
||||
interface Props{
|
||||
image:StaticImageData,
|
||||
}
|
||||
|
||||
const BlogContent = ({}:Props) => {
|
||||
return (
|
||||
<>
|
||||
<DateTime date="APRIL 30, 2021"/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default BlogContent
|
18
src/components/modules/blogs/BlogDetailImg/BlogDetailImg.tsx
Normal file
@ -0,0 +1,18 @@
|
||||
import Image from "next/image";
|
||||
import React from 'react';
|
||||
|
||||
interface Props{
|
||||
image:StaticImageData,
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BlogDetailImg = ({image}:Props) => {
|
||||
return (
|
||||
<>
|
||||
<Image src={image} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default BlogDetailImg
|
BIN
src/components/modules/blogs/BlogDetailImg/img/blogdetail.png
Normal file
After Width: | Height: | Size: 709 KiB |
1
src/components/modules/blogs/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as BlogDetailImg } from './BlogDetailImg/BlogDetailImg'
|
@ -0,0 +1,64 @@
|
||||
@import "../../../../../styles/_utilities";
|
||||
|
||||
.recipesItem {
|
||||
@apply flex justify-between;
|
||||
margin: 1.5rem 0;
|
||||
|
||||
@screen md{
|
||||
@apply block;
|
||||
}
|
||||
|
||||
.recipesItemImage {
|
||||
@apply transition-all duration-200;
|
||||
width: 31%;
|
||||
img {
|
||||
@apply block object-cover;
|
||||
width: 100%;
|
||||
min-height: 12.5rem;
|
||||
border-radius: 1.5rem;
|
||||
}
|
||||
|
||||
@screen md {
|
||||
@apply object-cover cursor-pointer;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
img{
|
||||
height:100%;
|
||||
border-radius: 2.4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.recipesItemText {
|
||||
width: 65%;
|
||||
.recipesItemName{
|
||||
@apply topline;
|
||||
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
-webkit-box-orient: vertical;
|
||||
|
||||
font-feature-settings: "salt" on;
|
||||
cursor: pointer;
|
||||
font-weight:bold;
|
||||
color:var(--text-active);
|
||||
margin-bottom: 1rem;
|
||||
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
@screen md {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.recipesItemDescription{
|
||||
color:var(--text-label);
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
import s from './RecipesItem.module.scss'
|
||||
import classNames from 'classnames';
|
||||
import Image from "next/image";
|
||||
import Link from 'next/link';
|
||||
|
||||
interface RecipesItem {
|
||||
image:StaticImageData,
|
||||
name: string,
|
||||
description:string,
|
||||
link: string
|
||||
}
|
||||
|
||||
const RecipesItem = ({ image, name,description, link }: RecipesItem) => {
|
||||
return (
|
||||
<div className={classNames(s.recipesItem)}>
|
||||
<div className={classNames(s.recipesItemImage)}>
|
||||
<Link href={link}>
|
||||
<a>
|
||||
<Image src={image} />
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<Link href={link}>
|
||||
<a className={classNames(s.recipesItemText)}>
|
||||
<div className={classNames(s.recipesItemName)}>{name}</div>
|
||||
<div className={classNames(s.recipesItemDescription)}>{description}</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
export default RecipesItem
|
@ -0,0 +1,43 @@
|
||||
@import "../../../../styles/_utilities";
|
||||
|
||||
.recipesListWrapper {
|
||||
@screen md{
|
||||
padding-bottom:5.6rem;
|
||||
}
|
||||
.recipesHead{
|
||||
@apply flex justify-end;
|
||||
@screen md{
|
||||
@apply justify-between;
|
||||
}
|
||||
}
|
||||
.recipesListBlogs{
|
||||
@screen md {
|
||||
@apply flex flex-col items-center justify-center;
|
||||
}
|
||||
.recipesList {
|
||||
@screen md {
|
||||
@apply flex justify-between flex-wrap;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
.recipesItem {
|
||||
@screen md {
|
||||
width: calc(97% / 2);
|
||||
margin-top:4rem;
|
||||
}
|
||||
@screen lg{
|
||||
width: calc(97% / 3);
|
||||
margin-top:4rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.recipesPagination{
|
||||
@apply flex justify-center;
|
||||
margin: 3rem 0;
|
||||
@screen md {
|
||||
@apply flex justify-center;
|
||||
margin:2rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
51
src/components/modules/recipes/RecipesList/RecipesList.tsx
Normal file
@ -0,0 +1,51 @@
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
|
||||
import s from './RecipesList.module.scss';
|
||||
import RecipesItem from './RecipesItem/RecipesItem';
|
||||
|
||||
import { PaginationCommon } from 'src/components/common';
|
||||
|
||||
interface Props{
|
||||
recipes:{
|
||||
id:string,
|
||||
title:string,
|
||||
image:StaticImageData,
|
||||
description:string,
|
||||
link:string
|
||||
}[],
|
||||
}
|
||||
|
||||
|
||||
|
||||
const RecipesList = ({recipes}:Props) => {
|
||||
return (
|
||||
<>
|
||||
<div className={classNames(s.recipesListWrapper)}>
|
||||
<div className={classNames(s.recipesHead)}>
|
||||
|
||||
</div>
|
||||
|
||||
<div className={classNames(s.recipesListBlogs)}>
|
||||
<div className={classNames(s.recipesList)}>
|
||||
{recipes?.map(item => (
|
||||
<div key={item.id} className={classNames(s.recipesItem)}>
|
||||
<RecipesItem
|
||||
name={item.title}
|
||||
image={item.image}
|
||||
description={item.description}
|
||||
link={item.link}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={classNames(s.recipesPagination)}>
|
||||
<PaginationCommon pageSize={6} total={9}/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
export default RecipesList
|
@ -0,0 +1,79 @@
|
||||
@import "../../../../styles/_utilities";
|
||||
.recipesListPageWrapper{
|
||||
@apply spacing-horizontal;
|
||||
|
||||
@screen md {
|
||||
padding:0 3.2rem;
|
||||
}
|
||||
|
||||
.recipesListPageBreadcrumbDesktop{
|
||||
@apply hidden;
|
||||
@screen md {
|
||||
@apply block;
|
||||
}
|
||||
}
|
||||
.recipesListPageHeadMobile{
|
||||
margin-top: 2rem;
|
||||
h2{
|
||||
margin-bottom: 0.7rem;
|
||||
}
|
||||
@screen md {
|
||||
@apply hidden;
|
||||
padding: 3rem 0;
|
||||
}
|
||||
}
|
||||
.recipesListPageMain{
|
||||
@screen md {
|
||||
@apply flex;
|
||||
}
|
||||
.categoriesDesktop{
|
||||
@apply hidden;
|
||||
@screen md {
|
||||
@apply block;
|
||||
width:25%;
|
||||
}
|
||||
}
|
||||
.sortByMobile{
|
||||
@apply flex justify-end;
|
||||
}
|
||||
.categoriesMobile{
|
||||
ul{
|
||||
@apply flex-nowrap ;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
.recipesList{
|
||||
@screen md {
|
||||
width:75%;
|
||||
}
|
||||
.sortByDesktop{
|
||||
@apply hidden;
|
||||
@screen md {
|
||||
@apply flex justify-between;
|
||||
margin-top:1.5rem;
|
||||
h2{
|
||||
@apply heading-3;
|
||||
}
|
||||
}
|
||||
@screen xl{
|
||||
@apply flex justify-between;
|
||||
h2{
|
||||
@apply heading-2;
|
||||
}
|
||||
}
|
||||
}
|
||||
.selectMobile{
|
||||
@apply flex justify-between;
|
||||
margin: 2rem 0;
|
||||
label{
|
||||
@apply topline;
|
||||
font-weight: bold;
|
||||
}
|
||||
@screen md {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,175 @@
|
||||
import classNames from 'classnames';
|
||||
import React from 'react';
|
||||
import s from './RecipesListPage.module.scss';
|
||||
import RecipesList from '../RecipesList/RecipesList';
|
||||
import { Banner, MenuFilter } from 'src/components/common';
|
||||
import {MenuNavigation} from 'src/components/common';
|
||||
import { OPTION_ALL, QUERY_KEY, ROUTE } from 'src/utils/constanst.utils'
|
||||
import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbCommon';
|
||||
import HeadingCommon from "../../../common/HeadingCommon/HeadingCommon";
|
||||
import { SelectCommon } from 'src/components/common';
|
||||
import {RECIPE_DATA_TEST} from '../../../../utils/demo-data';
|
||||
|
||||
import blog1 from './img/blog1.png';
|
||||
import blog2 from './img/blog2.png';
|
||||
import blog3 from './img/blog3.png';
|
||||
import blog4 from './img/blog4.png';
|
||||
import blog5 from './img/blog5.png';
|
||||
import blog6 from './img/blog6.png';
|
||||
|
||||
const BREADCRUMB = [
|
||||
{
|
||||
name: 'Home',
|
||||
link: "/",
|
||||
},
|
||||
{
|
||||
name: 'Special Recipes',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=malaysia`,
|
||||
},
|
||||
];
|
||||
|
||||
const CATEGORY = [
|
||||
{
|
||||
name: 'All',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=${OPTION_ALL}`,
|
||||
},
|
||||
{
|
||||
name: 'Malaysian',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=malaysia`,
|
||||
},
|
||||
{
|
||||
name: 'Vietnamese',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=vietnamese`,
|
||||
},
|
||||
{
|
||||
name: 'Thailand',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=thailand`,
|
||||
},
|
||||
{
|
||||
name: 'Indian',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=indian`,
|
||||
},
|
||||
{
|
||||
name: 'Lao',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=lao`,
|
||||
},
|
||||
{
|
||||
name: 'Chinese',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=chinese`,
|
||||
},
|
||||
{
|
||||
name: 'Korean',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=korean`,
|
||||
},
|
||||
{
|
||||
name: 'Japanese',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=japanese`,
|
||||
},
|
||||
{
|
||||
name: 'Western',
|
||||
link: `${ROUTE.PRODUCTS}/?${QUERY_KEY.RECIPES}=western`,
|
||||
},
|
||||
];
|
||||
|
||||
const RECIPES = [
|
||||
{
|
||||
id: '1',
|
||||
image: blog1,
|
||||
title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners",
|
||||
description: 'The DEBM diet stands for "Delicious Happy Fun Diet". This diet was popularized by Robert...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=veggie`
|
||||
}, {
|
||||
id: '2',
|
||||
image: blog2,
|
||||
title: "9 Ways to Make an Aloe Vera Mask at Home",
|
||||
description: 'Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=seafood`
|
||||
}
|
||||
, {
|
||||
id: '3',
|
||||
image: blog3,
|
||||
title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit",
|
||||
description: 'Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=coffee-bean`
|
||||
}
|
||||
, {
|
||||
id: '4',
|
||||
image: blog4,
|
||||
title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners",
|
||||
description: 'The DEBM diet stands for "Delicious Happy Fun Diet". This diet was popularized by Robert...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=sauce`,
|
||||
}, {
|
||||
id: '5',
|
||||
image: blog5,
|
||||
title: "9 Ways to Make an Aloe Vera Mask at Home",
|
||||
description: 'Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=sauce`,
|
||||
}
|
||||
, {
|
||||
id: '6',
|
||||
image: blog6,
|
||||
title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit",
|
||||
description: 'Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...',
|
||||
link: `${ROUTE.PRODUCTS}?${QUERY_KEY.RECIPES}=sauce`,
|
||||
}
|
||||
];
|
||||
|
||||
const OPTIONSLECT=[
|
||||
{
|
||||
name:"SORT BY 1"
|
||||
},
|
||||
{
|
||||
name:"SORT BY 2"
|
||||
},
|
||||
{
|
||||
name:"SORT BY 3"
|
||||
},
|
||||
]
|
||||
|
||||
const RecipesListPage = () => {
|
||||
return (
|
||||
<div className={classNames(s.recipesListPageWrapper)}>
|
||||
|
||||
<Banner title={'SPECIAL RECIPE OF THE WEEK'} subtitle={'Last call! Shop deep deals on 100+ bulk picks while you can.'} imgLink={'assets/bannerrecipes.png'} size="large"/>
|
||||
|
||||
<div className={classNames(s.recipesListPageBreadcrumbDesktop)}>
|
||||
<BreadcrumbCommon crumbs={BREADCRUMB} />
|
||||
</div>
|
||||
|
||||
<div className={classNames(s.recipesListPageHeadMobile)}>
|
||||
<div className={classNames(s.heading)}>
|
||||
<HeadingCommon align='left'>SPECIAL RECIPES</HeadingCommon>
|
||||
<BreadcrumbCommon crumbs={BREADCRUMB} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classNames(s.recipesListPageMain)}>
|
||||
|
||||
<div className={classNames(s.categoriesDesktop)}>
|
||||
<MenuNavigation categories={CATEGORY} heading="Categories"/>
|
||||
</div>
|
||||
|
||||
<div className={classNames(s.recipesList)}>
|
||||
<div className={classNames(s.sortByDesktop)}>
|
||||
<HeadingCommon align='left'>SPECIAL RECIPES</HeadingCommon>
|
||||
<SelectCommon option={OPTIONSLECT} placeHolder="SORT BY"/>
|
||||
</div>
|
||||
<div className={classNames(s.selectMobile)}>
|
||||
<div>
|
||||
<label htmlFor="">Categories</label>
|
||||
<SelectCommon option={CATEGORY} placeHolder="Categories"/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="">Sort By</label>
|
||||
<SelectCommon option={OPTIONSLECT} placeHolder="Sort by"/>
|
||||
</div>
|
||||
</div>
|
||||
<RecipesList recipes={RECIPES}/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RecipesListPage
|
BIN
src/components/modules/recipes/RecipesListPage/img/blog1.png
Normal file
After Width: | Height: | Size: 169 KiB |
BIN
src/components/modules/recipes/RecipesListPage/img/blog2.png
Normal file
After Width: | Height: | Size: 152 KiB |
BIN
src/components/modules/recipes/RecipesListPage/img/blog3.png
Normal file
After Width: | Height: | Size: 94 KiB |
BIN
src/components/modules/recipes/RecipesListPage/img/blog4.png
Normal file
After Width: | Height: | Size: 180 KiB |
BIN
src/components/modules/recipes/RecipesListPage/img/blog5.png
Normal file
After Width: | Height: | Size: 187 KiB |
BIN
src/components/modules/recipes/RecipesListPage/img/blog6.png
Normal file
After Width: | Height: | Size: 198 KiB |
1
src/components/modules/recipes/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default as RecipesListPage } from './RecipesListPage/RecipesListPage'
|
@ -30,7 +30,9 @@ export const QUERY_KEY = {
|
||||
TAB: 'tab',
|
||||
CATEGORY: 'category',
|
||||
BRAND: 'brand',
|
||||
FEATURED: 'feature'
|
||||
FEATURED: 'feature',
|
||||
SORTBY:'sortby',
|
||||
RECIPES:'recipes'
|
||||
}
|
||||
|
||||
export enum ProductFeature {
|
||||
|
44
src/utils/demo-data.ts
Normal file
@ -0,0 +1,44 @@
|
||||
export const RECIPE_DATA_TEST= [
|
||||
{
|
||||
id: '1',
|
||||
title: "Special Recipe of Vietnamese Phở",
|
||||
description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
||||
link:'#'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: "Original Recipe of Curry",
|
||||
description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
||||
link:'#'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: "The Best Recipe of Beef Noodle Soup",
|
||||
description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
||||
link:'#'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: "Special Recipe of Vietnamese Phở",
|
||||
description: "Alright, before we get to the actual recipe, let’s chat for a sec about the ingredients. To make this pho soup recipe, you will need:",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159257-f92574c7-d00d-4142-8ea7-0ca9515fb737.png',
|
||||
link:'#'
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: "Original Recipe of Curry",
|
||||
description: "Chicken curry is common to several countries including India, countries in Asia and the Caribbean. My favorite of them though is this aromatic Indian...",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159259-ae4c986d-ab53-4758-9137-d06bafdd15d0.png',
|
||||
link:'#'
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: "The Best Recipe of Beef Noodle Soup",
|
||||
description: "The broth for Bun Bo Hue is prepared by slowly simmering various types of beef and pork bones (ox tail, beef shank, pork neck bones, pork feet,...",
|
||||
image: 'https://user-images.githubusercontent.com/76729908/132159262-f28a9fb9-4852-47e6-80b5-d600521b548a.png',
|
||||
link:'#'
|
||||
},
|
||||
]
|
@ -2,6 +2,7 @@ export const LANGUAGE = {
|
||||
BUTTON_LABEL: {
|
||||
BUY_NOW: 'Buy now',
|
||||
SHOP_NOW: 'Shop now',
|
||||
CONFIRM:'Confirm'
|
||||
},
|
||||
PLACE_HOLDER: {
|
||||
SEARCH: 'Search',
|
||||
|