init: ProducrCard

This commit is contained in:
unknown
2021-08-24 16:25:08 +07:00
22 changed files with 362 additions and 62 deletions

View File

@@ -5,12 +5,28 @@
display: flex;
justify-content: center;
align-items: center;
padding: 1.6rem 3.2rem;
// padding: 1.6rem 3.2rem;
padding: 0.8rem 1.6rem;
width: 100%;
&:disabled {
filter: brightness(0.9);
cursor: not-allowed;
color: var(--disabled);
}
&:hover {
@apply shadow-md;
&:not(:disabled) {
filter: brightness(1.05);
}
}
&:focus {
outline: none;
filter: brightness(1.05);
}
&:focus-visible {
outline: 2px solid var(--text-active);
}
&.loading {
&::before {
content: "";
@@ -24,20 +40,6 @@
margin-right: 0.8rem;
}
}
&:hover {
@apply shadow-md;
&:not(:disabled) {
filter: brightness(1.05);
}
}
&:focus {
outline: none;
filter: brightness(1.05);
}
&:focus-visible {
outline: 2px solid var(--text-active);
}
&.light {
@apply text-base bg-white;
@@ -48,8 +50,30 @@
}
}
}
&.ghost {
@apply bg-white;
color: var(--primary);
border: 1px solid var(--primary);
&.loading {
&::before {
border-top-color: var(--primary);
}
}
}
&.onlyIcon {
padding: 0.8rem;
.icon {
margin: 0;
}
}
&.large {
padding: 3.2rem 4.8rem;
&.onlyIcon {
padding: 1.6rem;
}
&.loading {
&::before {
width: 2.4rem;
@@ -58,8 +82,21 @@
}
}
&.preserve {
flex-direction: row-reverse;
.icon {
margin: 0 0 0 1.6rem;
}
}
.icon {
margin: 0 1.6rem 0 0;
}
.label,
.icon {
margin-right: 0.8rem;
svg path {
fill: currentColor;
}

View File

@@ -1,26 +1,28 @@
import classNames from 'classnames'
import React from 'react'
import { ButonType, ButtonSize } from 'src/utils/constanst.utils'
import React, { memo } from 'react'
import s from './ButtonCommon.module.scss'
interface Props {
children?: any,
type?: ButonType,
size?: ButtonSize,
icon?: any,
children?: React.ReactNode,
type?: 'primary' | 'light' | 'ghost',
size?: 'default' | 'large',
icon?: React.ReactNode,
isIconSuffix?: boolean,
loading?: boolean,
disabled?: boolean,
onClick?: () => void,
}
const ButtonCommon = ({ type = ButonType.primary, size = ButtonSize.default,
icon, loading, disabled, children, onClick }: Props) => {
const ButtonCommon = memo(({ type = 'primary', size = 'default', loading = false, isIconSuffix = false,
icon, disabled, children, onClick }: Props) => {
return (
<button className={classNames({
[s.buttonCommon]: true,
[s[type]]: !!type,
[s[size]]: !!size,
[s.loading]: loading,
[s.preserve]: isIconSuffix,
[s.onlyIcon]: icon && !children,
})}
disabled={disabled}
onClick={onClick}
@@ -31,6 +33,6 @@ const ButtonCommon = ({ type = ButonType.primary, size = ButtonSize.default,
<span className={s.label}>{children}</span>
</button>
)
}
})
export default ButtonCommon

View File

@@ -0,0 +1,26 @@
import React, { memo } from 'react'
import { IconBuy } from 'src/components/icons'
import ButtonCommon from '../ButtonCommon/ButtonCommon'
interface Props {
type?: 'primary' | 'light' | 'ghost',
size?: 'default' | 'large',
loading?: boolean,
disabled?: boolean,
onClick?: () => void,
}
const ButtonIconBuy = memo(({ type = 'light', size = 'default', loading = false, disabled, onClick }: Props) => {
return (
<ButtonCommon
type={type}
size={size}
loading={loading}
disabled={disabled}
onClick={onClick}
icon={<IconBuy />}
/>
)
})
export default ButtonIconBuy

View File

@@ -0,0 +1,43 @@
@import "../../../styles/utilities";
.inputWrap {
@apply flex items-center relative;
.icon {
@apply absolute;
content: "";
left: 1.6rem;
margin-right: 1.6rem;
svg path {
fill: currentColor;
}
}
.icon + .inputCommon {
padding-left: 4.8rem;
}
.inputCommon {
@apply block w-full transition-all duration-200 rounded;
padding: 1.6rem;
border: 1px solid var(--border-line);
&:hover,
&:focus,
&:active {
outline: none;
border: 1px solid var(--primary);
@apply shadow-md;
}
&::placeholder {
@apply text-label;
}
&.custom {
@apply custom-border-radius border-none;
background: var(--gray);
&:hover,
&:focus,
&:active {
border: 1px solid var(--primary);
}
}
}
}

View File

@@ -0,0 +1,59 @@
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
import { KEY } from 'src/utils/constanst.utils';
import s from './InputCommon.module.scss';
type Ref = {
focus: () => void
} | null;
interface Props {
children?: React.ReactNode,
value?: string | number,
placeholder?: string,
type?: 'text' | 'number',
styleType?: 'default' | 'custom',
icon?: React.ReactNode,
onChange?: (value: string | number) => void,
onEnter?: (value: string | number) => void,
}
const InputCommon = forwardRef<Ref, Props>(({ value, placeholder, type, styleType = 'default', icon,
onChange, onEnter }: Props, ref) => {
const inputElementRef = useRef<HTMLInputElement>(null);
useImperativeHandle(ref, () => ({
focus: () => {
inputElementRef.current?.focus();
},
}));
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
onChange && onChange(e.target.value)
}
const handleKeyDown = (e: any) => {
if (e.key === KEY.ENTER && onEnter) {
const value = inputElementRef.current?.value || ''
onEnter(value)
}
}
return (
<div className={s.inputWrap}>
{
icon && <span className={s.icon}>{icon}</span>
}
<input
ref={inputElementRef}
value={value}
type={type}
placeholder={placeholder}
onChange={handleChange}
onKeyDown={handleKeyDown}
className={`${s.inputCommon} ${s[styleType]}`}
/>
</div>
)
})
export default InputCommon

View File

@@ -0,0 +1,22 @@
import React from 'react';
import { IconSearch } from 'src/components/icons';
import { LANGUAGE } from 'src/utils/language.utils';
import { Inputcommon } from '..';
interface Props {
onChange?: (value: string | number) => void,
onEnter?: (value: string | number) => void,
}
const InputSearch = ({ onChange, onEnter }: Props) => {
return (
<Inputcommon placeholder={LANGUAGE.PLACE_HOLDER.SEARCH}
styleType='custom'
icon={<IconSearch />}
onChange={onChange}
onEnter={onEnter}
/>
)
}
export default InputSearch

View File

@@ -0,0 +1,52 @@
.productCardWarpper{
max-width: 20.8rem;
max-height: 31.8rem;
padding: 1.2rem 1.2rem 0 1.2rem;
@apply border border-solid border-black;
.cardTop{
@apply border border-solid border-yellow-300 relative;
max-height: 13.8rem;
.productImage{
@apply flex justify-center items-center;
img{
@apply inline;
}
.productLabel{
@apply absolute left-0 bottom-0;
}
}
}
.cardMid{
padding: 1.6rem 0;
.cardMid{
.productname{
font-weight: bold;
line-height: 2.4rem;
font-size: 1.6rem;
color: var(--text-active);
}
.productWeight{
font-size: 1.2rem;
line-height: 2rem;
letter-spacing: 0.01em;
color: var(--text-base);
}
}
.cardMidBot{
margin-top: 2.8rem;
@apply flex justify-between items-center border-t border-solid border-line;
.productPrice{
@apply font-bold;
font-size: 2rem;
line-height: 2.8rem;
letter-spacing: -0.01em;
}
}
}
.cardBot{
@apply flex justify-between items-center;
.cardButton{
width: 13.6rem;
}
}
}

View File

@@ -0,0 +1,59 @@
import React from 'react'
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
buttonText?: string
imageSrc: string
}
const ProductCard = ({
category,
name,
weight,
price,
buttonText = 'Buy Now',
imageSrc,
}: ProductCardProps) => {
return (
<section className={s.productCardWarpper}>
<section className={s.cardTop}>
<div className={s.productImage}>
<img src={imageSrc} alt="image" />
<div className={s.productLabel}>
<LabelCommon shape="half">{category}</LabelCommon>
</div>
</div>
</section>
<section className={s.cardMid}>
<div className={s.cardMidTop}>
<div className={s.productname}>{name} </div>
<div className={s.productWeight}>{weight}</div>
</div>
<div className={s.cardMidBot}>
<div className={s.productPrice}>{price}</div>
<div className={s.wishList}>
<ItemWishList />
</div>
</div>
</section>
<section className={s.cardBot}>
<div className={s.cardIcon}>
<ButtonIconBuy/>
</div>
<div className={s.cardButton}>
<ButtonCommon type="ghost">{buttonText}</ButtonCommon>
</div>
</section>
</section>
)
}
export default ProductCard

View File

@@ -3,7 +3,11 @@ export { default as Layout } from './Layout/Layout'
export { default as CarouselCommon } from './CarouselCommon/CarouselCommon'
export { default as QuanittyInput } from './QuanittyInput/QuanittyInput'
export { default as LabelCommon } from './LabelCommon/LabelCommon'
export { default as ProductCard } from './ProductCard/ProductCard'
export { default as Head } from './Head/Head'
export { default as ViewAllItem} from './ViewAllItem/ViewAllItem'
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 InputSearch} from './InputSearch/InputSearch'
export { default as ButtonIconBuy} from './ButtonIconBuy/ButtonIconBuy'