🎨 styles: message common

:%s
This commit is contained in:
lytrankieio123 2021-09-29 13:39:40 +07:00
parent 4776ec6236
commit 02cc226ba7
7 changed files with 201 additions and 14 deletions

View File

@ -1,19 +1,35 @@
import { useEffect, useState } from 'react'
import {
ButtonCommon, Layout
} from 'src/components/common'
import { Layout, MessageCommon } from 'src/components/common'
import { MessageItemProps } from 'src/components/common/MessageCommon/MessageItem/MessageItem'
const data: MessageItemProps[] = [
{
id: 1,
content: 'Create account successfully',
type: 'error',
},
{
id: 2,
content: 'Create account successfully',
type: 'success',
},
{
id: 3,
content: 'Create account successfully',
type: 'warning',
},
{
id: 4,
content: 'Create account successfully',
type: 'info',
},
]
export default function Test() {
const [isLoading, setisLoading] = useState(false)
useEffect(() => {
setTimeout(() => {
setisLoading(true)
}, 3000)
}, [])
return (
<>
<ButtonCommon loading={isLoading}>Back to home</ButtonCommon>
<ButtonCommon type='light' loading={isLoading}>Back to home</ButtonCommon>
<ButtonCommon type='ghost' loading={isLoading}>Back to home</ButtonCommon>
<MessageCommon messages={data} />
{/* <MessageCommon type='error'>Create account successfully</MessageCommon>
<MessageCommon type='info'>Create account successfully</MessageCommon>
<MessageCommon type='warning'>Create account successfully</MessageCommon> */}
</>
)
}

View File

@ -41,4 +41,5 @@ const Banner = memo(({ data }: Props) => {
)
})
Banner.displayName = 'Banner'
export default Banner

View File

@ -0,0 +1,7 @@
.messageCommon {
@apply fixed;
top: 2.4rem;
left: 50%;
z-index: 20000;
transform: translateX(-50%);
}

View File

@ -0,0 +1,26 @@
import React, { memo } from 'react'
import s from './MessageCommon.module.scss'
import MessageItem, { MessageItemProps } from './MessageItem/MessageItem'
interface Props {
messages: MessageItemProps[]
onRemove?: (id?: number) => void
}
const MessageCommon = memo(({ messages, onRemove }: Props) => {
return (
<div className={s.messageCommon}>
{messages.map((item) => (
<MessageItem
key={item.id}
id={item.id}
content={item.content}
onRemove={onRemove}
/>
))}
</div>
)
})
MessageCommon.displayName = 'MessageCommon'
export default MessageCommon

View File

@ -0,0 +1,64 @@
@import "../../../../styles/utilities";
.messageItem {
@apply shadow-sm flex justify-center items-center cursor-default;
width: fit-content;
padding: 0.8rem 2.4rem;
margin-bottom: .8rem;
border-radius: 0.8rem;
transition: all .5s;
animation: showMessage .5s;
&.hide {
display: none;
}
.icon {
@apply flex justify-center items-center;
margin-right: 0.8rem;
svg {
width: 2rem;
height: 2rem;
}
}
&.info {
@apply bg-info-light;
color: var(--info-dark);
.icon svg path {
fill: var(--info);
}
}
&.success {
@apply bg-positive-light;
color: var(--positive-dark);
.icon svg path {
fill: var(--positive);
}
}
&.error {
@apply bg-negative-light;
color: var(--negative-dark);
.icon svg path {
fill: var(--negative);
}
}
&.warning {
@apply bg-warning-light;
color: var(--warning-dark);
.icon svg path {
fill: var(--warning);
}
}
}
@keyframes showMessage {
0% {
transform: translateY(-6rem);
opacity: .5;
}
100% {
transform: none;
opacity: 1;
}
}

View File

@ -0,0 +1,71 @@
import classNames from 'classnames'
import React, { memo, useEffect, useMemo, useState } from 'react'
import { IconCheck, IconError, IconInfo } from 'src/components/icons'
import s from './MessageItem.module.scss'
export interface MessageItemProps {
id?: number
content?: React.ReactNode
type?: 'info' | 'success' | 'error' | 'warning'
timeout?: number
onRemove?: (id?: number) => void
}
const MessageItem = memo(
({ id, content, type = 'success', timeout = 3000, onRemove }: MessageItemProps) => {
const [isHide, setIsHide] = useState<boolean>()
const [isMouseOver, setIsMouseOver] = useState(false)
const iconElement = useMemo(() => {
switch (type) {
case 'info':
return <IconInfo />
case 'success':
return <IconCheck />
case 'error':
return <IconError />
case 'warning':
return <IconError />
default:
return <IconInfo />
}
}, [type])
useEffect(() => {
setIsHide(false)
setTimeout(() => {
setIsHide(true)
}, timeout)
}, [timeout, isMouseOver])
useEffect(() => {
if (isHide && !isMouseOver && onRemove) {
onRemove(id)
}
}, [isHide, isMouseOver, onRemove, id])
const onMouseOver = () => {
setIsMouseOver(true)
}
const onMouseLeave = () => {
setIsMouseOver(false)
}
return (
<div
className={classNames(s.messageItem, s[type], {
[s.hide]: isHide && !isMouseOver,
})}
onMouseOver={onMouseOver}
onMouseLeave={onMouseLeave}
>
<span className={s.icon}>{iconElement}</span>
<span className={s.content}>{content}</span>
</div>
)
}
)
MessageItem.displayName = 'MessageItem'
export default MessageItem

View File

@ -1,4 +1,3 @@
import { InputFiledInForm } from 'src/components/common/InputFiledInForm/InputFiledInForm';
export { default as ButtonCommon } from './ButtonCommon/ButtonCommon'
export { default as Layout } from './Layout/Layout'
export { default as CarouselCommon } from './CarouselCommon/CarouselCommon'
@ -51,3 +50,6 @@ export { default as RecommendedRecipes} from './RecommendedRecipes/RecommendedRe
export { default as LayoutCheckout} from './LayoutCheckout/LayoutCheckout'
export { default as InputPasswordFiledInForm} from './InputPasswordFiledInForm/InputPasswordFiledInForm'
export { default as InputFiledInForm} from './InputFiledInForm/InputFiledInForm'
export { default as MessageCommon} from './MessageCommon/MessageCommon'