🎨 styles: cart drawer

:%s
This commit is contained in:
lytrankieio123 2021-09-06 17:06:06 +07:00
parent 432c7b403c
commit fc39eb1758
26 changed files with 431 additions and 12 deletions

View File

@ -13,6 +13,10 @@ const isVendure = provider === 'vendure'
module.exports = withCommerceConfig({
commerce,
images: {
// todo: replace domains for images
domains: ['user-images.githubusercontent.com'],
},
i18n: {
locales: ['en-US', 'es'],
defaultLocale: 'en-US',

View File

@ -0,0 +1,12 @@
@import '../../../styles/utilities';
.cartDrawer {
@apply flex flex-col h-full;
.body {
@apply overflow-y-auto overflow-x-hidden h-full custom-scroll;
}
.bottom {
padding-top: 1.6rem;
}
}

View File

@ -0,0 +1,35 @@
import React from 'react';
import { PRODUCT_CART_DATA_TEST } from 'src/utils/demo-data';
import { DrawerCommon } from '..';
import s from './CartDrawer.module.scss';
import CartCheckoutButton from './components/CartCheckoutButton/CartCheckoutButton';
import CartMessage from './components/CartMessage/CartMessage';
import CartRecommendation from './components/CartRecommendation/CartRecommendation';
import ProductsInCart from './components/ProductsInCart/ProductsInCart';
interface Props {
visible: boolean
onClose: () => void
}
const CartDrawer = ({ visible, onClose }: Props) => {
return (
<DrawerCommon
title={`Your cart (${PRODUCT_CART_DATA_TEST.length})`}
visible={visible}
onClose={onClose}>
<div className={s.cartDrawer}>
<div className={s.body}>
<ProductsInCart data={PRODUCT_CART_DATA_TEST}/>
<CartRecommendation />
</div>
<div className={s.bottom}>
<CartMessage />
<CartCheckoutButton />
</div>
</div>
</DrawerCommon>
)
}
export default CartDrawer;

View File

@ -0,0 +1,6 @@
.cartCheckoutButton {
padding: 1.6rem;
button {
width: 100%;
}
}

View File

@ -0,0 +1,13 @@
import React, { memo } from 'react';
import { ButtonCommon } from 'src/components/common';
import s from './CartCheckoutButton.module.scss';
const CartCheckoutButton = memo(() => {
return (
<div className={s.cartCheckoutButton}>
<ButtonCommon size='large'>Check out - Rp 120.500</ButtonCommon>
</div>
)
})
export default CartCheckoutButton;

View File

@ -0,0 +1,15 @@
@import "../../../../../styles/utilities";
.cartMessage {
@apply flex bg-info;
padding: 1.2rem 1.6rem;
.text {
font-weight: bold;
margin-right: 0.8rem;
}
.icon {
svg path {
fill: var(--text-placeholder);
}
}
}

View File

@ -0,0 +1,18 @@
import React, { memo } from 'react';
import { IconInfo } from 'src/components/icons';
import s from './CartMessage.module.scss';
const CartMessage = memo(() => {
return (
<div className={s.cartMessage}>
<div className={s.text}>
You save - Rp 150
</div>
<div className={s.icon}>
<IconInfo />
</div>
</div>
)
})
export default CartMessage;

View File

@ -0,0 +1,25 @@
@import '../../../../../styles/utilities';
.cartRecommendation {
@apply w-full bg-background-gray;
.top {
@apply flex justify-between items-center;
padding: 1.6rem;
.heading {
@apply font-bold text-active sm-headline;
}
}
.productCardWarpper {
padding-left: 1.6rem;
:global(.customArrow) {
@screen lg {
&:global(.leftArrow) {
left: calc(-6.4rem - 2rem);
}
&:global(.rightArrow) {
right: calc(-6.4rem - 2rem);
}
}
}
}
}

View File

@ -0,0 +1,43 @@
import { TOptionsEvents } from 'keen-slider';
import React from 'react';
import { CarouselCommon, ViewAllItem } from 'src/components/common';
import ProductCard, { ProductCardProps } from 'src/components/common/ProductCard/ProductCard';
import { ROUTE } from 'src/utils/constanst.utils';
import { PRODUCT_DATA_TEST } from 'src/utils/demo-data';
import s from './CartRecommendation.module.scss';
const option: TOptionsEvents = {
slidesPerView: 2,
mode: 'free',
breakpoints: {
'(min-width: 640px)': {
slidesPerView: 1,
},
'(min-width: 768px)': {
slidesPerView: 2.5,
}
},
}
const CartRecommendation = () => {
return (
<div className={s.cartRecommendation}>
<div className={s.top}>
<div className={s.heading}>
Recommendation
</div>
<ViewAllItem link={ROUTE.PRODUCTS} />
</div>
<div className={s.productCardWarpper}>
<CarouselCommon<ProductCardProps>
data={PRODUCT_DATA_TEST}
Component={ProductCard}
itemKey="cart-recommendation"
option={option}
/>
</div>
</div>
)
}
export default CartRecommendation;

View File

@ -0,0 +1,50 @@
@import "../../../../../styles/utilities";
.productCartItem {
@apply grid;
grid-template-columns: 2fr 1fr;
padding-bottom: 1.6rem;
padding-top: 1.6rem;
border-bottom: 1px solid var(--border-line);
.info {
@apply flex;
.imgWrap {
width: 11rem;
height: 7.5rem;
margin-right: 1.6rem;
img {
object-fit: contain;
}
}
.detail {
min-height: 9rem;
.price {
margin-top: 0.8rem;
.old {
margin-bottom: 0.8rem;
.number {
margin-right: 0.8rem;
color: var(--text-label);
text-decoration: line-through;
}
}
.current {
@apply text-active font-bold sm-headline;
}
}
}
}
.actions {
@apply flex flex-col justify-between items-end;
margin-left: 1.6rem;
.iconDelete {
@apply cursor-pointer;
&:hover {
svg path {
fill: var(--negative);
}
}
}
}
}

View File

@ -0,0 +1,56 @@
import React from 'react';
import Link from 'next/link'
import { QuanittyInput } from 'src/components/common';
import { IconDelete } from 'src/components/icons';
import { ROUTE } from 'src/utils/constanst.utils';
import { ProductProps } from 'src/utils/types.utils';
import ImgWithLink from '../../../ImgWithLink/ImgWithLink';
import LabelCommon from '../../../LabelCommon/LabelCommon';
import s from './ProductCartItem.module.scss';
export interface ProductCartItempProps extends ProductProps {
quantity: number,
}
const ProductCartItem = ({ name, slug, weight, price, oldPrice, discount, imageSrc, quantity }: ProductCartItempProps) => {
return (
<div className={s.productCartItem}>
<div className={s.info}>
<Link href={`${ROUTE.PRODUCT_DETAIL}/${slug}`}>
<a href="">
<div className={s.imgWrap}>
<ImgWithLink src={imageSrc} alt={name} />
</div>
</a>
</Link>
<div className={s.detail}>
<Link href={`${ROUTE.PRODUCT_DETAIL}/${slug}`}>
<a>
<div className={s.name}>
{name} {weight ? `(${weight})` : ''}
</div>
</a>
</Link>
<div className={s.price}>
{
oldPrice &&
<div className={s.old}>
<span className={s.number}>{oldPrice}</span>
<LabelCommon type='discount'>{discount}</LabelCommon>
</div>
}
<div className={s.current}>{price}</div>
</div>
</div>
</div>
<div className={s.actions}>
<div className={s.iconDelete}>
<IconDelete />
</div>
<QuanittyInput size='small' initValue={quantity} />
</div>
</div>
)
}
export default ProductCartItem;

View File

@ -0,0 +1,5 @@
.productsInCart {
padding: 1.6rem 1.6rem 0 1.6rem;
margin-bottom: -1px;
}

View File

@ -0,0 +1,28 @@
import React from 'react';
import ProductCartItem, { ProductCartItempProps } from '../ProductCartItem/ProductCartItem';
import s from './ProductsInCart.module.scss';
interface Props {
data: ProductCartItempProps[]
}
const ProductsInCart = ({ data }: Props) => {
return (
<div className={s.productsInCart}>
{
data.map(item => <ProductCartItem
key={item.name}
name={item.name}
weight={item.weight}
price={item.price}
oldPrice={item.oldPrice}
discount={item.discount}
imageSrc={item.imageSrc}
quantity={item.quantity}
/>)
}
</div>
)
}
export default ProductsInCart;

View File

@ -2,6 +2,7 @@
.drawerCommon {
@apply fixed flex justify-end transition-all duration-200;
overflow: hidden;
top: 0;
right: 0;
height: 100vh;
@ -13,12 +14,15 @@
}
.inner {
@apply bg-white;
@apply flex flex-col bg-white;
width: fit-content;
height: 100vh;
min-width: 48rem;
width: 100%;
margin-right: 0;
@screen md {
max-width: 50rem;
}
.top {
@apply flex justify-between items-center;
padding: 1.6rem;
@ -37,6 +41,7 @@
}
.content {
overflow-y: auto;
height: 100%;
}
&.hide {
transform: translateX(110%);

View File

@ -1,4 +1,9 @@
.imgWithLink {
@apply w-full h-full;
object-fit: cover;
position: relative;
min-width: 5rem;
width: 100%;
height: 100%;
img {
object-fit: cover;
}
}

View File

@ -1,5 +1,6 @@
import React from 'react'
import s from './ImgWithLink.module.scss'
import Image from 'next/image'
export interface ImgWithLinkProps {
src: string,
@ -8,8 +9,9 @@ export interface ImgWithLinkProps {
const ImgWithLink = ({ src, alt }: ImgWithLinkProps) => {
return (
<img className={s.imgWithLink} src={src} alt={alt} />
<div className={s.imgWithLink}>
<Image src={src} alt={alt} layout="fill" className={s.imgWithLink} />
</div>
)
}

View File

@ -2,7 +2,7 @@ import { CommerceProvider } from '@framework'
import { useRouter } from 'next/router'
import { FC } from 'react'
import { useModalCommon } from 'src/components/hooks'
import { DrawerCommon, ScrollToTop } from '..'
import { CartDrawer } from '..'
import Footer from '../Footer/Footer'
import Header from '../Header/Header'
import s from './Layout.module.scss'
@ -30,8 +30,7 @@ const Layout: FC<Props> = ({ children }) => {
<button onClick={toggle}>toggle card: {visibleCartDrawer.toString()}</button>
<Header />
<main >{children}</main>
<DrawerCommon
title="Cart"
<CartDrawer
visible={visibleCartDrawer}
onClose={closeCartDrawer} />
<Footer />

View File

@ -11,7 +11,7 @@
padding-top: 5.6rem;
padding-bottom: 5.6rem;
border: none;
background-color: #f5f4f2;
background-color: var(--background-gray);
}
.productsWrap {
@apply spacing-horizontal-left;

View File

@ -35,3 +35,4 @@ export { default as ModalCreateUserInfo} from './ModalCreateUserInfo/ModalCreate
export { default as ImgWithLink} from './ImgWithLink/ImgWithLink'
export { default as RecipeDetail} from './RecipeDetail/RecipeDetail'
export { default as DrawerCommon} from './DrawerCommon/DrawerCommon'
export { default as CartDrawer} from './CartDrawer/CartDrawer'

View File

@ -0,0 +1,11 @@
import React from 'react'
const IconDelete = () => {
return (
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 16C7.26522 16 7.51957 15.8946 7.70711 15.7071C7.89464 15.5196 8 15.2652 8 15V9C8 8.73478 7.89464 8.48043 7.70711 8.29289C7.51957 8.10536 7.26522 8 7 8C6.73478 8 6.48043 8.10536 6.29289 8.29289C6.10536 8.48043 6 8.73478 6 9V15C6 15.2652 6.10536 15.5196 6.29289 15.7071C6.48043 15.8946 6.73478 16 7 16ZM17 4H13V3C13 2.20435 12.6839 1.44129 12.1213 0.87868C11.5587 0.316071 10.7956 0 10 0H8C7.20435 0 6.44129 0.316071 5.87868 0.87868C5.31607 1.44129 5 2.20435 5 3V4H1C0.734784 4 0.48043 4.10536 0.292893 4.29289C0.105357 4.48043 0 4.73478 0 5C0 5.26522 0.105357 5.51957 0.292893 5.70711C0.48043 5.89464 0.734784 6 1 6H2V17C2 17.7956 2.31607 18.5587 2.87868 19.1213C3.44129 19.6839 4.20435 20 5 20H13C13.7956 20 14.5587 19.6839 15.1213 19.1213C15.6839 18.5587 16 17.7956 16 17V6H17C17.2652 6 17.5196 5.89464 17.7071 5.70711C17.8946 5.51957 18 5.26522 18 5C18 4.73478 17.8946 4.48043 17.7071 4.29289C17.5196 4.10536 17.2652 4 17 4ZM7 3C7 2.73478 7.10536 2.48043 7.29289 2.29289C7.48043 2.10536 7.73478 2 8 2H10C10.2652 2 10.5196 2.10536 10.7071 2.29289C10.8946 2.48043 11 2.73478 11 3V4H7V3ZM14 17C14 17.2652 13.8946 17.5196 13.7071 17.7071C13.5196 17.8946 13.2652 18 13 18H5C4.73478 18 4.48043 17.8946 4.29289 17.7071C4.10536 17.5196 4 17.2652 4 17V6H14V17ZM11 16C11.2652 16 11.5196 15.8946 11.7071 15.7071C11.8946 15.5196 12 15.2652 12 15V9C12 8.73478 11.8946 8.48043 11.7071 8.29289C11.5196 8.10536 11.2652 8 11 8C10.7348 8 10.4804 8.10536 10.2929 8.29289C10.1054 8.48043 10 8.73478 10 9V15C10 15.2652 10.1054 15.5196 10.2929 15.7071C10.4804 15.8946 10.7348 16 11 16Z" fill="#8F8F8F" />
</svg>
)
}
export default IconDelete

View File

@ -24,3 +24,4 @@ export { default as IconTime } from './IconTime'
export { default as IconPeople } from './IconPeople'
export { default as IconLocation } from './IconLocation'
export { default as IconClose } from './IconClose'
export { default as IconDelete } from './IconDelete'

View File

@ -6,7 +6,7 @@
--primary-lightest: #effaf4;
--info-dark: #00317a;
--info: #297fff;
--info: #3468B7;
--info-border-line: #d6e7ff;
--info-light: #ebf3ff;
@ -33,6 +33,7 @@
--disabled: #cccccc;
--border-line: #ebebeb;
--background: #fff;
--background-gray: #F5F4F2;
--gray: #f8f8f8;
--white: #fff;
--background-arrow:rgba(20, 20, 20, 0.05);

View File

@ -120,6 +120,25 @@
font-family: var(--font-logo);
}
.custom-scroll {
overflow-y: auto;
&::-webkit-scrollbar-track {
background-color: var(--background-gray);
border-radius: 10px;
}
&::-webkit-scrollbar {
border-radius: 10px;
width: 6px;
background-color: var(--background-gray);
}
&::-webkit-scrollbar-thumb {
border-radius: 10px;
background-color: var(--primary)
}
}
.u-form {
.body {
> div {

View File

@ -3,6 +3,7 @@ import { RecipeCardProps } from "src/components/common/RecipeCard/RecipeCard"
export const PRODUCT_DATA_TEST = [
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -10,6 +11,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -17,6 +19,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Carrot',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -24,6 +27,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Salad',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -31,6 +35,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -38,6 +43,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -45,6 +51,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -52,6 +59,7 @@ export const PRODUCT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -59,9 +67,55 @@ export const PRODUCT_DATA_TEST = [
},
]
export const PRODUCT_CART_DATA_TEST = [
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png",
oldPrice: 'Rp 32.000',
discount: '15%',
quantity: 1,
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
imageSrc: "https://user-images.githubusercontent.com/76729908/131646211-d56b77ac-83f1-4dd2-b55c-e3f1e0ba4e49.png",
oldPrice: 'Rp 32.000',
discount: '15%',
quantity: 2,
},
{
name: 'Carrot',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
imageSrc: "https://user-images.githubusercontent.com/76729908/131646217-23b86160-45c9-4845-8dcc-b3e1a4483edd.png",
oldPrice: 'Rp 32.000',
discount: '20%',
quantity: 3,
},
{
name: 'Salad',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
imageSrc: "https://user-images.githubusercontent.com/76729908/131646221-aaa1d48d-bb80-470f-9400-ae2aa47285b6.png",
quantity: 1,
},
]
export const INGREDIENT_DATA_TEST = [
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -69,6 +123,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -77,6 +132,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Carrot',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -84,6 +140,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Salad',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -92,6 +149,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -99,6 +157,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -106,6 +165,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Tomato',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',
@ -113,6 +173,7 @@ export const INGREDIENT_DATA_TEST = [
},
{
name: 'Cucumber',
slug: 'tomato',
weight: '250g',
category: 'VEGGIE',
price: 'Rp 27.500',

View File

@ -1,8 +1,11 @@
export interface ProductProps {
category: string
category?: string
name: string
slug: string
weight: string
price: string
oldPrice?: string
discount?: string
imageSrc: string
isNotSell?: boolean
}
@ -17,7 +20,7 @@ export interface FeaturedProductProps {
export interface RecipeProps {
title: string
description:string
description: string
imageSrc: string
}

View File

@ -47,6 +47,7 @@ module.exports = {
'line': 'var(--border-line)',
'background': 'var(--background)',
'background-gray': 'var(--background-gray)',
'white': 'var(--white)',
'background-arrow': 'var(--background-arrow)',