mirror of
https://github.com/vercel/commerce.git
synced 2025-07-04 04:01:21 +00:00
✨ feat: product caroucel
:%s
This commit is contained in:
commit
7a5c5657fe
@ -1,27 +1,88 @@
|
||||
|
||||
import { Layout, ProductCard } from 'src/components/common'
|
||||
import {CarouselCommon } from 'src/components/common'
|
||||
import image1 from "../public/assets/images/image5.png"
|
||||
import ProductCaroucel from 'src/components/common/ProductCaroucel/ProductCaroucel'
|
||||
import image5 from "../public/assets/images/image5.png"
|
||||
import image6 from "../public/assets/images/image6.png"
|
||||
import image7 from "../public/assets/images/image7.png"
|
||||
import image8 from "../public/assets/images/image8.png"
|
||||
const dataTest = [{
|
||||
text:1
|
||||
name:"Tomato",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image5.src
|
||||
},{
|
||||
text:2
|
||||
name:"Cucumber",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image6.src
|
||||
},{
|
||||
text:3
|
||||
name:"Carrot",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image7.src
|
||||
},{
|
||||
text:4
|
||||
name:"Salad",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image8.src
|
||||
},{
|
||||
text:5
|
||||
name:"Tomato",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image5.src
|
||||
},{
|
||||
text:6
|
||||
name:"Cucumber",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image6.src
|
||||
},{
|
||||
name:"Tomato",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image5.src
|
||||
},{
|
||||
name:"Cucumber",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image6.src
|
||||
},{
|
||||
name:"Carrot",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image7.src
|
||||
},{
|
||||
name:"Salad",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image8.src
|
||||
},{
|
||||
name:"Tomato",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image5.src
|
||||
},{
|
||||
name:"Cucumber",
|
||||
weight:"250g",
|
||||
category:"VEGGIE",
|
||||
price:"Rp 27.500",
|
||||
imageSrc:image6.src
|
||||
}]
|
||||
const test = (props:{text:string})=><div className="h-64 bg-yellow-300">{props.text}</div>
|
||||
export default function Home() {
|
||||
return (
|
||||
<>
|
||||
<CarouselCommon data={dataTest} Component={test} itemKey="test"/>
|
||||
|
||||
<ProductCard name="tomato" weight = "250g" category ="VEGGIE" price="Rp 27.500" imageSrc={image1.src}/>
|
||||
<ProductCaroucel data={dataTest} itemKey="product-1" />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -53,11 +53,11 @@
|
||||
|
||||
&.ghost {
|
||||
@apply bg-white;
|
||||
color: var(--primary);
|
||||
border: 1px solid var(--primary);
|
||||
color: var(--text-active);
|
||||
border: 1px solid var(--text-active);
|
||||
&.loading {
|
||||
&::before {
|
||||
border-top-color: var(--primary);
|
||||
border-top-color: var(--text-active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,25 @@
|
||||
.navigation_wrapper{
|
||||
@import '../../../styles/utilities';
|
||||
.navigationWrapper{
|
||||
@apply relative;
|
||||
min-height: theme("caroucel.arrow-height") ;
|
||||
|
||||
.isPadding{
|
||||
@apply spacing-horizontal;
|
||||
}
|
||||
:global(.customArrow) {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
&:focus{
|
||||
outline: none;
|
||||
}
|
||||
@apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100;
|
||||
&:global(.leftArrow){
|
||||
@apply left-0;
|
||||
}
|
||||
&:global(.rightArrow){
|
||||
@apply right-0;
|
||||
}
|
||||
&:global(.isDisabledArrow){
|
||||
@apply hidden ;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,30 @@
|
||||
import { useKeenSlider } from 'keen-slider/react'
|
||||
import React from 'react'
|
||||
import 'keen-slider/keen-slider.min.css'
|
||||
import { CustomCarouselArrow } from './CustomArrow/CustomCarouselArrow';
|
||||
import s from "./CaroucelCommon.module.scss"
|
||||
interface CarouselCommonProps {
|
||||
children?: React.ReactNode
|
||||
data?: any[]
|
||||
Component: React.ComponentType<any>
|
||||
isArrow?:Boolean
|
||||
itemKey:String
|
||||
import { CustomCarouselArrow } from './CustomArrow/CustomCarouselArrow'
|
||||
import s from './CaroucelCommon.module.scss'
|
||||
import { TOptionsEvents } from 'keen-slider'
|
||||
import classNames from 'classnames'
|
||||
export interface CarouselCommonProps<T> {
|
||||
data: T[]
|
||||
Component: React.ComponentType<T>
|
||||
isArrow?: Boolean
|
||||
itemKey: String
|
||||
option: TOptionsEvents
|
||||
keenClassname?: string
|
||||
isPadding?: boolean
|
||||
}
|
||||
|
||||
const CarouselCommon = ({ data, Component,itemKey }: CarouselCommonProps) => {
|
||||
const CarouselCommon = <T,>({
|
||||
data,
|
||||
Component,
|
||||
itemKey,
|
||||
keenClassname,isPadding=false,
|
||||
option: { slideChanged, ...sliderOption },
|
||||
}: CarouselCommonProps<T>) => {
|
||||
const [currentSlide, setCurrentSlide] = React.useState(0)
|
||||
const [sliderRef, slider] = useKeenSlider<HTMLDivElement>({
|
||||
slidesPerView: 1,
|
||||
initial: 0,
|
||||
...sliderOption,
|
||||
slideChanged(s) {
|
||||
setCurrentSlide(s.details().relativeSlide)
|
||||
},
|
||||
@ -28,28 +37,28 @@ const CarouselCommon = ({ data, Component,itemKey }: CarouselCommonProps) => {
|
||||
slider.prev()
|
||||
}
|
||||
return (
|
||||
<div className={s.navigation_wrapper}>
|
||||
<div ref={sliderRef} className="keen-slider">
|
||||
{data?.map((props,index) => (
|
||||
<div className={s.navigationWrapper}>
|
||||
<div ref={sliderRef} className={classNames('keen-slider', keenClassname,{[s.isPadding]:isPadding})}>
|
||||
{data?.map((props, index) => (
|
||||
<div className="keen-slider__slide" key={`${itemKey}-${index}`}>
|
||||
<Component {...props} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{slider && (
|
||||
<>
|
||||
<CustomCarouselArrow
|
||||
side="right"
|
||||
onClick={handleRightArrowClick}
|
||||
isDisabled={currentSlide === slider.details().size - 1}
|
||||
/>
|
||||
<CustomCarouselArrow
|
||||
side="left"
|
||||
onClick={handleLeftArrowClick}
|
||||
isDisabled={currentSlide === 0}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<>
|
||||
<CustomCarouselArrow
|
||||
side="right"
|
||||
onClick={handleRightArrowClick}
|
||||
// isDisabled={currentSlide === slider.details().size - 1}
|
||||
/>
|
||||
<CustomCarouselArrow
|
||||
side="left"
|
||||
onClick={handleLeftArrowClick}
|
||||
// isDisabled={currentSlide === 0}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -1,17 +1,37 @@
|
||||
.custom_arrow{
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
&:focus{
|
||||
outline: none;
|
||||
}
|
||||
@apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100;
|
||||
&.left{
|
||||
@apply left-0;
|
||||
}
|
||||
&.right{
|
||||
@apply right-0;
|
||||
}
|
||||
&.isDisabled{
|
||||
@apply hidden ;
|
||||
// .customArrow{
|
||||
// width: 64px;
|
||||
// height: 64px;
|
||||
// &:focus{
|
||||
// outline: none;
|
||||
// }
|
||||
// @apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100;
|
||||
// &.leftArrow{
|
||||
// @apply left-0;
|
||||
// }
|
||||
// &.rightArrow{
|
||||
// @apply right-0;
|
||||
// }
|
||||
// &.isDisabled{
|
||||
// @apply hidden ;
|
||||
// }
|
||||
// }
|
||||
.navigationWrapper{
|
||||
:global(.customArrow) {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
&:focus{
|
||||
outline: none;
|
||||
}
|
||||
@apply absolute top-1/2 bg-background-arrow transform -translate-y-1/2 flex justify-center items-center transition duration-100;
|
||||
&.leftArrow{
|
||||
@apply left-0;
|
||||
}
|
||||
&.rightArrow{
|
||||
@apply right-0;
|
||||
}
|
||||
&.isDisabled{
|
||||
@apply hidden ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,11 +2,13 @@ import classNames from 'classnames'
|
||||
import React from 'react'
|
||||
import ArrowLeft from 'src/components/icons/ArrowLeft'
|
||||
import ArrowRight from 'src/components/icons/ArrowRight'
|
||||
import s from "./CustomCarouselArrow.module.scss"
|
||||
import "./CustomCarouselArrow.module.scss"
|
||||
// import s from "../CaroucelCommon.module.scss"
|
||||
|
||||
interface CustomCarouselArrowProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
side: 'left' | 'right'
|
||||
isDisabled:Boolean
|
||||
isDisabled?:Boolean
|
||||
}
|
||||
|
||||
export const CustomCarouselArrow = ({
|
||||
@ -16,7 +18,8 @@ export const CustomCarouselArrow = ({
|
||||
return (
|
||||
<button
|
||||
{...props}
|
||||
className={classNames(`${s.custom_arrow}`, { [`${s[side]}`]: side,[`${s.isDisabled}`]:isDisabled })}
|
||||
// className={classNames(`${s.customArrow}`, { [`${s[`${side}Arrow`]}`]: side,[`${s.isDisabled}`]:isDisabled })}
|
||||
className={classNames("customArrow", { [`${side}Arrow`]: side,"isDisabledArrow":isDisabled})}
|
||||
>
|
||||
{side==='left'?(<ArrowLeft/>):(<ArrowRight/>)}
|
||||
</button>
|
||||
|
@ -2,9 +2,14 @@
|
||||
|
||||
.heartToggle{
|
||||
cursor: pointer;
|
||||
width: 4.8rem;
|
||||
height: 4.8rem;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 2.4rem;
|
||||
height: 2.4rem;
|
||||
path{
|
||||
stroke: theme("colors.primary");
|
||||
}
|
||||
}
|
||||
.isToggleOn{
|
||||
svg path{
|
||||
stroke: theme("colors.primary");
|
||||
}
|
||||
}
|
@ -1,19 +1,27 @@
|
||||
import { Heart } from '@components/icons'
|
||||
import React, { useState } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import IconHeart from 'src/components/icons/IconHeart'
|
||||
import React, { memo } from 'react'
|
||||
import s from './ItemWishList.module.scss'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
isActive?: boolean,
|
||||
onClick?: () => void
|
||||
onChange?: () => void
|
||||
}
|
||||
|
||||
const ItemWishList = ({}:Props) => {
|
||||
const [isClick,setClick] = useState(false)
|
||||
const ItemWishList = memo(({isActive, onClick, onChange}:Props) => {
|
||||
const handleClick = () => {
|
||||
isActive = !isActive
|
||||
}
|
||||
return(
|
||||
<div className={s.heartToggle} onClick={() => setClick(!isClick)}>
|
||||
<Heart color={isClick ? "#D1644D" : "#5B9A74"}/>
|
||||
<div className={classNames({
|
||||
[s.heartToggle]:true,
|
||||
[s.isToggleOn]:isActive
|
||||
})}
|
||||
onClick={handleClick}>
|
||||
<IconHeart />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default ItemWishList
|
@ -1,6 +1,4 @@
|
||||
@import '../../../styles/utilities';
|
||||
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@700&display=swap');
|
||||
|
||||
|
||||
.logo{
|
||||
display: flex;
|
||||
@ -12,7 +10,7 @@
|
||||
margin-right: 1.2rem;
|
||||
}
|
||||
.conTent{
|
||||
font-family: 'Poppins', sans-serif;
|
||||
@apply font-logo;
|
||||
text-transform: uppercase;
|
||||
line-height: 3.2rem;
|
||||
letter-spacing: -0.02rem;
|
||||
|
@ -1,15 +1,13 @@
|
||||
import s from './Logo.module.scss'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
|
||||
}
|
||||
|
||||
const Logo = ({}: Props) => {
|
||||
return(
|
||||
<div className={s.logo}>
|
||||
<div className={s.eclipse}>
|
||||
|
||||
</div>
|
||||
<div className={s.conTent}>
|
||||
ONLINE GROCERY
|
||||
|
@ -1,24 +1,30 @@
|
||||
.productCardWarpper{
|
||||
max-width: 20.8rem;
|
||||
max-height: 31.8rem;
|
||||
width: 20.8rem;
|
||||
height: 31.8rem;
|
||||
padding: 1.2rem 1.2rem 0 1.2rem;
|
||||
@apply border border-solid border-black;
|
||||
margin-bottom: 1px;
|
||||
@apply inline-flex flex-col justify-between;
|
||||
.cardTop{
|
||||
@apply border border-solid border-yellow-300 relative;
|
||||
max-height: 13.8rem;
|
||||
@apply relative;
|
||||
height: 13.8rem;
|
||||
width: 100%;
|
||||
.productImage{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
@apply flex justify-center items-center;
|
||||
img{
|
||||
@apply inline;
|
||||
}
|
||||
.productLabel{
|
||||
@apply absolute left-0 bottom-0;
|
||||
}
|
||||
}
|
||||
.productLabel{
|
||||
@apply absolute left-0 bottom-0;
|
||||
}
|
||||
}
|
||||
.cardMid{
|
||||
padding: 1.6rem 0;
|
||||
.cardMid{
|
||||
// padding: 1.6rem 0;
|
||||
min-height: 10.4rem;
|
||||
@apply flex flex-col justify-between;
|
||||
.cardMidTop{
|
||||
.productname{
|
||||
font-weight: bold;
|
||||
line-height: 2.4rem;
|
||||
@ -33,7 +39,6 @@
|
||||
}
|
||||
}
|
||||
.cardMidBot{
|
||||
margin-top: 2.8rem;
|
||||
@apply flex justify-between items-center border-t border-solid border-line;
|
||||
.productPrice{
|
||||
@apply font-bold;
|
||||
@ -44,6 +49,7 @@
|
||||
}
|
||||
}
|
||||
.cardBot{
|
||||
max-height: 4rem;
|
||||
@apply flex justify-between items-center;
|
||||
.cardButton{
|
||||
width: 13.6rem;
|
||||
|
@ -1,17 +1,13 @@
|
||||
import React from 'react'
|
||||
import { ProductProps } from 'src/utils/types.utils'
|
||||
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
||||
import ButtonIconBuy from '../ButtonIconBuy/ButtonIconBuy'
|
||||
import ItemWishList from '../ItemWishList/ItemWishList'
|
||||
import LabelCommon from '../LabelCommon/LabelCommon'
|
||||
import s from './ProductCard.module.scss'
|
||||
|
||||
interface ProductCardProps {
|
||||
category: string
|
||||
name: string
|
||||
weight: string
|
||||
price: string
|
||||
export interface ProductCardProps extends ProductProps {
|
||||
buttonText?: string
|
||||
imageSrc: string
|
||||
}
|
||||
|
||||
const ProductCard = ({
|
||||
@ -23,16 +19,16 @@ const ProductCard = ({
|
||||
imageSrc,
|
||||
}: ProductCardProps) => {
|
||||
return (
|
||||
<section className={s.productCardWarpper}>
|
||||
<section className={s.cardTop}>
|
||||
<div className={s.productCardWarpper}>
|
||||
<div className={s.cardTop}>
|
||||
<div className={s.productImage}>
|
||||
<img src={imageSrc} alt="image" />
|
||||
</div>
|
||||
<div className={s.productLabel}>
|
||||
<LabelCommon shape="half">{category}</LabelCommon>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className={s.cardMid}>
|
||||
</div>
|
||||
<div className={s.cardMid}>
|
||||
<div className={s.cardMidTop}>
|
||||
<div className={s.productname}>{name} </div>
|
||||
<div className={s.productWeight}>{weight}</div>
|
||||
@ -43,16 +39,16 @@ const ProductCard = ({
|
||||
<ItemWishList />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section className={s.cardBot}>
|
||||
</div>
|
||||
<div className={s.cardBot}>
|
||||
<div className={s.cardIcon}>
|
||||
<ButtonIconBuy/>
|
||||
</div>
|
||||
<div className={s.cardButton}>
|
||||
<ButtonCommon type="ghost">{buttonText}</ButtonCommon>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,12 @@
|
||||
@import "../../../styles/utilities";
|
||||
.productCardWarpper{
|
||||
@apply spacing-horizontal;
|
||||
:global(.customArrow) {
|
||||
&:global(.leftArrow){
|
||||
left: calc(-6.4rem - 2rem);
|
||||
}
|
||||
&:global(.rightArrow){
|
||||
right: calc(-6.4rem - 2rem);
|
||||
}
|
||||
}
|
||||
}
|
39
src/components/common/ProductCaroucel/ProductCaroucel.tsx
Normal file
39
src/components/common/ProductCaroucel/ProductCaroucel.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { TOptionsEvents } from 'keen-slider'
|
||||
import React from 'react'
|
||||
import CarouselCommon, {
|
||||
CarouselCommonProps,
|
||||
} from '../CarouselCommon/CarouselCommon'
|
||||
import ProductCard, { ProductCardProps } from '../ProductCard/ProductCard'
|
||||
import s from "./ProductCaroucel.module.scss"
|
||||
|
||||
interface ProductCaroucelProps
|
||||
extends Omit<CarouselCommonProps<ProductCardProps>, 'Component'|"option"> {
|
||||
option?:TOptionsEvents
|
||||
}
|
||||
|
||||
const OPTION_DEFAULT: TOptionsEvents = {
|
||||
slidesPerView: 2,
|
||||
mode: 'free',
|
||||
breakpoints: {
|
||||
'(min-width: 768px)': {
|
||||
slidesPerView: 3,
|
||||
},
|
||||
'(min-width: 1024px)': {
|
||||
slidesPerView: 5.5,
|
||||
},
|
||||
},
|
||||
}
|
||||
const ProductCaroucel = ({ option, data, ...props }: ProductCaroucelProps) => {
|
||||
return (
|
||||
<div className={s.productCardWarpper}>
|
||||
<CarouselCommon<ProductCardProps>
|
||||
data={data}
|
||||
Component={ProductCard}
|
||||
{...props}
|
||||
option={{ ...OPTION_DEFAULT, ...option }}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProductCaroucel
|
@ -1,16 +1,18 @@
|
||||
@import '../../../styles/utilities';
|
||||
@import url('https://fonts.googleapis.com/css2?family=Nunito&display=swap');
|
||||
|
||||
.viewAll{
|
||||
display: flex;
|
||||
color: theme("colors.primary");
|
||||
.conTent{
|
||||
margin: 0.8rem 0.8rem 0.8rem 1.6rem;
|
||||
font-family: 'Nunito', sans-serif;
|
||||
font-family: var(--font-sans);
|
||||
font-weight: bold;
|
||||
}
|
||||
.vecTor{
|
||||
margin: 0.8rem 0rem 0.8rem 0rem;
|
||||
svg path{
|
||||
fill: theme("colors.primary");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,8 @@
|
||||
import Vector from 'src/components/icons/Vector'
|
||||
import IconVector from 'src/components/icons/IconVector'
|
||||
import s from './ViewAllItem.module.scss'
|
||||
import Link from 'next/link'
|
||||
|
||||
interface Props {
|
||||
className?: string
|
||||
children?: any
|
||||
link?: string
|
||||
}
|
||||
|
||||
@ -17,7 +15,7 @@ const ViewAllItem = ({ link }: Props) => {
|
||||
</a>
|
||||
</Link>
|
||||
<div className={s.vecTor}>
|
||||
<Vector />
|
||||
<IconVector />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
@ -1,20 +0,0 @@
|
||||
|
||||
const Vector = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M20.16 4.99992C19.1 3.93713 17.6948 3.28846 16.1984 3.17109C14.7019 3.05372 13.2128 3.47539 12 4.35992C10.7277 3.41356 9.14402 2.98443 7.56795 3.15896C5.99188 3.33348 4.54047 4.0987 3.506 5.30051C2.47154 6.50231 1.93085 8.05144 1.99283 9.63594C2.05481 11.2204 2.71485 12.7226 3.84003 13.8399L10.05 20.0599C10.57 20.5717 11.2704 20.8585 12 20.8585C12.7296 20.8585 13.43 20.5717 13.95 20.0599L20.16 13.8399C21.3276 12.6652 21.983 11.0762 21.983 9.41992C21.983 7.76365 21.3276 6.17465 20.16 4.99992ZM18.75 12.4599L12.54 18.6699C12.4694 18.7413 12.3853 18.7979 12.2926 18.8366C12.1999 18.8752 12.1005 18.8951 12 18.8951C11.8996 18.8951 11.8002 18.8752 11.7075 18.8366C11.6148 18.7979 11.5307 18.7413 11.46 18.6699L5.25003 12.4299C4.46579 11.6283 4.02664 10.5514 4.02664 9.42992C4.02664 8.30846 4.46579 7.23158 5.25003 6.42992C6.04919 5.64091 7.127 5.19849 8.25003 5.19849C9.37306 5.19849 10.4509 5.64091 11.25 6.42992C11.343 6.52365 11.4536 6.59804 11.5755 6.64881C11.6973 6.69958 11.828 6.72572 11.96 6.72572C12.092 6.72572 12.2227 6.69958 12.3446 6.64881C12.4665 6.59804 12.5771 6.52365 12.67 6.42992C13.4692 5.64091 14.547 5.19849 15.67 5.19849C16.7931 5.19849 17.8709 5.64091 18.67 6.42992C19.4651 7.22107 19.9186 8.29211 19.9336 9.41361C19.9485 10.5351 19.5237 11.6179 18.75 12.4299V12.4599Z"
|
||||
fill={props.color}
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default Vector
|
23
src/components/icons/IconHeart.tsx
Normal file
23
src/components/icons/IconHeart.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
const IconHeart = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M20.84 2.61C20.3292 2.099 19.7228 1.69365 19.0554 1.41708C18.3879 1.14052 17.6725 0.998175 16.95 0.998175C16.2275 0.998175 15.5121 1.14052 14.8446 1.41708C14.1772 1.69365 13.5708 2.099 13.06 2.61L12 3.67L10.94 2.61C9.9083 1.57831 8.50903 0.998709 7.05 0.998709C5.59096 0.998709 4.19169 1.57831 3.16 2.61C2.1283 3.64169 1.54871 5.04097 1.54871 6.5C1.54871 7.95903 2.1283 9.35831 3.16 10.39L4.22 11.45L12 19.23L19.78 11.45L20.84 10.39C21.351 9.87924 21.7563 9.27281 22.0329 8.60536C22.3095 7.9379 22.4518 7.22249 22.4518 6.5C22.4518 5.77751 22.3095 5.0621 22.0329 4.39464C21.7563 3.72719 21.351 3.12076 20.84 2.61V2.61Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default IconHeart
|
@ -1,5 +1,5 @@
|
||||
|
||||
const Vector = ({ ...props }) => {
|
||||
const IconVector = ({ ...props }) => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
@ -11,10 +11,9 @@ const Vector = ({ ...props }) => {
|
||||
>
|
||||
<path
|
||||
d="M14.8299 11.2899L10.5899 7.04995C10.497 6.95622 10.3864 6.88183 10.2645 6.83106C10.1427 6.78029 10.012 6.75415 9.87994 6.75415C9.74793 6.75415 9.61723 6.78029 9.49537 6.83106C9.37351 6.88183 9.26291 6.95622 9.16994 7.04995C8.98369 7.23731 8.87915 7.49076 8.87915 7.75495C8.87915 8.01913 8.98369 8.27259 9.16994 8.45995L12.7099 11.9999L9.16994 15.5399C8.98369 15.7273 8.87915 15.9808 8.87915 16.2449C8.87915 16.5091 8.98369 16.7626 9.16994 16.9499C9.26338 17.0426 9.3742 17.116 9.49604 17.1657C9.61787 17.2155 9.74834 17.2407 9.87994 17.2399C10.0115 17.2407 10.142 17.2155 10.2638 17.1657C10.3857 17.116 10.4965 17.0426 10.5899 16.9499L14.8299 12.7099C14.9237 12.617 14.9981 12.5064 15.0488 12.3845C15.0996 12.2627 15.1257 12.132 15.1257 11.9999C15.1257 11.8679 15.0996 11.7372 15.0488 11.6154C14.9981 11.4935 14.9237 11.3829 14.8299 11.2899Z"
|
||||
fill="#5B9A74"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
|
||||
export default Vector
|
||||
export default IconVector
|
7
src/utils/types.utils.ts
Normal file
7
src/utils/types.utils.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface ProductProps {
|
||||
category: string
|
||||
name: string
|
||||
weight: string
|
||||
price: string
|
||||
imageSrc: string
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user