mirror of
https://github.com/vercel/commerce.git
synced 2025-07-22 20:26:49 +00:00
🎨 styles: message common
:%s
This commit is contained in:
@@ -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> */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@@ -41,4 +41,5 @@ const Banner = memo(({ data }: Props) => {
|
||||
)
|
||||
})
|
||||
|
||||
Banner.displayName = 'Banner'
|
||||
export default Banner
|
||||
|
@@ -0,0 +1,7 @@
|
||||
.messageCommon {
|
||||
@apply fixed;
|
||||
top: 2.4rem;
|
||||
left: 50%;
|
||||
z-index: 20000;
|
||||
transform: translateX(-50%);
|
||||
}
|
26
src/components/common/MessageCommon/MessageCommon.tsx
Normal file
26
src/components/common/MessageCommon/MessageCommon.tsx
Normal 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
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -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
|
@@ -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'
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user