mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 22:11:56 +08:00
Improve: optimize message component
This commit is contained in:
parent
e6b0e9a4ed
commit
d18ca26bad
@ -4,89 +4,123 @@ import classnames from 'classnames'
|
|||||||
import { unmountComponentAtNode, render } from 'react-dom'
|
import { unmountComponentAtNode, render } from 'react-dom'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
|
const noop = () => {}
|
||||||
|
const TYPE_ICON_MAP = {
|
||||||
|
info: 'info',
|
||||||
|
success: 'check',
|
||||||
|
warning: 'info-o',
|
||||||
|
error: 'close'
|
||||||
|
}
|
||||||
|
|
||||||
type NoticeType = 'success' | 'info' | 'warning' | 'error'
|
type NoticeType = 'success' | 'info' | 'warning' | 'error'
|
||||||
type ConfigOnClose = () => void
|
|
||||||
interface ArgsProps {
|
interface ArgsProps {
|
||||||
content: string
|
content: string
|
||||||
type: NoticeType
|
type: NoticeType
|
||||||
duration?: number
|
duration?: number
|
||||||
onClose?: () => void
|
onClose?: typeof noop
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
content?: string
|
content?: string
|
||||||
|
type?: NoticeType
|
||||||
icon?: React.ReactNode
|
icon?: React.ReactNode
|
||||||
onClose?: () => void
|
|
||||||
duration?: number
|
duration?: number
|
||||||
removeComponent: () => void
|
onClose?: typeof noop
|
||||||
|
removeComponent: typeof noop
|
||||||
}
|
}
|
||||||
|
|
||||||
class Message extends React.Component <MessageProps, {}> {
|
export class Message extends React.Component <MessageProps, {}> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* static function to call Message directly
|
||||||
|
*/
|
||||||
|
static info = (
|
||||||
|
content: string,
|
||||||
|
duration?: number,
|
||||||
|
onClose?: typeof noop
|
||||||
|
) => showMessage({ type: 'info', content, duration, onClose })
|
||||||
|
|
||||||
|
static success = (
|
||||||
|
content: string,
|
||||||
|
duration?: number,
|
||||||
|
onClose?: typeof noop
|
||||||
|
) => showMessage({ type: 'success', content, duration, onClose })
|
||||||
|
|
||||||
|
static warning = (
|
||||||
|
content: string,
|
||||||
|
duration?: number,
|
||||||
|
onClose?: typeof noop
|
||||||
|
) => showMessage({ type: 'warning', content, duration, onClose })
|
||||||
|
|
||||||
|
static error = (
|
||||||
|
content: string,
|
||||||
|
duration?: number,
|
||||||
|
onClose?: typeof noop
|
||||||
|
) => showMessage({ type: 'error', content, duration, onClose })
|
||||||
|
|
||||||
static defaultProps: MessageProps = {
|
static defaultProps: MessageProps = {
|
||||||
content: '',
|
content: '',
|
||||||
icon: <Icon type={'info'} size={26}></Icon>,
|
type: 'info',
|
||||||
|
icon: <Icon type="info" size={16} />,
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
onClose: () => {},
|
onClose: noop,
|
||||||
removeComponent: () => {}
|
removeComponent: noop
|
||||||
}
|
}
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
visible: false
|
visible: false
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.setState({
|
// TODO: optimize animation
|
||||||
visible: true
|
// fix do not show animation when element mounted
|
||||||
})
|
setTimeout(() => this.setState({ visible: true }), 0)
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.setState({
|
this.setState({ visible: false })
|
||||||
visible: false
|
|
||||||
})
|
|
||||||
this.props.onClose()
|
this.props.onClose()
|
||||||
}, this.props.duration)
|
}, this.props.duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { removeComponent, icon, content } = this.props
|
const { removeComponent, icon, content, type } = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('message', { 'message-show': this.state.visible })} onTransitionEnd={() => !this.state.visible && removeComponent()}>
|
<div
|
||||||
{icon}
|
className={classnames('message', `message-${type}`, { 'message-show': this.state.visible })}
|
||||||
{content}
|
onTransitionEnd={() => !this.state.visible && removeComponent()}
|
||||||
</div>
|
>
|
||||||
|
<span className="message-icon">{icon}</span>
|
||||||
|
<span className="message-content">{content}</span>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function notice (args: ArgsProps) {
|
export function showMessage (args: ArgsProps) {
|
||||||
|
// create container element
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
document.body.appendChild(container)
|
document.body.appendChild(container)
|
||||||
|
|
||||||
|
// remove container when component unmount
|
||||||
const removeComponent = () => {
|
const removeComponent = () => {
|
||||||
const isUnMount = unmountComponentAtNode(container)
|
const isUnMount = unmountComponentAtNode(container)
|
||||||
if (isUnMount) {
|
if (isUnMount) {
|
||||||
document.body.removeChild(container)
|
document.body.removeChild(container)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const icon = <Icon type={args.type} size={26}></Icon>
|
|
||||||
|
const icon = <Icon type={TYPE_ICON_MAP[args.type]} size={16}></Icon>
|
||||||
|
const { type, content, duration, onClose } = args
|
||||||
const props: MessageProps = {
|
const props: MessageProps = {
|
||||||
icon,
|
icon,
|
||||||
content: args.content,
|
type,
|
||||||
|
content,
|
||||||
removeComponent,
|
removeComponent,
|
||||||
duration: args.duration,
|
duration,
|
||||||
onClose: args.onClose
|
onClose
|
||||||
}
|
}
|
||||||
|
|
||||||
render(<Message {...props} />, container)
|
render(<Message {...props} />, container)
|
||||||
}
|
}
|
||||||
export interface MessageApi {
|
|
||||||
info (content: string, type: NoticeType, duration?: number, onClose?: ConfigOnClose)
|
|
||||||
}
|
|
||||||
|
|
||||||
const api: any = {
|
|
||||||
}
|
|
||||||
const types = ['success', 'info', 'warning', 'error']
|
|
||||||
types.forEach(type => {
|
|
||||||
api[type] = (content: string, type: NoticeType, duration?: number, onClose?: ConfigOnClose) => notice({
|
|
||||||
content, duration, type, onClose
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
export default api as MessageApi
|
|
||||||
|
@ -3,12 +3,61 @@
|
|||||||
.message {
|
.message {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
left: 50%;
|
right: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transition: all 2000ms ease-out;
|
background: $color-white;
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 0 20px rgba($color-primary-dark, 0.2);
|
||||||
|
transition: all 200ms ease;
|
||||||
|
transform: translateX(100%);
|
||||||
|
|
||||||
|
.message-icon {
|
||||||
|
width: 36px;
|
||||||
|
flex: 1;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> i {
|
||||||
|
color: $color-white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content {
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 13px;
|
||||||
|
color: $color-primary-darken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-info {
|
||||||
|
.message-icon {
|
||||||
|
background: linear-gradient(135deg, $color-primary, $color-primary-dark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-success {
|
||||||
|
.message-icon {
|
||||||
|
background: linear-gradient(135deg, $color-green, darken($color-green, 5%));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-warning {
|
||||||
|
.message-icon {
|
||||||
|
background: linear-gradient(135deg, $color-orange, darken($color-orange, 5%));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-error {
|
||||||
|
.message-icon {
|
||||||
|
background: linear-gradient(135deg, $color-red, darken($color-red, 10%));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-show {
|
.message-show {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: all 2000ms ease-out;
|
transition: all 200ms ease;
|
||||||
|
transform: translateX(0);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user