mirror of
https://github.com/vercel/commerce.git
synced 2025-07-04 12:11:22 +00:00
Merge branch 'common' of github.com:KieIO/grocery-vercel-commerce into m3-datnguyen
This commit is contained in:
commit
7951fbb81a
@ -1,18 +1,37 @@
|
|||||||
|
|
||||||
import { Layout } from 'src/components/common'
|
import { Layout } from 'src/components/common';
|
||||||
import { HomeBanner, HomeCollection, HomeCTA, HomeSubscribe, HomeVideo, HomeCategories, HomeFeature, HomeRecipe } from 'src/components/modules/home';
|
import { HomeBanner, HomeCategories, HomeCollection, HomeCTA, HomeFeature, HomeRecipe, HomeSubscribe, HomeVideo } from 'src/components/modules/home';
|
||||||
|
import {SelectCommon} from 'src/components/common'
|
||||||
|
|
||||||
|
const OPTION_SORT = [
|
||||||
|
{
|
||||||
|
name: "By Name"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Price (High to Low)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "On Sale"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<HomeBanner />
|
{/* <HomeBanner />
|
||||||
|
<HomeBanner/>
|
||||||
<HomeFeature />
|
<HomeFeature />
|
||||||
<HomeCategories />
|
<HomeCategories />
|
||||||
<HomeCollection />
|
<HomeCollection />
|
||||||
<HomeVideo />
|
<HomeVideo />
|
||||||
<HomeCTA />
|
<HomeCTA />
|
||||||
<HomeRecipe />
|
<HomeRecipe />
|
||||||
<HomeSubscribe />
|
<HomeSubscribe /> */}
|
||||||
|
<SelectCommon option={OPTION_SORT}>Sort By</SelectCommon>
|
||||||
|
<SelectCommon option={OPTION_SORT} size="large" type="custom">Sort By</SelectCommon>
|
||||||
|
|
||||||
|
// todo: uncomment
|
||||||
|
{/* <ModalCreateUserInfo/> */}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
@import "../../../styles/utilities";
|
|
||||||
|
|
||||||
.banner {
|
|
||||||
@apply bg-primary-light custom-border-radius-lg overflow-hidden;
|
|
||||||
@screen md {
|
|
||||||
border: 1px solid var(--primary);
|
|
||||||
}
|
|
||||||
&.large {
|
|
||||||
margin-bottom: 2.8rem;
|
|
||||||
.inner {
|
|
||||||
@screen xl {
|
|
||||||
@apply bg-right-bottom;
|
|
||||||
background-size: unset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.inner {
|
|
||||||
@apply bg-no-repeat;
|
|
||||||
background-size: 90%;
|
|
||||||
background-position: right -500% bottom 0%;
|
|
||||||
.content {
|
|
||||||
background-image: linear-gradient(
|
|
||||||
to right,
|
|
||||||
rgb(227, 242, 233, 0.9),
|
|
||||||
rgb(227, 242, 233, 0.5) 80%,
|
|
||||||
rgb(227, 242, 233, 0)
|
|
||||||
);
|
|
||||||
padding: 1.6rem;
|
|
||||||
max-width: 37rem;
|
|
||||||
@screen md {
|
|
||||||
max-width: 49.6rem;
|
|
||||||
padding: 4.8rem;
|
|
||||||
}
|
|
||||||
.top {
|
|
||||||
.heading {
|
|
||||||
@apply heading-1 font-heading;
|
|
||||||
margin-bottom: 1.6rem;
|
|
||||||
}
|
|
||||||
.subHeading {
|
|
||||||
@apply sub-headline;
|
|
||||||
@screen md {
|
|
||||||
@apply caption;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.bottom {
|
|
||||||
margin-top: 4rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +1,24 @@
|
|||||||
import classNames from 'classnames'
|
|
||||||
import Link from 'next/link'
|
|
||||||
import React, { memo } from 'react'
|
import React, { memo } from 'react'
|
||||||
import { IconArrowRight } from 'src/components/icons'
|
import CarouselCommon from '../CarouselCommon/CarouselCommon'
|
||||||
import { ROUTE } from 'src/utils/constanst.utils'
|
import BannerItem, { BannerItemProps } from './BannerItem/BannerItem'
|
||||||
import { LANGUAGE } from 'src/utils/language.utils'
|
|
||||||
import ButtonCommon from '../ButtonCommon/ButtonCommon'
|
|
||||||
import s from './Banner.module.scss'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
imgLink: string,
|
data: BannerItemProps[],
|
||||||
title: string,
|
|
||||||
subtitle: string,
|
|
||||||
buttonLabel?: string,
|
|
||||||
linkButton?: string,
|
|
||||||
size?: 'small' | 'large',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Banner = memo(({ imgLink, title, subtitle, buttonLabel = LANGUAGE.BUTTON_LABEL.SHOP_NOW, linkButton = ROUTE.HOME, size = 'large' }: Props) => {
|
const option = {
|
||||||
|
slidesPerView: 1,
|
||||||
|
breakpoints: {}
|
||||||
|
}
|
||||||
|
const Banner = memo(({ data }: Props) => {
|
||||||
return (
|
return (
|
||||||
<div className={classNames({
|
<CarouselCommon<BannerItemProps>
|
||||||
[s.banner]: true,
|
data={data}
|
||||||
[s[size]]: true,
|
itemKey="banner"
|
||||||
})}>
|
Component={BannerItem}
|
||||||
<div className={s.inner} style={{ backgroundImage: `url(${imgLink})` }}>
|
option={option}
|
||||||
<div className={s.content}>
|
isDot = {true}
|
||||||
<div className={s.top}>
|
/>
|
||||||
<h1 className={s.heading}>
|
|
||||||
{title}
|
|
||||||
</h1>
|
|
||||||
<div className={s.subHeading}>
|
|
||||||
{subtitle}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={s.bottom}>
|
|
||||||
<Link href={linkButton}>
|
|
||||||
<a>
|
|
||||||
<ButtonCommon icon={<IconArrowRight />} isIconSuffix={true}>{buttonLabel}</ButtonCommon>
|
|
||||||
</a>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
@import "../../../../styles/utilities";
|
||||||
|
|
||||||
|
.bannerItem {
|
||||||
|
@apply bg-primary-light custom-border-radius-lg overflow-hidden;
|
||||||
|
@screen md {
|
||||||
|
border: 1px solid var(--primary);
|
||||||
|
}
|
||||||
|
&.large {
|
||||||
|
margin-bottom: 2.8rem;
|
||||||
|
.inner {
|
||||||
|
@screen xl {
|
||||||
|
@apply bg-right-bottom;
|
||||||
|
background-size: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.inner {
|
||||||
|
@apply bg-no-repeat;
|
||||||
|
background-size: 90%;
|
||||||
|
background-position: right -500% bottom 0%;
|
||||||
|
.content {
|
||||||
|
background-image: linear-gradient(
|
||||||
|
to right,
|
||||||
|
rgb(227, 242, 233, 0.9),
|
||||||
|
rgb(227, 242, 233, 0.5) 80%,
|
||||||
|
rgb(227, 242, 233, 0)
|
||||||
|
);
|
||||||
|
padding: 1.6rem;
|
||||||
|
max-width: 37rem;
|
||||||
|
@screen md {
|
||||||
|
max-width: 49.6rem;
|
||||||
|
padding: 4.8rem;
|
||||||
|
}
|
||||||
|
.top {
|
||||||
|
.heading {
|
||||||
|
@apply heading-1 font-heading;
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
|
}
|
||||||
|
.subHeading {
|
||||||
|
@apply sub-headline;
|
||||||
|
@screen md {
|
||||||
|
@apply caption;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom {
|
||||||
|
margin-top: 4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
48
src/components/common/Banner/BannerItem/BannerItem.tsx
Normal file
48
src/components/common/Banner/BannerItem/BannerItem.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import React, { memo } from 'react'
|
||||||
|
import { IconArrowRight } from 'src/components/icons'
|
||||||
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
|
import { LANGUAGE } from 'src/utils/language.utils'
|
||||||
|
import ButtonCommon from '../../ButtonCommon/ButtonCommon'
|
||||||
|
import s from './BannerItem.module.scss'
|
||||||
|
|
||||||
|
export interface BannerItemProps {
|
||||||
|
imgLink: string,
|
||||||
|
title: string,
|
||||||
|
subtitle: string,
|
||||||
|
buttonLabel?: string,
|
||||||
|
linkButton?: string,
|
||||||
|
size?: 'small' | 'large',
|
||||||
|
}
|
||||||
|
|
||||||
|
const BannerItem = memo(({ imgLink, title, subtitle, buttonLabel = LANGUAGE.BUTTON_LABEL.SHOP_NOW, linkButton = ROUTE.HOME, size = 'large' }: BannerItemProps) => {
|
||||||
|
return (
|
||||||
|
<div className={classNames({
|
||||||
|
[s.bannerItem]: true,
|
||||||
|
[s[size]]: true,
|
||||||
|
})}>
|
||||||
|
<div className={s.inner} style={{ backgroundImage: `url(${imgLink})` }}>
|
||||||
|
<div className={s.content}>
|
||||||
|
<div className={s.top}>
|
||||||
|
<h1 className={s.heading}>
|
||||||
|
{title}
|
||||||
|
</h1>
|
||||||
|
<div className={s.subHeading}>
|
||||||
|
{subtitle}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={s.bottom}>
|
||||||
|
<Link href={linkButton}>
|
||||||
|
<a>
|
||||||
|
<ButtonCommon icon={<IconArrowRight />} isIconSuffix={true}>{buttonLabel}</ButtonCommon>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
export default BannerItem
|
@ -3,6 +3,7 @@ import React, { memo, useEffect, useState } from 'react'
|
|||||||
import { useModalCommon } from 'src/components/hooks/useModalCommon'
|
import { useModalCommon } from 'src/components/hooks/useModalCommon'
|
||||||
import { isMobile } from 'src/utils/funtion.utils'
|
import { isMobile } from 'src/utils/funtion.utils'
|
||||||
import ModalAuthenticate from '../ModalAuthenticate/ModalAuthenticate'
|
import ModalAuthenticate from '../ModalAuthenticate/ModalAuthenticate'
|
||||||
|
import ModalCreateUserInfo from '../ModalCreateUserInfo/ModalCreateUserInfo'
|
||||||
import HeaderHighLight from './components/HeaderHighLight/HeaderHighLight'
|
import HeaderHighLight from './components/HeaderHighLight/HeaderHighLight'
|
||||||
import HeaderMenu from './components/HeaderMenu/HeaderMenu'
|
import HeaderMenu from './components/HeaderMenu/HeaderMenu'
|
||||||
import HeaderSubMenu from './components/HeaderSubMenu/HeaderSubMenu'
|
import HeaderSubMenu from './components/HeaderSubMenu/HeaderSubMenu'
|
||||||
@ -13,6 +14,7 @@ import s from './Header.module.scss'
|
|||||||
const Header = memo(() => {
|
const Header = memo(() => {
|
||||||
const [isFullHeader, setIsFullHeader] = useState<boolean>(true)
|
const [isFullHeader, setIsFullHeader] = useState<boolean>(true)
|
||||||
const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false })
|
const { visible: visibleModalAuthen, closeModal: closeModalAuthen, openModal: openModalAuthen } = useModalCommon({ initialValue: false })
|
||||||
|
const { visible: visibleModalInfo, closeModal: closeModalInfo, openModal: openModalInfo } = useModalCommon({ initialValue: false })
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
window.addEventListener('scroll', handleScroll)
|
window.addEventListener('scroll', handleScroll)
|
||||||
@ -35,12 +37,15 @@ const Header = memo(() => {
|
|||||||
<header className={classNames({ [s.header]: true, [s.full]: isFullHeader })}>
|
<header className={classNames({ [s.header]: true, [s.full]: isFullHeader })}>
|
||||||
<HeaderHighLight isShow={isFullHeader} />
|
<HeaderHighLight isShow={isFullHeader} />
|
||||||
<div className={s.menu}>
|
<div className={s.menu}>
|
||||||
<HeaderMenu isFull={isFullHeader} openModalAuthen={openModalAuthen} />
|
<HeaderMenu isFull={isFullHeader}
|
||||||
|
openModalAuthen={openModalAuthen}
|
||||||
|
openModalInfo={openModalInfo} />
|
||||||
<HeaderSubMenu isShow={isFullHeader} />
|
<HeaderSubMenu isShow={isFullHeader} />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<HeaderSubMenuMobile />
|
<HeaderSubMenuMobile />
|
||||||
<ModalAuthenticate visible={visibleModalAuthen} closeModal={closeModalAuthen} />
|
<ModalAuthenticate visible={visibleModalAuthen} closeModal={closeModalAuthen} />
|
||||||
|
<ModalCreateUserInfo demoVisible={visibleModalInfo} demoCloseModal={closeModalInfo}/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -11,14 +11,19 @@ interface Props {
|
|||||||
children?: any,
|
children?: any,
|
||||||
isFull: boolean,
|
isFull: boolean,
|
||||||
openModalAuthen: () => void,
|
openModalAuthen: () => void,
|
||||||
|
openModalInfo: () => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
const HeaderMenu = memo(({ isFull, openModalAuthen }: Props) => {
|
const HeaderMenu = memo(({ isFull, openModalAuthen, openModalInfo }: Props) => {
|
||||||
const optionMenu = useMemo(() => [
|
const optionMenu = useMemo(() => [
|
||||||
{
|
{
|
||||||
onClick: openModalAuthen,
|
onClick: openModalAuthen,
|
||||||
name: 'Login (Demo)',
|
name: 'Login (Demo)',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
onClick: openModalInfo,
|
||||||
|
name: 'Create User Info (Demo)',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
link: ROUTE.ACCOUNT,
|
link: ROUTE.ACCOUNT,
|
||||||
name: 'Account',
|
name: 'Account',
|
||||||
|
@ -1,51 +1,94 @@
|
|||||||
@import "../../../styles/utilities";
|
@import "../../../styles/utilities";
|
||||||
|
|
||||||
.inputWrap {
|
.inputWrap {
|
||||||
@apply flex items-center relative;
|
.inputInner {
|
||||||
.icon {
|
@apply flex items-center relative;
|
||||||
@apply absolute;
|
.icon {
|
||||||
content: "";
|
@apply absolute flex justify-center items-center;
|
||||||
left: 1.6rem;
|
content: "";
|
||||||
margin-right: 1.6rem;
|
left: 1.6rem;
|
||||||
svg path {
|
margin-right: 1.6rem;
|
||||||
fill: currentColor;
|
svg path {
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
.icon + .inputCommon {
|
||||||
.icon + .inputCommon {
|
padding-left: 4.8rem;
|
||||||
padding-left: 4.8rem;
|
|
||||||
}
|
|
||||||
.inputCommon {
|
|
||||||
@apply block w-full transition-all duration-200 rounded;
|
|
||||||
padding: 1.2rem 1.6rem;
|
|
||||||
border: 1px solid var(--border-line);
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
outline: none;
|
|
||||||
border: 1px solid var(--primary);
|
|
||||||
@apply shadow-md;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&::placeholder {
|
.inputCommon {
|
||||||
@apply text-label;
|
@apply block w-full transition-all duration-200 rounded;
|
||||||
}
|
padding: 1.2rem 1.6rem;
|
||||||
|
border: 1px solid var(--border-line);
|
||||||
&.custom {
|
|
||||||
@apply custom-border-radius;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
background: var(--gray);
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:active {
|
&:active {
|
||||||
|
outline: none;
|
||||||
border: 1px solid var(--primary);
|
border: 1px solid var(--primary);
|
||||||
|
@apply shadow-md;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
@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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&.bgTransparent {
|
|
||||||
background: rgb(227, 242, 233, 0.3);
|
&.preserve {
|
||||||
color: var(--white);
|
@apply flex-row-reverse;
|
||||||
&::placeholder {
|
.icon {
|
||||||
color: var(--white);
|
left: unset;
|
||||||
|
right: 1.6rem;
|
||||||
|
margin-left: 1.6rem;
|
||||||
|
margin-right: 0;
|
||||||
|
svg path {
|
||||||
|
fill: var(--text-label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.icon + .inputCommon {
|
||||||
|
padding-left: 1.6rem;
|
||||||
|
padding-right: 4.8rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.success {
|
||||||
|
.icon {
|
||||||
|
svg path {
|
||||||
|
fill: var(--primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.error {
|
||||||
|
.icon {
|
||||||
|
svg path {
|
||||||
|
fill: var(--negative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
border-color: var(--negative) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.errorMessage {
|
||||||
|
@apply caption;
|
||||||
|
color: var(--negative);
|
||||||
|
margin-top: 0.4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
import React, { forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
||||||
|
import { IconCheck, IconError, IconPassword, IconPasswordCross } 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';
|
||||||
|
|
||||||
@ -14,14 +15,29 @@ interface Props {
|
|||||||
styleType?: 'default' | 'custom',
|
styleType?: 'default' | 'custom',
|
||||||
backgroundTransparent?: boolean,
|
backgroundTransparent?: boolean,
|
||||||
icon?: React.ReactNode,
|
icon?: React.ReactNode,
|
||||||
|
isIconSuffix?: boolean,
|
||||||
|
isShowIconSuccess?: boolean,
|
||||||
|
error?: string,
|
||||||
onChange?: (value: string | number) => void,
|
onChange?: (value: string | number) => void,
|
||||||
onEnter?: (value: string | number) => void,
|
onEnter?: (value: string | number) => void,
|
||||||
}
|
}
|
||||||
|
|
||||||
const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleType = 'default', icon, backgroundTransparent = false,
|
const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleType = 'default', icon, backgroundTransparent = false,
|
||||||
|
isIconSuffix, isShowIconSuccess, error,
|
||||||
onChange, onEnter }: Props, ref) => {
|
onChange, onEnter }: Props, ref) => {
|
||||||
const inputElementRef = useRef<HTMLInputElement>(null);
|
const inputElementRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
const iconElement = useMemo(() => {
|
||||||
|
if (error) {
|
||||||
|
return <span className={s.icon}><IconError /> </span>
|
||||||
|
} else if (isShowIconSuccess) {
|
||||||
|
return <span className={s.icon}><IconCheck /> </span>
|
||||||
|
} else if (icon) {
|
||||||
|
return <span className={s.icon}>{icon} </span>
|
||||||
|
}
|
||||||
|
return <></>
|
||||||
|
}, [icon, error, isShowIconSuccess])
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
focus: () => {
|
focus: () => {
|
||||||
inputElementRef.current?.focus();
|
inputElementRef.current?.focus();
|
||||||
@ -44,23 +60,33 @@ const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleTyp
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={s.inputWrap}>
|
<div className={classNames({
|
||||||
|
[s.inputWrap]: true,
|
||||||
|
})}>
|
||||||
|
<div className={classNames({
|
||||||
|
[s.inputInner]: true,
|
||||||
|
[s.preserve]: isIconSuffix,
|
||||||
|
[s.success]: isShowIconSuccess,
|
||||||
|
[s.error]: !!error,
|
||||||
|
})}>
|
||||||
|
{iconElement}
|
||||||
|
<input
|
||||||
|
ref={inputElementRef}
|
||||||
|
value={value}
|
||||||
|
type={type}
|
||||||
|
placeholder={placeholder}
|
||||||
|
onChange={handleChange}
|
||||||
|
onKeyDown={handleKeyDown}
|
||||||
|
className={classNames({
|
||||||
|
[s.inputCommon]: true,
|
||||||
|
[s[styleType]]: true,
|
||||||
|
[s.bgTransparent]: backgroundTransparent
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
icon && <span className={s.icon}>{icon}</span>
|
error && <div className={s.errorMessage}>{error}</div>
|
||||||
}
|
}
|
||||||
<input
|
|
||||||
ref={inputElementRef}
|
|
||||||
value={value}
|
|
||||||
type={type}
|
|
||||||
placeholder={placeholder}
|
|
||||||
onChange={handleChange}
|
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
className={classNames({
|
|
||||||
[s.inputCommon]: true,
|
|
||||||
[s[styleType]]: true,
|
|
||||||
[s.bgTransparent]: backgroundTransparent
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
.iconPassword {
|
||||||
|
all: unset;
|
||||||
|
cursor: pointer;
|
||||||
|
&:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
&:focus-visible {
|
||||||
|
outline: 2px solid var(--text-active);
|
||||||
|
}
|
||||||
|
}
|
40
src/components/common/InputPassword/InputPassword.tsx
Normal file
40
src/components/common/InputPassword/InputPassword.tsx
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IconPassword, IconPasswordCross } from 'src/components/icons';
|
||||||
|
import { Inputcommon } from '..';
|
||||||
|
import s from './InputPassword.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children?: React.ReactNode,
|
||||||
|
value?: string | number,
|
||||||
|
placeholder?: string,
|
||||||
|
styleType?: 'default' | 'custom',
|
||||||
|
error?: string,
|
||||||
|
onChange?: (value: string | number) => void,
|
||||||
|
onEnter?: (value: string | number) => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputPassword = ({ value, placeholder, styleType = 'default', error,
|
||||||
|
onChange, onEnter }: Props) => {
|
||||||
|
const [isShowPassword, setIsShowPassword] = useState<boolean>(false)
|
||||||
|
const toggleShowPassword = () => {
|
||||||
|
setIsShowPassword(!isShowPassword)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Inputcommon
|
||||||
|
value={value}
|
||||||
|
type={isShowPassword ? 'text' : 'password'}
|
||||||
|
styleType={styleType}
|
||||||
|
error={error}
|
||||||
|
placeholder={placeholder}
|
||||||
|
icon={<button className={s.iconPassword} onClick={toggleShowPassword}>
|
||||||
|
{isShowPassword ? <IconPassword /> : <IconPasswordCross />}
|
||||||
|
</button>}
|
||||||
|
isIconSuffix={true}
|
||||||
|
onChange={onChange}
|
||||||
|
onEnter={onEnter}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default InputPassword
|
@ -1,17 +1,12 @@
|
|||||||
|
@import '../../../../styles/utilities';
|
||||||
|
|
||||||
.formAuthen {
|
.formAuthen {
|
||||||
@apply bg-white w-full;
|
@apply bg-white w-full u-form;
|
||||||
.inner {
|
.inner {
|
||||||
@screen md {
|
@screen md {
|
||||||
max-width: 52rem;
|
width: 60rem;
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
.body {
|
|
||||||
> div {
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-bottom: 1.6rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.others {
|
.others {
|
||||||
@apply font-bold text-center;
|
@apply font-bold text-center;
|
||||||
margin-top: 4rem;
|
margin-top: 4rem;
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import React, { useRef, useEffect } from 'react'
|
import React, { useEffect, useRef } from 'react'
|
||||||
import { Inputcommon, ButtonCommon } from 'src/components/common'
|
import { ButtonCommon, Inputcommon } from 'src/components/common'
|
||||||
|
import InputPassword from 'src/components/common/InputPassword/InputPassword'
|
||||||
import { ROUTE } from 'src/utils/constanst.utils'
|
import { ROUTE } from 'src/utils/constanst.utils'
|
||||||
import SocialAuthen from '../SocialAuthen/SocialAuthen'
|
|
||||||
import s from '../FormAuthen.module.scss'
|
|
||||||
import styles from './FormLogin.module.scss'
|
|
||||||
import classNames from 'classnames'
|
|
||||||
import { CustomInputCommon } from 'src/utils/type.utils'
|
import { CustomInputCommon } from 'src/utils/type.utils'
|
||||||
|
import s from '../FormAuthen.module.scss'
|
||||||
|
import SocialAuthen from '../SocialAuthen/SocialAuthen'
|
||||||
|
import styles from './FormLogin.module.scss'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
isHide: boolean,
|
isHide: boolean,
|
||||||
@ -23,14 +23,13 @@ const FormLogin = ({ onSwitch, isHide }: Props) => {
|
|||||||
}, [isHide])
|
}, [isHide])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className={classNames({
|
<section className={s.formAuthen}>
|
||||||
[s.formAuthen]: true,
|
|
||||||
// [styles.hide]: isHide
|
|
||||||
})}>
|
|
||||||
<div className={s.inner}>
|
<div className={s.inner}>
|
||||||
<div className={s.body}>
|
<div className={s.body}>
|
||||||
<Inputcommon placeholder='Email Address' type='email' ref={emailRef} />
|
<Inputcommon placeholder='Email Address' type='email' ref={emailRef} />
|
||||||
<Inputcommon placeholder='Password' type='password' />
|
{/* <Inputcommon placeholder='Email Address' type='email' ref={emailRef}
|
||||||
|
isShowIconSuccess={true} isIconSuffix={true} /> */}
|
||||||
|
<InputPassword placeholder='Password'/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.bottom}>
|
<div className={styles.bottom}>
|
||||||
<Link href={ROUTE.FORGOT_PASSWORD}>
|
<Link href={ROUTE.FORGOT_PASSWORD}>
|
||||||
|
@ -24,12 +24,11 @@ const FormRegister = ({ onSwitch, isHide }: Props) => {
|
|||||||
<section className={classNames({
|
<section className={classNames({
|
||||||
[s.formAuthen]: true,
|
[s.formAuthen]: true,
|
||||||
[styles.formRegister]: true,
|
[styles.formRegister]: true,
|
||||||
// [styles.hide]: isHide
|
|
||||||
})}>
|
})}>
|
||||||
<div className={s.inner}>
|
<div className={s.inner}>
|
||||||
<div className={s.body}>
|
<div className={s.body}>
|
||||||
<Inputcommon placeholder='Email Address' type='email' ref={emailRef}/>
|
<Inputcommon placeholder='Email Address' type='email' ref={emailRef}/>
|
||||||
<Inputcommon placeholder='Password' type='password' />
|
<InputPassword placeholder='Password'/>
|
||||||
<div className={styles.passwordNote}>
|
<div className={styles.passwordNote}>
|
||||||
Must contain 8 characters with at least 1 uppercase and 1 lowercase letter and either 1 number or 1 special character.
|
Must contain 8 characters with at least 1 uppercase and 1 lowercase letter and either 1 number or 1 special character.
|
||||||
</div>
|
</div>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
@apply flex justify-center items-center min-h-screen;
|
@apply flex justify-center items-center min-h-screen;
|
||||||
.modal{
|
.modal{
|
||||||
@apply inline-block align-bottom bg-white relative;
|
@apply inline-block align-bottom bg-white relative;
|
||||||
max-width: 60rem;
|
max-width: 66.4rem;
|
||||||
padding: 3.2rem;
|
padding: 3.2rem;
|
||||||
box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.24);
|
box-shadow: 0px 8px 16px rgba(0, 0, 0, 0.24);
|
||||||
border-radius: 1.2rem;
|
border-radius: 1.2rem;
|
||||||
@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
.title{
|
.title{
|
||||||
@apply font-heading heading-3;
|
@apply font-heading heading-3;
|
||||||
padding: 0 0.8rem 0 0.8rem;
|
padding: 0 1.6rem 0 0.8rem;
|
||||||
}
|
}
|
||||||
.close{
|
.close{
|
||||||
@apply absolute;
|
@apply absolute;
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
@import "../../../styles/utilities";
|
||||||
|
|
||||||
|
.formUserInfo {
|
||||||
|
@apply u-form;
|
||||||
|
.inner {
|
||||||
|
@screen md {
|
||||||
|
width: 60rem;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.bottom {
|
||||||
|
@apply grid grid-cols-2;
|
||||||
|
margin-top: 4rem;
|
||||||
|
grid-gap: 1.6rem;
|
||||||
|
> button {
|
||||||
|
@apply w-full;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
import classNames from 'classnames';
|
||||||
|
import Link from 'next/link';
|
||||||
|
import React, { useRef } from 'react';
|
||||||
|
import { useModalCommon } from 'src/components/hooks/useModalCommon';
|
||||||
|
import { CustomInputCommon } from 'src/utils/type.utils';
|
||||||
|
import { Inputcommon } from '..';
|
||||||
|
import ButtonCommon from '../ButtonCommon/ButtonCommon';
|
||||||
|
import ModalCommon from '../ModalCommon/ModalCommon';
|
||||||
|
import s from './ModalCreateUserInfo.module.scss';
|
||||||
|
|
||||||
|
// todo: remove
|
||||||
|
interface Props {
|
||||||
|
demoVisible: boolean,
|
||||||
|
demoCloseModal: () => void,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ModalCreateUserInfo = ({ demoVisible: visible, demoCloseModal: closeModal }: Props) => {
|
||||||
|
// const { visible, closeModal } = useModalCommon({ initialValue: false})
|
||||||
|
const firstInputRef = useRef<CustomInputCommon>(null)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ModalCommon visible={visible} onClose={closeModal} title='Enter your Information'>
|
||||||
|
<div className={s.formUserInfo}>
|
||||||
|
<div className={s.inner}>
|
||||||
|
<div className={s.body}>
|
||||||
|
<Inputcommon placeholder='Street Address' ref={firstInputRef} />
|
||||||
|
<Inputcommon placeholder='City' />
|
||||||
|
<div className={s.line}>
|
||||||
|
{/* todo: select, not input */}
|
||||||
|
<Inputcommon placeholder='State' />
|
||||||
|
<Inputcommon placeholder='Zip code' />
|
||||||
|
</div>
|
||||||
|
<Inputcommon placeholder='Phone (delivery contact)' />
|
||||||
|
</div>
|
||||||
|
<div className={s.bottom}>
|
||||||
|
<ButtonCommon size='large' onClick={closeModal} type='light'>Skip</ButtonCommon>
|
||||||
|
<ButtonCommon size='large'>Submit</ButtonCommon>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalCommon>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ModalCreateUserInfo;
|
@ -1,32 +1,69 @@
|
|||||||
@import "../../../styles/utilities";
|
@import "../../../styles/utilities";
|
||||||
|
|
||||||
.select{
|
.select{
|
||||||
@apply rounded-lg border-solid;
|
background-color: var(--white);
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1.2rem 1.6rem;
|
|
||||||
&.base{
|
&.base{
|
||||||
width: 18.6rem;
|
width: 20.6rem;
|
||||||
height: 4.8rem;
|
.selectTrigger{
|
||||||
|
width: 20.6rem;
|
||||||
|
padding: 1.2rem 1.6rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.large{
|
&.large{
|
||||||
width: 34.25rem;
|
width: 34.25rem;
|
||||||
height: 5.6rem;
|
.selectTrigger{
|
||||||
|
width: 34.25rem;
|
||||||
|
padding: 1.6rem 1.6rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.default{
|
&.default{
|
||||||
@apply border;
|
.selectTrigger{
|
||||||
|
@apply border-solid border border-current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.custom{
|
||||||
|
.selectTrigger{
|
||||||
|
@apply border-2;
|
||||||
|
border-color: var(--border-line);
|
||||||
|
color: var(--text-label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.isActive{
|
||||||
|
.selectOptionWrapper{
|
||||||
|
@apply block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.selectTrigger{
|
||||||
|
@apply outline-none flex justify-between;
|
||||||
|
color: var(--text-active);
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
|
||||||
|
}
|
||||||
|
.selectOptionWrapper{
|
||||||
|
@apply outline-none hidden z-10 absolute;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
background-color: var(--white);
|
||||||
|
padding: 0.4rem 0rem 0.4rem 0rem;
|
||||||
|
margin-top: 0.6rem;
|
||||||
|
&.base{
|
||||||
|
width: 20.6rem;
|
||||||
|
}
|
||||||
|
&.large{
|
||||||
|
width: 34.25rem;
|
||||||
|
}
|
||||||
|
&.default{
|
||||||
|
@apply border-solid border border-current;
|
||||||
}
|
}
|
||||||
&.custom{
|
&.custom{
|
||||||
@apply border-2;
|
@apply border-2;
|
||||||
border-color: var(--border-line);
|
border-color: var(--border-line);
|
||||||
color: var(--text-label);
|
color: var(--text-label);
|
||||||
}
|
}
|
||||||
.option{
|
&.active{
|
||||||
&:hover{
|
@apply hidden;
|
||||||
background-color: black;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,26 +1,75 @@
|
|||||||
import s from './SelectCommon.module.scss'
|
import s from './SelectCommon.module.scss'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
|
import { useState, useRef, useEffect } from 'react'
|
||||||
|
import { IconVectorDown } from 'src/components/icons'
|
||||||
|
import SelectOption from './SelectOption/SelectOption'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
placeHolder? : string,
|
children? : React.ReactNode,
|
||||||
size?: 'base' | 'large',
|
size?: 'base' | 'large',
|
||||||
type?: 'default' | 'custom',
|
type?: 'default' | 'custom',
|
||||||
option: {name: string}[],
|
option: {name: string}[],
|
||||||
}
|
}
|
||||||
|
|
||||||
const SelectCommon = ({ type = 'default', size = 'base', option, placeHolder }: Props) => {
|
const SelectCommon = ({ type = 'default', size = 'base', option, children }: Props) => {
|
||||||
return(
|
const [isActive, setActive] = useState(false)
|
||||||
<select className={classNames({
|
const [selectedName, setSelectedName] = useState(children)
|
||||||
[s.select] : true,
|
const ref = useRef<HTMLDivElement>(null)
|
||||||
[s[type]]: !!type,
|
|
||||||
[s[size]]: !!size,
|
useEffect(() => {
|
||||||
})}
|
const handleClick = (event: MouseEvent) => {
|
||||||
>
|
const { target } = event;
|
||||||
<option disabled selected hidden>{placeHolder}</option>
|
if (!ref?.current || ref?.current.contains(target as Node)) {
|
||||||
{
|
return
|
||||||
option.map(item => <option className={s.option} value={item.name}> {item.name} </option>)
|
|
||||||
}
|
}
|
||||||
</select>
|
else{
|
||||||
|
setActive(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('click', handleClick)
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', handleClick)
|
||||||
|
}
|
||||||
|
}, [ref])
|
||||||
|
|
||||||
|
const changeActiveStatus = () => {
|
||||||
|
setActive(!isActive)
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeSelectedName = (item:string) => {
|
||||||
|
setSelectedName(item)
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<>
|
||||||
|
<div className={classNames({
|
||||||
|
[s.select] : true,
|
||||||
|
[s[size]] : !!size,
|
||||||
|
[s[type]] : !!type,
|
||||||
|
[s.isActive] : isActive,
|
||||||
|
})}
|
||||||
|
onClick = { changeActiveStatus }
|
||||||
|
ref = {ref}
|
||||||
|
>
|
||||||
|
<div className={classNames({
|
||||||
|
[s.selectTrigger] : true,
|
||||||
|
|
||||||
|
})}
|
||||||
|
>{selectedName}<IconVectorDown /></div>
|
||||||
|
|
||||||
|
<div className={classNames({
|
||||||
|
[s.selectOptionWrapper] : true,
|
||||||
|
[s[type]] : !!type,
|
||||||
|
[s[size]] : !!size,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
option.map(item =>
|
||||||
|
<SelectOption itemName={item.name} onClick={changeSelectedName} size={size} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
@import "../../../../styles/utilities";
|
||||||
|
|
||||||
|
.selectOption {
|
||||||
|
@apply outline-none;
|
||||||
|
background-color: var(--white);
|
||||||
|
&.base{
|
||||||
|
width: 20.4rem;
|
||||||
|
padding: 0.8rem 1.6rem;
|
||||||
|
}
|
||||||
|
&.large{
|
||||||
|
width: 33.75rem;
|
||||||
|
padding: 0.8rem 1.6rem;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: var(--gray);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
import s from './SelectOption.module.scss'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
interface Props{
|
||||||
|
onClick: (value: string) => void,
|
||||||
|
itemName: string,
|
||||||
|
size: 'base' | 'large',
|
||||||
|
}
|
||||||
|
|
||||||
|
const SelectOption = ({onClick, itemName, size}: Props) => {
|
||||||
|
|
||||||
|
const changeName = () => {
|
||||||
|
onClick(itemName)
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<div className={classNames({
|
||||||
|
[s.selectOption] : true,
|
||||||
|
[s[size]] : !!size,
|
||||||
|
})}
|
||||||
|
onClick = {changeName}
|
||||||
|
>{itemName}</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectOption
|
@ -12,6 +12,7 @@ export { default as ViewAllItem} from './ViewAllItem/ViewAllItem'
|
|||||||
export { default as ItemWishList} from './ItemWishList/ItemWishList'
|
export { default as ItemWishList} from './ItemWishList/ItemWishList'
|
||||||
export { default as Logo} from './Logo/Logo'
|
export { default as Logo} from './Logo/Logo'
|
||||||
export { default as Inputcommon} from './InputCommon/InputCommon'
|
export { default as Inputcommon} from './InputCommon/InputCommon'
|
||||||
|
export { default as InputPassword} from './InputPassword/InputPassword'
|
||||||
export { default as CheckboxCommon} from './CheckboxCommon/CheckboxCommon'
|
export { default as CheckboxCommon} from './CheckboxCommon/CheckboxCommon'
|
||||||
export { default as Author} from './Author/Author'
|
export { default as Author} from './Author/Author'
|
||||||
export { default as DateTime} from './DateTime/DateTime'
|
export { default as DateTime} from './DateTime/DateTime'
|
||||||
@ -30,3 +31,4 @@ export { default as SelectCommon} from './SelectCommon/SelectCommon'
|
|||||||
export { default as ModalCommon} from './ModalCommon/ModalCommon'
|
export { default as ModalCommon} from './ModalCommon/ModalCommon'
|
||||||
export { default as ModalConfirm} from "./ModalConfirm/ModalConfirm"
|
export { default as ModalConfirm} from "./ModalConfirm/ModalConfirm"
|
||||||
export { default as ModalInfo} from "./ModalInfo/ModalInfo"
|
export { default as ModalInfo} from "./ModalInfo/ModalInfo"
|
||||||
|
export { default as ModalCreateUserInfo} from './ModalCreateUserInfo/ModalCreateUserInfo'
|
||||||
|
11
src/components/icons/IconCheck.tsx
Normal file
11
src/components/icons/IconCheck.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const IconCheck = () => {
|
||||||
|
return (
|
||||||
|
<svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M14.7104 1.20986C14.6175 1.11613 14.5069 1.04174 14.385 0.990969C14.2632 0.940201 14.1324 0.914062 14.0004 0.914062C13.8684 0.914062 13.7377 0.940201 13.6159 0.990969C13.494 1.04174 13.3834 1.11613 13.2904 1.20986L5.84044 8.66986L2.71044 5.52986C2.61392 5.43662 2.49998 5.36331 2.37512 5.3141C2.25026 5.2649 2.11694 5.24077 1.98276 5.24309C1.84858 5.24541 1.71617 5.27414 1.59309 5.32763C1.47001 5.38113 1.35868 5.45834 1.26544 5.55486C1.1722 5.65138 1.09889 5.76532 1.04968 5.89018C1.00048 6.01503 0.976347 6.14836 0.978669 6.28254C0.98099 6.41672 1.00972 6.54913 1.06321 6.67221C1.1167 6.79529 1.19392 6.90662 1.29044 6.99986L5.13044 10.8399C5.2234 10.9336 5.334 11.008 5.45586 11.0588C5.57772 11.1095 5.70843 11.1357 5.84044 11.1357C5.97245 11.1357 6.10316 11.1095 6.22502 11.0588C6.34687 11.008 6.45748 10.9336 6.55044 10.8399L14.7104 2.67986C14.8119 2.58622 14.893 2.47257 14.9484 2.34607C15.0038 2.21957 15.0324 2.08296 15.0324 1.94486C15.0324 1.80676 15.0038 1.67015 14.9484 1.54365C14.893 1.41715 14.8119 1.3035 14.7104 1.20986Z" fill="#4EA674" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconCheck
|
11
src/components/icons/IconError.tsx
Normal file
11
src/components/icons/IconError.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const IconError = () => {
|
||||||
|
return (
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 5C9.73479 5 9.48043 5.10536 9.2929 5.29289C9.10536 5.48043 9 5.73478 9 6V10C9 10.2652 9.10536 10.5196 9.2929 10.7071C9.48043 10.8946 9.73479 11 10 11C10.2652 11 10.5196 10.8946 10.7071 10.7071C10.8946 10.5196 11 10.2652 11 10V6C11 5.73478 10.8946 5.48043 10.7071 5.29289C10.5196 5.10536 10.2652 5 10 5ZM10.92 13.62C10.8981 13.5563 10.8679 13.4957 10.83 13.44L10.71 13.29C10.5694 13.1512 10.3908 13.0572 10.1968 13.0199C10.0028 12.9825 9.80212 13.0034 9.62 13.08C9.49882 13.1306 9.38721 13.2017 9.29 13.29C9.19732 13.3834 9.124 13.4943 9.07423 13.6161C9.02447 13.7379 8.99924 13.8684 9 14C9.00159 14.1307 9.02876 14.2598 9.08 14.38C9.12492 14.5041 9.19657 14.6168 9.28989 14.7101C9.38321 14.8034 9.49591 14.8751 9.62 14.92C9.73971 14.9729 9.86913 15.0002 10 15.0002C10.1309 15.0002 10.2603 14.9729 10.38 14.92C10.5041 14.8751 10.6168 14.8034 10.7101 14.7101C10.8034 14.6168 10.8751 14.5041 10.92 14.38C10.9712 14.2598 10.9984 14.1307 11 14C11.0049 13.9334 11.0049 13.8666 11 13.8C10.9828 13.7362 10.9558 13.6755 10.92 13.62ZM10 0C8.02219 0 6.08879 0.58649 4.4443 1.6853C2.79981 2.78412 1.51809 4.3459 0.761209 6.17317C0.00433284 8.00043 -0.193701 10.0111 0.192152 11.9509C0.578004 13.8907 1.53041 15.6725 2.92894 17.0711C4.32746 18.4696 6.10929 19.422 8.0491 19.8079C9.98891 20.1937 11.9996 19.9957 13.8268 19.2388C15.6541 18.4819 17.2159 17.2002 18.3147 15.5557C19.4135 13.9112 20 11.9778 20 10C20 8.68678 19.7413 7.38642 19.2388 6.17317C18.7363 4.95991 17.9997 3.85752 17.0711 2.92893C16.1425 2.00035 15.0401 1.26375 13.8268 0.761205C12.6136 0.258658 11.3132 0 10 0ZM10 18C8.41775 18 6.87104 17.5308 5.55544 16.6518C4.23985 15.7727 3.21447 14.5233 2.60897 13.0615C2.00347 11.5997 1.84504 9.99113 2.15372 8.43928C2.4624 6.88743 3.22433 5.46197 4.34315 4.34315C5.46197 3.22433 6.88743 2.4624 8.43928 2.15372C9.99113 1.84504 11.5997 2.00346 13.0615 2.60896C14.5233 3.21447 15.7727 4.23984 16.6518 5.55544C17.5308 6.87103 18 8.41775 18 10C18 12.1217 17.1572 14.1566 15.6569 15.6569C14.1566 17.1571 12.1217 18 10 18Z" fill="#D1644D" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconError
|
11
src/components/icons/IconPassword.tsx
Normal file
11
src/components/icons/IconPassword.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const IconPassword = () => {
|
||||||
|
return (
|
||||||
|
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M20.9196 7.6C18.8996 2.91 15.0996 0 10.9996 0C6.89958 0 3.09958 2.91 1.07958 7.6C1.02452 7.72617 0.996094 7.86234 0.996094 8C0.996094 8.13766 1.02452 8.27383 1.07958 8.4C3.09958 13.09 6.89958 16 10.9996 16C15.0996 16 18.8996 13.09 20.9196 8.4C20.9746 8.27383 21.0031 8.13766 21.0031 8C21.0031 7.86234 20.9746 7.72617 20.9196 7.6ZM10.9996 14C7.82958 14 4.82958 11.71 3.09958 8C4.82958 4.29 7.82958 2 10.9996 2C14.1696 2 17.1696 4.29 18.8996 8C17.1696 11.71 14.1696 14 10.9996 14ZM10.9996 4C10.2085 4 9.43509 4.2346 8.7773 4.67412C8.1195 5.11365 7.60681 5.73836 7.30406 6.46927C7.00131 7.20017 6.9221 8.00444 7.07644 8.78036C7.23078 9.55628 7.61174 10.269 8.17115 10.8284C8.73056 11.3878 9.44329 11.7688 10.2192 11.9231C10.9951 12.0775 11.7994 11.9983 12.5303 11.6955C13.2612 11.3928 13.8859 10.8801 14.3255 10.2223C14.765 9.56448 14.9996 8.79113 14.9996 8C14.9996 6.93913 14.5782 5.92172 13.828 5.17157C13.0779 4.42143 12.0604 4 10.9996 4ZM10.9996 10C10.604 10 10.2173 9.8827 9.88844 9.66294C9.55954 9.44318 9.30319 9.13082 9.15182 8.76537C9.00044 8.39991 8.96084 7.99778 9.03801 7.60982C9.11518 7.22186 9.30566 6.86549 9.58537 6.58579C9.86507 6.30608 10.2214 6.1156 10.6094 6.03843C10.9974 5.96126 11.3995 6.00087 11.7649 6.15224C12.1304 6.30362 12.4428 6.55996 12.6625 6.88886C12.8823 7.21776 12.9996 7.60444 12.9996 8C12.9996 8.53043 12.7889 9.03914 12.4138 9.41421C12.0387 9.78929 11.53 10 10.9996 10Z" fill="#8F8F8F" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconPassword
|
11
src/components/icons/IconPasswordCross.tsx
Normal file
11
src/components/icons/IconPasswordCross.tsx
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const IconPasswordCross = () => {
|
||||||
|
return (
|
||||||
|
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8.94409 4.08409C9.29485 4.03032 9.64923 4.00358 10.0041 4.00409C13.1841 4.00409 16.1741 6.29409 17.9141 10.0041C17.648 10.5687 17.3474 11.1164 17.0141 11.6441C16.9083 11.8079 16.8527 11.9991 16.8541 12.1941C16.8563 12.4123 16.9299 12.6238 17.0636 12.7964C17.1972 12.9689 17.3837 13.0929 17.5944 13.1496C17.8052 13.2063 18.0287 13.1924 18.2309 13.1102C18.433 13.0279 18.6027 12.8818 18.7141 12.6941C19.18 11.962 19.5847 11.1927 19.9241 10.3941C19.9777 10.2693 20.0054 10.1349 20.0054 9.99909C20.0054 9.86327 19.9777 9.72887 19.9241 9.60409C17.9041 4.91409 14.1041 2.00409 10.0041 2.00409C9.53476 2.00173 9.06618 2.04189 8.60409 2.12409C8.47277 2.14642 8.34713 2.19439 8.23435 2.26527C8.12157 2.33615 8.02385 2.42855 7.94678 2.53719C7.8697 2.64584 7.81479 2.7686 7.78516 2.89847C7.75553 3.02834 7.75177 3.16277 7.77409 3.29409C7.79642 3.42541 7.84439 3.55105 7.91527 3.66383C7.98615 3.77662 8.07855 3.87433 8.18719 3.95141C8.29584 4.02848 8.4186 4.0834 8.54847 4.11303C8.67834 4.14266 8.81277 4.14642 8.94409 4.12409V4.08409ZM1.71409 0.294092C1.62085 0.200853 1.51016 0.126892 1.38834 0.0764319C1.26652 0.0259715 1.13595 0 1.00409 0C0.872232 0 0.741664 0.0259715 0.619842 0.0764319C0.49802 0.126892 0.38733 0.200853 0.294092 0.294092C0.105788 0.482395 0 0.73779 0 1.00409C0 1.27039 0.105788 1.52579 0.294092 1.71409L3.39409 4.80409C1.97966 6.16562 0.853948 7.79808 0.0840915 9.60409C0.0290282 9.73026 0.000606775 9.86643 0.000606775 10.0041C0.000606775 10.1417 0.0290282 10.2779 0.0840915 10.4041C2.10409 15.0941 5.90409 18.0041 10.0041 18.0041C11.8012 17.9917 13.5559 17.4566 15.0541 16.4641L18.2941 19.7141C18.3871 19.8078 18.4977 19.8822 18.6195 19.933C18.7414 19.9838 18.8721 20.0099 19.0041 20.0099C19.1361 20.0099 19.2668 19.9838 19.3887 19.933C19.5105 19.8822 19.6211 19.8078 19.7141 19.7141C19.8078 19.6211 19.8822 19.5105 19.933 19.3887C19.9838 19.2668 20.0099 19.1361 20.0099 19.0041C20.0099 18.8721 19.9838 18.7414 19.933 18.6195C19.8822 18.4977 19.8078 18.3871 19.7141 18.2941L1.71409 0.294092ZM8.07409 9.48409L10.5241 11.9341C10.3551 11.9826 10.1799 12.0061 10.0041 12.0041C9.47366 12.0041 8.96495 11.7934 8.58988 11.4183C8.21481 11.0432 8.00409 10.5345 8.00409 10.0041C8.00204 9.82828 8.02562 9.6531 8.07409 9.48409ZM10.0041 16.0041C6.82409 16.0041 3.83409 13.7141 2.10409 10.0041C2.75018 8.57784 3.66716 7.29067 4.80409 6.21409L6.57409 8.00409C6.15834 8.76289 5.99983 9.63604 6.12235 10.4925C6.24487 11.3491 6.64181 12.1428 7.25362 12.7546C7.86543 13.3664 8.65912 13.7633 9.51563 13.8858C10.3721 14.0084 11.2453 13.8498 12.0041 13.4341L13.5941 15.0041C12.5052 15.645 11.2675 15.9897 10.0041 16.0041Z" fill="#8F8F8F" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconPasswordCross
|
21
src/components/icons/IconVectorDown.tsx
Normal file
21
src/components/icons/IconVectorDown.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
|
||||||
|
const IconVectorDown = ({ ...props }) => {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="-6 -9 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M10.9999 1.16994C10.8126 0.983692 10.5591 0.87915 10.2949 0.87915C10.0308 0.87915 9.77731 0.983692 9.58995 1.16994L5.99995 4.70994L2.45995 1.16994C2.27259 0.983692 2.01913 0.87915 1.75495 0.87915C1.49076 0.87915 1.23731 0.983692 1.04995 1.16994C0.95622 1.26291 0.881826 1.37351 0.831057 1.49537C0.780288 1.61723 0.75415 1.74793 0.75415 1.87994C0.75415 2.01195 0.780288 2.14266 0.831057 2.26452C0.881826 2.38638 0.95622 2.49698 1.04995 2.58994L5.28995 6.82994C5.38291 6.92367 5.49351 6.99806 5.61537 7.04883C5.73723 7.0996 5.86794 7.12574 5.99995 7.12574C6.13196 7.12574 6.26267 7.0996 6.38453 7.04883C6.50638 6.99806 6.61699 6.92367 6.70995 6.82994L10.9999 2.58994C11.0937 2.49698 11.1681 2.38638 11.2188 2.26452C11.2696 2.14266 11.2957 2.01195 11.2957 1.87994C11.2957 1.74793 11.2696 1.61723 11.2188 1.49537C11.1681 1.37351 11.0937 1.26291 10.9999 1.16994Z"
|
||||||
|
fill="#141414"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconVectorDown
|
@ -9,9 +9,14 @@ export { default as IconHome } from './IconHome'
|
|||||||
export { default as IconShopping } from './IconShopping'
|
export { default as IconShopping } from './IconShopping'
|
||||||
export { default as IconHeart } from './IconHeart'
|
export { default as IconHeart } from './IconHeart'
|
||||||
export { default as IconVector } from './IconVector'
|
export { default as IconVector } from './IconVector'
|
||||||
|
export { default as IconVectorDown } from './IconVectorDown'
|
||||||
export { default as IconFacebookColor } from './IconFacebookColor'
|
export { default as IconFacebookColor } from './IconFacebookColor'
|
||||||
export { default as IconGoogleColor } from './IconGoogleColor'
|
export { default as IconGoogleColor } from './IconGoogleColor'
|
||||||
export { default as IconApple } from './IconApple'
|
export { default as IconApple } from './IconApple'
|
||||||
export { default as ArrowLeft } from './ArrowLeft'
|
export { default as ArrowLeft } from './ArrowLeft'
|
||||||
export { default as ArrowRight } from './ArrowRight'
|
export { default as ArrowRight } from './ArrowRight'
|
||||||
export { default as Close } from './Close'
|
export { default as Close } from './Close'
|
||||||
|
export { default as IconPassword } from './IconPassword'
|
||||||
|
export { default as IconPasswordCross } from './IconPasswordCross'
|
||||||
|
export { default as IconError } from './IconError'
|
||||||
|
export { default as IconCheck } from './IconCheck'
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
margin-bottom: 2.8rem;
|
margin-bottom: 2.8rem;
|
||||||
.left {
|
.left {
|
||||||
@apply hidden;
|
@apply hidden;
|
||||||
|
margin-bottom: 3rem;
|
||||||
}
|
}
|
||||||
@screen xl {
|
@screen xl {
|
||||||
@apply grid;
|
@apply grid;
|
||||||
|
@ -2,6 +2,7 @@ import React from 'react'
|
|||||||
import { Banner } from 'src/components/common'
|
import { Banner } from 'src/components/common'
|
||||||
import s from './HomeBanner.module.scss'
|
import s from './HomeBanner.module.scss'
|
||||||
import BannerImgRight from './assets/banner_full.png'
|
import BannerImgRight from './assets/banner_full.png'
|
||||||
|
import BannerImgRight2 from './assets/banner_product.png'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
className?: string
|
className?: string
|
||||||
@ -13,14 +14,25 @@ const HomeBanner = ({ }: Props) => {
|
|||||||
<div className={s.homeBanner}>
|
<div className={s.homeBanner}>
|
||||||
<section className={s.left}>
|
<section className={s.left}>
|
||||||
<div className={s.text}>
|
<div className={s.text}>
|
||||||
Freshness<br/>guaranteed
|
Freshness<br />guaranteed
|
||||||
</div>
|
</div>
|
||||||
</section >
|
</section >
|
||||||
<Banner
|
<Banner
|
||||||
title="Save 15% on your first order"
|
data={
|
||||||
subtitle="Last call! Shop deep deals on 100+ bulk picks while you can."
|
[{
|
||||||
imgLink={BannerImgRight.src}
|
title: "Save 15% on your first order",
|
||||||
size="small"
|
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
||||||
|
imgLink: BannerImgRight.src,
|
||||||
|
size: "small",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Save 15% on your first order 2",
|
||||||
|
subtitle: "Last call! Shop deep deals on 100+ bulk picks while you can.",
|
||||||
|
imgLink: BannerImgRight2.src,
|
||||||
|
size: "small",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</div >
|
</div >
|
||||||
)
|
)
|
||||||
|
BIN
src/components/modules/home/HomeBanner/assets/banner_product.png
Normal file
BIN
src/components/modules/home/HomeBanner/assets/banner_product.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 KiB |
@ -80,7 +80,7 @@
|
|||||||
font-size: 10px;
|
font-size: 10px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spacing-horizontal {
|
.spacing-horizontal {
|
||||||
padding-left: 2rem;
|
padding-left: 2rem;
|
||||||
padding-right: 2rem;
|
padding-right: 2rem;
|
||||||
@ -119,4 +119,22 @@
|
|||||||
.font-logo {
|
.font-logo {
|
||||||
font-family: var(--font-logo);
|
font-family: var(--font-logo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.u-form {
|
||||||
|
.body {
|
||||||
|
> div {
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-bottom: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.line {
|
||||||
|
@apply flex justify-between items-center;
|
||||||
|
> div {
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 1.6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user