diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/APIConfig.js | 23 | ||||
| -rw-r--r-- | src/components/APIConfig.module.scss | 4 | ||||
| -rw-r--r-- | src/components/Proxies.js | 73 | ||||
| -rw-r--r-- | src/components/Proxies.module.scss | 40 | ||||
| -rw-r--r-- | src/components/Proxy.js | 117 | ||||
| -rw-r--r-- | src/components/Proxy.module.scss | 32 | ||||
| -rw-r--r-- | src/components/ProxyGroup.js | 80 | ||||
| -rw-r--r-- | src/components/ProxyGroup.module.scss | 20 | ||||
| -rw-r--r-- | src/components/ProxyLatency.js | 44 | ||||
| -rw-r--r-- | src/components/ProxyLatency.module.scss | 8 | ||||
| -rw-r--r-- | src/components/StyleGuide.js | 11 |
11 files changed, 271 insertions, 181 deletions
diff --git a/src/components/APIConfig.js b/src/components/APIConfig.js index ce2b7fe..4e85a69 100644 --- a/src/components/APIConfig.js +++ b/src/components/APIConfig.js @@ -33,6 +33,10 @@ class APIConfig extends Component { secret: this.props.apiConfig.secret }; + componentDidMount() { + this.content.focus(); + } + handleInputOnChange = e => { const target = e.target; const { name } = target; @@ -46,15 +50,30 @@ class APIConfig extends Component { this.setState({ [name]: value }); }; - handleConfirmOnClick = () => { + updateClashAPIConfig() { const { hostname, port, secret } = this.state; this.props.updateClashAPIConfig({ hostname, port, secret }); + } + + handleConfirmOnClick = () => { + this.updateClashAPIConfig(); + }; + + handleContentOnKeyDown = e => { + // enter keyCode is 13 + if (e.keyCode !== 13) return; + this.updateClashAPIConfig(); }; render() { const { hostname, port, secret } = this.state; return ( - <div className={s0.root}> + <div + className={s0.root} + ref={e => (this.content = e)} + tabIndex="1" + onKeyDown={this.handleContentOnKeyDown} + > <div className={s0.header}>RESTful API config for Clash</div> <div className={s0.body}> <div className={s0.group}> diff --git a/src/components/APIConfig.module.scss b/src/components/APIConfig.module.scss index d723016..0edf1b6 100644 --- a/src/components/APIConfig.module.scss +++ b/src/components/APIConfig.module.scss @@ -1,5 +1,7 @@ .root { - // + &:focus { + outline: none; + } } .header { diff --git a/src/components/Proxies.js b/src/components/Proxies.js index f6d7caf..98876ae 100644 --- a/src/components/Proxies.js +++ b/src/components/Proxies.js @@ -2,22 +2,24 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ContentHeader from 'c/ContentHeader'; -import Proxy from 'c/Proxy'; +import ProxyGroup from 'c/ProxyGroup'; import Button from 'c/Button'; -import cx from 'classnames'; import s0 from 'c/Proxies.module.scss'; -const th = cx(s0.row, s0.th, 'border-bottom'); -// const colItem = cx(s0.colItem, 'border-bottom'); - import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import { getUserProxies, fetchProxies, requestDelayAll } from 'd/proxies'; +import { + getUserProxies, + getProxyGroupNames, + fetchProxies, + requestDelayAll +} from 'd/proxies'; function mapStateToProps(s) { return { - proxies: getUserProxies(s) + proxies: getUserProxies(s), + groupNames: getProxyGroupNames(s) }; } @@ -30,7 +32,7 @@ function mapDispatchToProps(dispatch) { class Proxies extends Component { static propTypes = { - proxies: PropTypes.object.isRequired, + groupNames: PropTypes.array.isRequired, fetchProxies: PropTypes.func.isRequired, requestDelayAll: PropTypes.func.isRequired }; @@ -40,64 +42,27 @@ class Proxies extends Component { } render() { - const { proxies, requestDelayAll } = this.props; - + const { groupNames, requestDelayAll } = this.props; return ( <div> <ContentHeader title="Proxies" /> - - <div className={s0.root}> + <div> <div className={s0.btnGroup}> <Button label="Test Latency" onClick={requestDelayAll} /> </div> - <div className={th}> - <div className={s0.col1}>Name</div> - <div className={s0.col2}>Type</div> - <div className={s0.col3}>All</div> - </div> - - <div> - {Object.keys(proxies).map(k => { - const o = proxies[k]; - return <ProxyRow name={k} key={k} {...o} />; - })} - </div> + {groupNames.map(groupName => { + return ( + <div className={s0.group} key={groupName}> + <ProxyGroup name={groupName} /> + </div> + ); + })} </div> </div> ); } } -class ProxyRow extends Component { - static propTypes = { - name: PropTypes.string.isRequired, - type: PropTypes.string.isRequired, - all: PropTypes.array, - now: PropTypes.string - }; - - render() { - const { name, type, all, now } = this.props; - return ( - <div className={s0.row}> - <div className={s0.col1}>{name}</div> - <div className={s0.col2}>{type}</div> - {all ? ( - <div className={s0.col3 + ' border-left'}> - {all.map(p => { - return ( - <div className={s0.colItem} key={p}> - <Proxy name={p} parentName={name} checked={p === now} /> - </div> - ); - })} - </div> - ) : null} - </div> - ); - } -} - export default connect( mapStateToProps, mapDispatchToProps diff --git a/src/components/Proxies.module.scss b/src/components/Proxies.module.scss index 3b11056..9a73ee6 100644 --- a/src/components/Proxies.module.scss +++ b/src/components/Proxies.module.scss @@ -1,47 +1,13 @@ -$heightHeader: 76px; - .root { - color: #eee; - padding: 10px 40px; - height: calc(100vh - #{$heightHeader}); - overflow: scroll; } -.row { - display: flex; -} - -.th { - font-weight: bold; -} - -.col1 { - width: 150px; - padding: 8px; - display: flex; - align-items: center; -} - -.col2 { - width: 150px; - padding: 8px; - display: flex; - align-items: center; -} - -.col3 { - width: 350px; - margin: 16px 8px; - padding-left: 20px; -} - -.colItem { - padding: 6px; +.group { + padding: 10px 40px; } .btnGroup { color: #eee; - // padding: 10px 40px; + padding: 0 40px; display: flex; justify-content: flex-end; } diff --git a/src/components/Proxy.js b/src/components/Proxy.js index b3d071b..2bb9435 100644 --- a/src/components/Proxy.js +++ b/src/components/Proxy.js @@ -1,92 +1,71 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import s0 from 'c/Proxy.module.scss'; +import Icon from 'c/Icon'; +import ProxyLatency from 'c/ProxyLatency'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { getDelay, switchProxy, requestDelayForProxy } from 'd/proxies'; +import globe from 's/globe.svg'; +import ss from 's/ss.svg'; +import vmess from 's/vmess.svg'; +import auto from 's/auto.svg'; +import fallback from 's/fallback.svg'; -const mapStateToProps = state => { - const delay = getDelay(state); - return { delay }; -}; +import s0 from './Proxy.module.scss'; -const mapDispatchToProps = dispatch => { - return { - switchProxy: bindActionCreators(switchProxy, dispatch), - requestDelay: bindActionCreators(requestDelayForProxy, dispatch) - }; +import { connect } from 'react-redux'; +import { getDelay, getUserProxies } from 'd/proxies'; + +const colors = { + Vmess: '#ca3487', + Shadowsocks: '#1a7dc0', + Socks5: '#2a477a', + URLTest: '#3483e8', + Fallback: '#3483e8' }; -const colorMap = { - good: '#67C23A', - normal: '#E6A23C', - bad: '#F56C6C', - na: '#909399' +const icons = { + Vmess: vmess.id, + Shadowsocks: ss.id, + Socks5: globe.id, + URLTest: auto.id, + Fallback: fallback.id }; -class Proxy extends Component { - static propTypes = { - name: PropTypes.string.isRequired, - parentName: PropTypes.string, - checked: PropTypes.bool, - switchProxy: PropTypes.func, - requestDelay: PropTypes.func, - delay: PropTypes.object - }; +// typeof Proxy = 'Shadowsocks' | 'Vmess' | 'Socks5'; - handleRadioOnChange = () => { - const { name, parentName, checked, switchProxy } = this.props; - if (checked) return; - switchProxy(parentName, name); +const mapStateToProps = s => { + return { + proxies: getUserProxies(s), + delay: getDelay(s) }; +}; - render() { - const { name, parentName, checked, delay } = this.props; - const id = parentName + ':' + name; - const latency = delay[name] || 0; - return ( - <label className={s0.Proxy} htmlFor={id}> - <input - type="radio" - id={id} - checked={checked} - value={name} - onChange={this.handleRadioOnChange} - /> - <div className={s0.name}>{name}</div> - <LatencyLabel val={latency} /> - </label> - ); - } -} +const mapDispatchToProps = null; -class LatencyLabel extends Component { +class Proxy extends Component { static propTypes = { - val: PropTypes.number + now: PropTypes.bool, + delay: PropTypes.object, + proxies: PropTypes.object, + name: PropTypes.string }; render() { - const { val } = this.props; - let bg = colorMap.na; + const { name, proxies, delay, now } = this.props; + const latency = delay[name]; + const proxy = proxies[name]; + const color = now ? colors[proxy.type] : '#555'; + const iconId = icons[proxy.type]; - if (val < 100) { - bg = colorMap.good; - } else if (val < 300) { - bg = colorMap.normal; - } else { - bg = colorMap.bad; - } - const style = { background: bg }; - if (val === 0 || !val) { - style.opacity = '0'; - style.visibility = 'hidden'; - } return ( - <div className={s0.LatencyLabel} style={style}> - <div>{val}</div> - <div>ms</div> + <div className={s0.proxy}> + <div className={s0.left} style={{ color }}> + <Icon id={iconId} width={80} height={80} /> + </div> + <div className={s0.right}> + <div className={s0.proxyName}>{name}</div> + {latency ? <ProxyLatency latency={latency} /> : null} + </div> </div> ); } diff --git a/src/components/Proxy.module.scss b/src/components/Proxy.module.scss index 735c348..20cb494 100644 --- a/src/components/Proxy.module.scss +++ b/src/components/Proxy.module.scss @@ -1,22 +1,28 @@ -.Proxy { +.proxy { display: flex; - align-items: center; + cursor: pointer; - .name { - flex: 1; - // width: 100px; - padding-left: 10px; + svg { + transition: transform 0.4s ease, color 0.4s ease; + } + &:hover { + svg { + transform: scale(1.1); + color: #aaa; + } } } -.LatencyLabel { +.left { display: flex; align-items: center; - padding: 5px; - border-radius: 5px; - background: #e6a23c; + justify-content: center; +} - div:nth-child(2) { - padding-left: 4px; - } +.right { + padding-left: 20px; +} + +.proxyName { + margin: 10px 0; } diff --git a/src/components/ProxyGroup.js b/src/components/ProxyGroup.js new file mode 100644 index 0000000..b697b27 --- /dev/null +++ b/src/components/ProxyGroup.js @@ -0,0 +1,80 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import memoize from 'memoize-one'; + +import Proxy from 'c/Proxy'; + +import s0 from './ProxyGroup.module.scss'; + +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; +import { getUserProxies, switchProxy } from 'd/proxies'; + +const mapStateToProps = s => { + return { + proxies: getUserProxies(s) + }; +}; + +const mapDispatchToProps = dispatch => { + return { + switchProxy: bindActionCreators(switchProxy, dispatch) + }; +}; + +// should move this to sth like constants.js +// const userProxyTypes = ['Shadowsocks', 'Vmess', 'Socks5']; + +class ProxyGroup extends Component { + static propTypes = { + // group name + name: PropTypes.string.isRequired, + proxies: PropTypes.object, + switchProxy: PropTypes.func + }; + + reOrderProxies = memoize((list, now) => { + const a = [now]; + list.forEach(i => i !== now && a.push(i)); + return a; + }); + + render() { + const { name, proxies, switchProxy } = this.props; + const group = proxies[name]; + let list; + if (group.all) { + list = this.reOrderProxies(group.all, group.now); + } else { + list = [group.now]; + } + return ( + <div className={s0.group}> + <div className={s0.header}> + <h2> + <span>{name}</span> + <span>{group.type}</span> + </h2> + </div> + <div className={s0.list}> + {list.map(proxyName => { + return ( + <div + className={s0.proxy} + key={proxyName} + onClick={() => switchProxy(name, proxyName)} + > + <Proxy name={proxyName} now={proxyName === group.now} /> + </div> + ); + })} + </div> + </div> + ); + } +} + +export default connect( + mapStateToProps, + mapDispatchToProps +)(ProxyGroup); diff --git a/src/components/ProxyGroup.module.scss b/src/components/ProxyGroup.module.scss new file mode 100644 index 0000000..43cbdaa --- /dev/null +++ b/src/components/ProxyGroup.module.scss @@ -0,0 +1,20 @@ +.header { + h2 { + span:nth-child(2) { + font-size: 12px; + color: #777; + font-weight: normal; + margin: 0 0.3em; + } + } +} + +.list { + display: flex; + flex-wrap: wrap; +} + +.proxy { + width: 300px; + padding: 10px 5px; +} diff --git a/src/components/ProxyLatency.js b/src/components/ProxyLatency.js new file mode 100644 index 0000000..5d1aaee --- /dev/null +++ b/src/components/ProxyLatency.js @@ -0,0 +1,44 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import s0 from './ProxyLatency.module.scss'; + +const colorMap = { + good: '#67C23A', + normal: '#E6A23C', + bad: '#F56C6C', + na: '#909399' +}; + +class C extends Component { + static propTypes = { + latency: PropTypes.shape({ + number: PropTypes.number, + error: PropTypes.string + }) + }; + + render() { + const { latency } = this.props; + const { number, error } = latency; + let bg; + + if (error !== '') { + bg = colorMap.na; + } else if (number < 200) { + bg = colorMap.good; + } else if (number < 400) { + bg = colorMap.normal; + } else { + bg = colorMap.bad; + } + + return ( + <span className={s0.proxyLatency} style={{ color: bg }}> + {error !== '' ? <span>{error}</span> : <span>{number} ms</span>} + </span> + ); + } +} + +export default C; diff --git a/src/components/ProxyLatency.module.scss b/src/components/ProxyLatency.module.scss new file mode 100644 index 0000000..61485bd --- /dev/null +++ b/src/components/ProxyLatency.module.scss @@ -0,0 +1,8 @@ +.proxyLatency { + border-radius: 20px; + margin: 10px 0; + // padding: 3px 5px; + padding: 3px 0; + color: #eee; + // background: #ccc; +} diff --git a/src/components/StyleGuide.js b/src/components/StyleGuide.js index 3fe142d..0bb3813 100644 --- a/src/components/StyleGuide.js +++ b/src/components/StyleGuide.js @@ -5,8 +5,9 @@ import ToggleSwitch from 'c/ToggleSwitch'; import Input from 'c/Input'; import Switch from 'c/Switch'; import Button from 'c/Button'; -import Modal from 'c/Modal'; -import APIConfig from 'c/APIConfig'; +// import Modal from 'c/Modal'; +// import APIConfig from 'c/APIConfig'; +import Proxy2 from 'c/Proxy2'; const paneStyle = { padding: '20px 0' @@ -37,6 +38,9 @@ class StyleGuide extends PureComponent { return ( <div> <Pane> + <Proxy2 /> + </Pane> + <Pane> <Switch /> </Pane> <Pane> @@ -53,9 +57,6 @@ class StyleGuide extends PureComponent { <Pane> <Button label="Test Latency" /> </Pane> - <Modal isOpen={true} onRequestClose={() => {}}> - <APIConfig /> - </Modal> </div> ); } |
