mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 14:01:56 +08:00
Migration: base component
This commit is contained in:
parent
658a26c2fc
commit
73d992ae94
1306
package-lock.json
generated
1306
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -33,11 +33,11 @@
|
|||||||
"@babel/preset-env": "^7.4.5",
|
"@babel/preset-env": "^7.4.5",
|
||||||
"@babel/preset-react": "^7.0.0",
|
"@babel/preset-react": "^7.0.0",
|
||||||
"@types/classnames": "^2.2.8",
|
"@types/classnames": "^2.2.8",
|
||||||
"@types/node": "^12.0.8",
|
"@types/node": "^12.0.10",
|
||||||
"@types/react": "^16.8.19",
|
"@types/react": "^16.8.22",
|
||||||
"@types/react-dom": "^16.8.4",
|
"@types/react-dom": "^16.8.4",
|
||||||
"@types/react-i18next": "^8.1.0",
|
"@types/react-i18next": "^8.1.0",
|
||||||
"@types/react-router-dom": "^4.3.3",
|
"@types/react-router-dom": "^4.3.4",
|
||||||
"@types/react-sortable-hoc": "^0.6.5",
|
"@types/react-sortable-hoc": "^0.6.5",
|
||||||
"@types/react-virtualized": "^9.21.2",
|
"@types/react-virtualized": "^9.21.2",
|
||||||
"@types/yaml": "^1.0.2",
|
"@types/yaml": "^1.0.2",
|
||||||
@ -53,20 +53,20 @@
|
|||||||
"offline-plugin": "^5.0.7",
|
"offline-plugin": "^5.0.7",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
"react-addons-test-utils": "^15.6.2",
|
"react-addons-test-utils": "^15.6.2",
|
||||||
"react-hot-loader": "^4.11.0",
|
"react-hot-loader": "^4.12.0",
|
||||||
"sass": "^1.21.0",
|
"sass": "^1.22.2",
|
||||||
"sass-loader": "^7.1.0",
|
"sass-loader": "^7.1.0",
|
||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"stylelint": "^10.1.0",
|
"stylelint": "^10.1.0",
|
||||||
"stylelint-config-standard": "^18.3.0",
|
"stylelint-config-standard": "^18.3.0",
|
||||||
"stylelint-webpack-plugin": "^0.10.5",
|
"stylelint-webpack-plugin": "^0.10.5",
|
||||||
"tslint": "^5.17.0",
|
"tslint": "^5.18.0",
|
||||||
"tslint-config-standard": "^8.0.1",
|
"tslint-config-standard": "^8.0.1",
|
||||||
"tslint-loader": "^3.6.0",
|
"tslint-loader": "^3.6.0",
|
||||||
"webpack": "^4.33.0",
|
"webpack": "^4.35.2",
|
||||||
"webpack-cli": "^3.3.4",
|
"webpack-cli": "^3.3.5",
|
||||||
"webpack-dev-middleware": "^3.7.0",
|
"webpack-dev-middleware": "^3.7.0",
|
||||||
"webpack-dev-server": "^3.7.1",
|
"webpack-dev-server": "^3.7.2",
|
||||||
"webpack-merge": "^4.2.1",
|
"webpack-merge": "^4.2.1",
|
||||||
"webpack-pwa-manifest": "^4.0.0"
|
"webpack-pwa-manifest": "^4.0.0"
|
||||||
},
|
},
|
||||||
@ -74,20 +74,20 @@
|
|||||||
"axios": "^0.19.0",
|
"axios": "^0.19.0",
|
||||||
"classnames": "^2.2.6",
|
"classnames": "^2.2.6",
|
||||||
"dayjs": "^1.8.14",
|
"dayjs": "^1.8.14",
|
||||||
"eventemitter3": "^3.1.2",
|
"eventemitter3": "^4.0.0",
|
||||||
"i18next": "^11.10.0",
|
"i18next": "^17.0.6",
|
||||||
"i18next-browser-languagedetector": "^2.2.4",
|
"i18next-browser-languagedetector": "^3.0.1",
|
||||||
"mobx": "^5.10.1",
|
"mobx": "^5.10.1",
|
||||||
"mobx-react": "^6.0.3",
|
"mobx-react": "^6.1.1",
|
||||||
"mobx-react-router": "^4.0.7",
|
"mobx-react-router": "^4.0.7",
|
||||||
"react": "^16.8.6",
|
"react": "^16.8.6",
|
||||||
"react-dom": "^16.8.6",
|
"react-dom": "^16.8.6",
|
||||||
"react-i18next": "^7.12.0",
|
"react-i18next": "^10.11.2",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-router-dom": "^5.0.1",
|
||||||
"react-sortable-hoc": "^1.9.1",
|
"react-sortable-hoc": "^1.9.1",
|
||||||
"react-virtualized": "^9.21.1",
|
"react-virtualized": "^9.21.1",
|
||||||
"terser-webpack-plugin": "^1.3.0",
|
"terser-webpack-plugin": "^1.3.0",
|
||||||
"typescript": "^3.5.1",
|
"typescript": "^3.5.2",
|
||||||
"yaml": "^1.6.0"
|
"yaml": "^1.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,36 +10,26 @@ interface AlertProps extends BaseComponentProps {
|
|||||||
inside?: boolean
|
inside?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Alert extends React.Component<AlertProps, {}> {
|
const iconMap = {
|
||||||
|
success: 'check',
|
||||||
static defaultProps: AlertProps = {
|
info: 'info',
|
||||||
message: '',
|
warning: 'info',
|
||||||
type: 'info',
|
error: 'close'
|
||||||
inside: false
|
}
|
||||||
}
|
|
||||||
|
export function Alert (props: AlertProps) {
|
||||||
iconMap = {
|
const { message = '', type = 'info', inside = false, children, className, style } = props
|
||||||
success: 'check',
|
const classname = classnames('alert', `alert-${inside ? 'note' : 'box'}-${type}`, className)
|
||||||
info: 'info',
|
return (
|
||||||
warning: 'info',
|
<div className={classname} style={style}>
|
||||||
error: 'close'
|
<span className="alert-icon">
|
||||||
}
|
<Icon type={iconMap[type]} size={26} />
|
||||||
|
</span>
|
||||||
render () {
|
{
|
||||||
const { message, type, inside, children, className, style } = this.props
|
message
|
||||||
|
? <p className="alert-message">{message}</p>
|
||||||
return (
|
: <div className="alert-message">{children}</div>
|
||||||
<div className={classnames('alert', `alert-${inside ? 'note' : 'box'}-${type}`, className)} style={style}>
|
}
|
||||||
<span className="alert-icon">
|
</div>
|
||||||
<Icon type={this.iconMap[type]} size={26} />
|
)
|
||||||
</span>
|
|
||||||
{
|
|
||||||
message
|
|
||||||
? <p className="alert-message">{message}</p>
|
|
||||||
: <div className="alert-message">{children}</div>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import { BaseComponentProps } from '@models'
|
import { BaseComponentProps } from '@models'
|
||||||
|
import { noop } from '@lib/helper'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface ButtonProps extends BaseComponentProps {
|
interface ButtonProps extends BaseComponentProps {
|
||||||
@ -8,23 +9,15 @@ interface ButtonProps extends BaseComponentProps {
|
|||||||
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Button extends React.Component<ButtonProps, {}> {
|
export function Button (props: ButtonProps) {
|
||||||
|
const { type = 'normal', onClick = noop, children, className, style } = props
|
||||||
static defaultProps: ButtonProps = {
|
const classname = classnames('button', `button-${type}`, className)
|
||||||
type: 'normal',
|
|
||||||
onClick: () => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { type, onClick, children, className, style } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<button
|
|
||||||
className={classnames('button', `button-${type}`, className)}
|
|
||||||
style={style}
|
|
||||||
onClick={onClick}
|
|
||||||
>{children}</button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={classname}
|
||||||
|
style={style}
|
||||||
|
onClick={onClick}
|
||||||
|
>{children}</button>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -19,26 +19,22 @@ export interface ButtonSelectProps extends BaseComponentProps {
|
|||||||
onSelect?: (value: any) => void
|
onSelect?: (value: any) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ButtonSelect extends React.Component<ButtonSelectProps, {}> {
|
export function ButtonSelect (props: ButtonSelectProps) {
|
||||||
|
const { options, value, onSelect } = props
|
||||||
render () {
|
|
||||||
const { options, value, onSelect } = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="button-select">
|
|
||||||
{
|
|
||||||
options.map(option => (
|
|
||||||
<button
|
|
||||||
value={option.value}
|
|
||||||
key={option.value}
|
|
||||||
className={classnames('button-select-options', { actived: value === option.value })}
|
|
||||||
onClick={() => onSelect(option.value)}>
|
|
||||||
{ option.label }
|
|
||||||
</button>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="button-select">
|
||||||
|
{
|
||||||
|
options.map(option => (
|
||||||
|
<button
|
||||||
|
value={option.value}
|
||||||
|
key={option.value}
|
||||||
|
className={classnames('button-select-options', { actived: value === option.value })}
|
||||||
|
onClick={() => onSelect(option.value)}>
|
||||||
|
{ option.label }
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { BaseComponentProps } from '@models/BaseProps'
|
||||||
|
import { noop } from '@lib/helper'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface InputProps extends BaseComponentProps {
|
interface InputProps extends BaseComponentProps {
|
||||||
value?: string | number
|
value?: string | number
|
||||||
disabled?: boolean
|
|
||||||
align?: 'left' | 'center' | 'right'
|
align?: 'left' | 'center' | 'right'
|
||||||
inside?: boolean
|
inside?: boolean
|
||||||
autoFocus?: boolean
|
autoFocus?: boolean
|
||||||
@ -14,41 +14,29 @@ interface InputProps extends BaseComponentProps {
|
|||||||
onBlur?: (event?: React.FocusEvent<HTMLInputElement>) => void
|
onBlur?: (event?: React.FocusEvent<HTMLInputElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Input extends React.Component<InputProps, {}> {
|
export function Input (props: InputProps) {
|
||||||
static defaultProps: InputProps = {
|
const {
|
||||||
value: '',
|
className,
|
||||||
disabled: false,
|
style,
|
||||||
align: 'center',
|
value = '',
|
||||||
inside: false,
|
align = 'center',
|
||||||
autoFocus: false,
|
inside = false,
|
||||||
type: 'text',
|
autoFocus = false,
|
||||||
onChange: () => {},
|
type = 'text',
|
||||||
onBlur: () => {}
|
onChange = noop,
|
||||||
}
|
onBlur = noop
|
||||||
|
} = props
|
||||||
|
const classname = classnames('input', `input-align-${align}`, { 'input-inside': inside }, className)
|
||||||
|
|
||||||
render () {
|
return (
|
||||||
const {
|
<input
|
||||||
className,
|
className={classname}
|
||||||
style,
|
style={style}
|
||||||
value,
|
value={value}
|
||||||
align,
|
autoFocus={autoFocus}
|
||||||
inside,
|
type={type}
|
||||||
autoFocus,
|
onChange={event => onChange(event.target.value, event)}
|
||||||
type,
|
onBlur={onBlur}
|
||||||
onChange,
|
/>
|
||||||
onBlur
|
)
|
||||||
} = this.props
|
|
||||||
|
|
||||||
return (
|
|
||||||
<input
|
|
||||||
className={classnames('input', `input-align-${align}`, { 'input-inside': inside }, className)}
|
|
||||||
style={style}
|
|
||||||
value={value}
|
|
||||||
autoFocus={autoFocus}
|
|
||||||
type={type}
|
|
||||||
onChange={event => onChange(event.target.value, event)}
|
|
||||||
onBlur={onBlur}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { BaseComponentProps } from '@models/BaseProps'
|
import { BaseComponentProps } from '@models/BaseProps'
|
||||||
import { Icon } from '@components'
|
import { Icon } from '@components'
|
||||||
|
import { noop } from '@lib/helper'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
@ -10,26 +11,19 @@ interface SwitchProps extends BaseComponentProps {
|
|||||||
onChange?: (checked: boolean) => void
|
onChange?: (checked: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Switch extends React.Component<SwitchProps, {}> {
|
export function Switch (props: SwitchProps) {
|
||||||
static defaultProps: SwitchProps = {
|
const { className, checked = false, disabled = false, onChange = noop } = props
|
||||||
checked: false,
|
const classname = classnames('switch', { checked, disabled }, className)
|
||||||
disabled: false,
|
|
||||||
onChange: () => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = () => {
|
function handleClick () {
|
||||||
if (!this.props.disabled) {
|
if (!disabled) {
|
||||||
this.props.onChange(!this.props.checked)
|
onChange(!checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
return (
|
||||||
const { className, checked, disabled } = this.props
|
<div className={classname} onClick={handleClick}>
|
||||||
|
<Icon className="switch-icon" type="check" size={20} style={{ fontWeight: 'bold' }} />
|
||||||
return (
|
</div>
|
||||||
<div className={classnames('switch', { checked, disabled }, className)} onClick={this.handleClick}>
|
)
|
||||||
<Icon className="switch-icon" type="check" size={20} style={{ fontWeight: 'bold' }} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react'
|
import React, { useState, useRef, useMemo } from 'react'
|
||||||
import { translate } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { BaseComponentProps, I18nProps } from '@models'
|
import { BaseComponentProps, I18nProps } from '@models'
|
||||||
import { noop } from '@lib/helper'
|
import { noop } from '@lib/helper'
|
||||||
import classnames from 'classnames'
|
import classnames from 'classnames'
|
||||||
@ -13,55 +13,41 @@ interface TagsProps extends BaseComponentProps, I18nProps {
|
|||||||
canClick: boolean
|
canClick: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TagsState {
|
export function Tags (props: TagsProps) {
|
||||||
expand: boolean
|
const { className, data, onClick, select, canClick } = props
|
||||||
showExtend: boolean
|
|
||||||
ulRef: React.RefObject<HTMLUListElement>
|
const { t } = useTranslation()
|
||||||
|
const [expand, setExpand] = useState(false)
|
||||||
|
|
||||||
|
const ulRef = useRef<HTMLUListElement>()
|
||||||
|
const showExtend = useMemo(() => ulRef.current.offsetHeight > 30, [ulRef])
|
||||||
|
|
||||||
|
const rowHeight = this.state.expand ? 'auto' : this.props.rowHeight
|
||||||
|
const handleClick = canClick ? onClick : noop
|
||||||
|
|
||||||
|
function toggleExtend () {
|
||||||
|
setExpand(!expand)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = data
|
||||||
|
.map(t => {
|
||||||
|
const tagClass = classnames({ 'tags-selected': select === t, 'can-click': canClick })
|
||||||
|
return (
|
||||||
|
<li className={tagClass} key={t} onClick={() => handleClick(t)}>
|
||||||
|
{ t }
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classnames('tags-container', className)} style={{ height: rowHeight }}>
|
||||||
|
<ul ref={ulRef} className={classnames('tags', { expand })}>
|
||||||
|
{ tags }
|
||||||
|
</ul>
|
||||||
|
{
|
||||||
|
showExtend &&
|
||||||
|
<span className="tags-expand" onClick={toggleExtend}>{ expand ? t('collapseText') : t('expandText') }</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class TagsClass extends React.Component<TagsProps, TagsState> {
|
|
||||||
state: TagsState = {
|
|
||||||
expand: false,
|
|
||||||
showExtend: true,
|
|
||||||
ulRef: React.createRef<HTMLUListElement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleExtend = () => {
|
|
||||||
this.setState({ expand: !this.state.expand })
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
this.setState({ showExtend: this.state.ulRef.current.offsetHeight > 30 })
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { t, className, data, onClick, select, canClick } = this.props
|
|
||||||
const { expand } = this.state
|
|
||||||
const rowHeight = this.state.expand ? 'auto' : this.props.rowHeight
|
|
||||||
const handleClick = canClick ? onClick : noop
|
|
||||||
|
|
||||||
const tags = data
|
|
||||||
.map(t => {
|
|
||||||
const tagClass = classnames({ 'tags-selected': select === t, 'can-click': canClick })
|
|
||||||
return (
|
|
||||||
<li className={tagClass} key={t} onClick={() => handleClick(t)}>
|
|
||||||
{ t }
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classnames('tags-container', className)} style={{ height: rowHeight }}>
|
|
||||||
<ul ref={this.state.ulRef} className={classnames('tags', { expand })}>
|
|
||||||
{ tags }
|
|
||||||
</ul>
|
|
||||||
{
|
|
||||||
this.state.showExtend &&
|
|
||||||
<span className="tags-expand" onClick={this.toggleExtend}>{ this.state.expand ? t('collapseText') : t('expandText') }</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Tags = translate(['Proxies'])(TagsClass)
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { translate } from 'react-i18next'
|
import { withTranslation } from 'react-i18next'
|
||||||
import { inject, observer } from 'mobx-react'
|
import { inject, observer } from 'mobx-react'
|
||||||
import { storeKeys } from '@lib/createStore'
|
import { storeKeys } from '@lib/createStore'
|
||||||
import { Modal, Input, Row, Col, Alert } from '@components'
|
import { Modal, Input, Row, Col, Alert } from '@components'
|
||||||
@ -93,4 +93,4 @@ class ExternalController extends React.Component<ExternalControllerModalProps, E
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translate(['Settings'])(ExternalController)
|
export default withTranslation(['Settings'])(ExternalController)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import * as EventEmitter from 'eventemitter3'
|
import EventEmitter from 'eventemitter3'
|
||||||
|
|
||||||
export enum Action {
|
export enum Action {
|
||||||
SPEED_NOTIFY = 'speed-notify'
|
SPEED_NOTIFY = 'speed-notify'
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { to } from '@lib/helper'
|
import { to } from '@lib/helper'
|
||||||
import * as EventEmitter from 'eventemitter3'
|
import EventEmitter from 'eventemitter3'
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
url: string
|
url: string
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { CSSProperties } from 'react'
|
import { CSSProperties, ReactNode } from 'react'
|
||||||
import { RouteComponentProps } from 'react-router'
|
import { RouteComponentProps } from 'react-router'
|
||||||
import { RouterStore, ConfigStore } from '@stores'
|
import { RouterStore, ConfigStore } from '@stores'
|
||||||
|
|
||||||
@ -19,5 +19,6 @@ export interface BaseProps extends BaseComponentProps {
|
|||||||
|
|
||||||
export interface BaseComponentProps {
|
export interface BaseComponentProps {
|
||||||
className?: string
|
className?: string
|
||||||
|
children?: ReactNode
|
||||||
style?: CSSProperties
|
style?: CSSProperties
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist/",
|
"outDir": "./dist/",
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"noImplicitAny": false,
|
"noImplicitAny": false,
|
||||||
"noUnusedLocals": true,
|
"noUnusedLocals": true,
|
||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user