diff --git a/src/components/Card/style.scss b/src/components/Card/style.scss index 1763691..da5c796 100644 --- a/src/components/Card/style.scss +++ b/src/components/Card/style.scss @@ -3,6 +3,6 @@ .card { padding: 15px; box-shadow: 0 0 20px rgba($color-primary-dark, 0.2); - background-color: #fff; + background-color: $color-white; border-radius: 4px; } diff --git a/src/components/Switch/style.scss b/src/components/Switch/style.scss index fc6c910..84ce0e6 100644 --- a/src/components/Switch/style.scss +++ b/src/components/Switch/style.scss @@ -44,7 +44,7 @@ $width: 32px; height: $switch-radius; width: $switch-radius; border-radius: $switch-radius / 2; - background-color: #fff; + background-color: $color-white; box-shadow: 0 0 8px rgba($color-primary-dark, 0.4); transition: transform 0.3s ease; transform: translateX($width - $switch-radius + $switch-offset); @@ -54,6 +54,6 @@ $width: 32px; .switch-icon { position: absolute; transform: translateX(13px) scale(0.4); - color: #fff; + color: $color-white; line-height: $height; } diff --git a/src/containers/Proxies/components/ModifyProxyDialog/index.tsx b/src/containers/Proxies/components/ModifyProxyDialog/index.tsx new file mode 100644 index 0000000..2eee9df --- /dev/null +++ b/src/containers/Proxies/components/ModifyProxyDialog/index.tsx @@ -0,0 +1,76 @@ +import * as React from 'react' +import { translate } from 'react-i18next' +import classnames from 'classnames' +import { BaseComponentProps, Proxy as IProxy, I18nProps, TagColors } from '@models' +import { Modal, Row, Col } from '@components' +import { getLocalStorageItem, setLocalStorageItem } from '@lib/helper' +import './style.scss' + +interface ModifyProxyDialogProps extends BaseComponentProps, I18nProps { + config: IProxy + onOk?: (config: IProxy) => void + onCancel?: () => void +} + +interface ModifyProxyDialogState { + config: IProxy + currentColor: string +} + +class RawDialog extends React.Component { + + constructor (props: ModifyProxyDialogProps) { + super(props) + + this.state = { + config: props.config, + currentColor: getLocalStorageItem(props.config.name) + } + } + + componentDidMount () { + console.log(this.props.config) + } + + handleOk = () => { + const { onOk } = this.props + const { config, currentColor } = this.state + setLocalStorageItem(config.name, currentColor) + + onOk(config) + } + + render () { + const { onCancel, t } = this.props + const { currentColor } = this.state + + return + + {t('editDialog.color')} + +
+ { + TagColors.map(color => ( + this.setState({ currentColor: color })} + /> + )) + } +
+ +
+
+ } +} + +export const ModifyProxyDialog = translate(['Proxies'])(RawDialog) diff --git a/src/containers/Proxies/components/ModifyProxyDialog/style.scss b/src/containers/Proxies/components/ModifyProxyDialog/style.scss new file mode 100644 index 0000000..11c2541 --- /dev/null +++ b/src/containers/Proxies/components/ModifyProxyDialog/style.scss @@ -0,0 +1,29 @@ +@import '~@styles/variables'; + +.proxy-editor { + .proxy-editor-color-selector { + display: flex; + align-items: center; + + .color-item { + position: relative; + margin-right: 10px; + width: 16px; + height: 16px; + border-radius: 50%; + cursor: pointer; + } + + .color-item-active::after { + position: absolute; + left: -3px; + top: -3px; + content: ''; + display: block; + width: 22px; + height: 22px; + border-radius: 50%; + border: 1px solid $color-gray-dark; + } + } +} diff --git a/src/containers/Proxies/components/Proxy/index.tsx b/src/containers/Proxies/components/Proxy/index.tsx index e9bfea2..326d789 100644 --- a/src/containers/Proxies/components/Proxy/index.tsx +++ b/src/containers/Proxies/components/Proxy/index.tsx @@ -1,24 +1,51 @@ import * as React from 'react' import classnames from 'classnames' -import { BaseComponentProps, Proxy as IProxy } from '@models' +import { Icon } from '@components' +import { BaseComponentProps, Proxy as IProxy, TagColors } from '@models' import { getProxyDelay } from '@lib/request' -import { to } from '@lib/helper' +import { to, getLocalStorageItem, setLocalStorageItem, sample, noop } from '@lib/helper' import './style.scss' interface ProxyProps extends BaseComponentProps { config: IProxy + onEdit?: (e: React.MouseEvent) => void } interface ProxyState { delay: number hasError: boolean + color: string } export class Proxy extends React.Component { - state = { - delay: -1, - hasError: false + constructor (props) { + super(props) + + const { config } = props + const { name } = config + let color = getLocalStorageItem(name) + + if (!color) { + color = sample(TagColors) + setLocalStorageItem(name, color) + } + + this.state = { + delay: -1, + hasError: false, + color + } + } + + componentWillUpdate () { + const { config: { name } } = this.props + const { color: rawColor } = this.state + const color = getLocalStorageItem(name) + + if (rawColor !== color) { + this.setState({ color }) + } } async componentDidMount () { @@ -34,13 +61,16 @@ export class Proxy extends React.Component { } render () { - const { config, className } = this.props - const { delay, hasError } = this.state + const { config, className, onEdit = noop } = this.props + const { delay, color, hasError } = this.state + const backgroundColor = hasError ? undefined : color return (
- {config.name} - {delay === -1 ? '-' : `${delay}s`} + {config.type} +

{config.name}

+

{delay === -1 ? '-' : `${delay}ms`}

+
) } diff --git a/src/containers/Proxies/components/Proxy/style.scss b/src/containers/Proxies/components/Proxy/style.scss index 9110a74..3bd75ea 100644 --- a/src/containers/Proxies/components/Proxy/style.scss +++ b/src/containers/Proxies/components/Proxy/style.scss @@ -1,37 +1,65 @@ @import '~@styles/variables'; .proxy-item { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - height: 100px; - width: 100px; - box-shadow: 0 0 20px rgba($color-primary-dark, 0.2); + position: relative; + padding: 10px; + height: 110px; + width: 110px; border-radius: 4px; + background: $color-white; + user-select: none; + cursor: default; + box-shadow: 0 0 20px rgba($color-primary-dark, 0.2); + transition: all 300ms ease; - .proxy-icon { - height: 40px; - width: 40px; + .proxy-type { + padding: 2px 5px; + font-size: 10px; + color: $color-white; + border-radius: 2px; } .proxy-name { - width: 80%; - margin-top: 8px; - color: $color-primary-dark; + max-height: 30px; + margin-top: 10px; + color: $color-primary-darken; font-size: 12px; - text-overflow: ellipsis; overflow: hidden; - text-align: center; } .proxy-delay { - width: 80%; - margin-top: 8px; - color: $color-primary-dark; - font-size: 12px; - text-overflow: ellipsis; - overflow: hidden; - text-align: center; + position: absolute; + left: 10px; + bottom: 13px; + font-size: 10px; + color: rgba($color: $color-primary-darken, $alpha: 0.8); + } + + .proxy-editor { + position: absolute; + right: 10px; + bottom: 10px; + cursor: pointer; + color: rgba($color: $color-primary-darken, $alpha: 0.8); + opacity: 0; + pointer-events: none; + transition: all 300ms ease; + } + + &:hover { + box-shadow: 0 10px 20px rgba($color-primary-darken, 0.4); + + .proxy-editor { + opacity: 1; + pointer-events: visible; + } + } +} + +.proxy-error { + opacity: 0.5; + + .proxy-type { + background-color: $color-gray-darken; } } diff --git a/src/containers/Proxies/components/index.ts b/src/containers/Proxies/components/index.ts index 693bc69..dae0b9b 100644 --- a/src/containers/Proxies/components/index.ts +++ b/src/containers/Proxies/components/index.ts @@ -1 +1,2 @@ export * from './Proxy' +export * from './ModifyProxyDialog' diff --git a/src/containers/Proxies/index.tsx b/src/containers/Proxies/index.tsx index 650b522..41c008a 100644 --- a/src/containers/Proxies/index.tsx +++ b/src/containers/Proxies/index.tsx @@ -3,16 +3,26 @@ import { translate } from 'react-i18next' import { inject, observer } from 'mobx-react' import { storeKeys } from '@lib/createStore' import { Header, Icon } from '@components' -import { I18nProps, BaseRouterProps } from '@models' +import { I18nProps, BaseRouterProps, Proxy as IProxy } from '@models' -import { Proxy } from './components' +import { Proxy, ModifyProxyDialog } from './components' import './style.scss' interface ProxiesProps extends BaseRouterProps, I18nProps {} +interface ProxiesState { + showModifyProxyDialog: boolean + activeConfig?: IProxy +} + @inject(...storeKeys) @observer -class Proxies extends React.Component { +class Proxies extends React.Component { + + state = { + showModifyProxyDialog: false, + activeConfig: null + } componentDidMount () { this.props.config.fetchAndParseConfig() @@ -20,31 +30,46 @@ class Proxies extends React.Component { render () { const { t, config } = this.props + const { showModifyProxyDialog, activeConfig } = this.state return ( -
-
-
- -
- { - config.state === 'ok' &&
    - { - config.config.proxy.map( - (p, index) => ( + <> +
    +
    +
    + +
    + { + config.state === 'ok' &&
      + { + config.config.proxy.map((p, index) => (
    • - + this.setState({ + showModifyProxyDialog: true, + activeConfig: p + })} />
    • - ) - ) - } -
    + )) + } +
+ } +
+
+
+
+ + { + showModifyProxyDialog && { + console.log(config) + this.setState({ showModifyProxyDialog: false, activeConfig: null }) + }} + onCancel={() => this.setState({ showModifyProxyDialog: false, activeConfig: null })} + /> }
-
-
-
- + ) } } diff --git a/src/containers/Proxies/style.scss b/src/containers/Proxies/style.scss index c53e635..20d956c 100644 --- a/src/containers/Proxies/style.scss +++ b/src/containers/Proxies/style.scss @@ -7,6 +7,11 @@ list-style: none; li { - margin: 20px 15px 20px 0; + margin: 8px 0; + margin-right: 15px; + + &:nth-child(6n) { + margin-right: 0; + } } } diff --git a/src/containers/Settings/style.scss b/src/containers/Settings/style.scss index 42e20df..5830be8 100644 --- a/src/containers/Settings/style.scss +++ b/src/containers/Settings/style.scss @@ -52,7 +52,7 @@ > i { transform: scale(0.5); - color: #fff; + color: $color-white; font-weight: bold; } } diff --git a/src/containers/Sidebar/style.scss b/src/containers/Sidebar/style.scss index 0b767f2..dbcb3c2 100644 --- a/src/containers/Sidebar/style.scss +++ b/src/containers/Sidebar/style.scss @@ -1,11 +1,15 @@ @import '~@styles/variables'; .sidebar { + position: fixed; + top: 0; + left: 0; display: flex; flex-direction: column; align-items: center; flex-shrink: 0; width: 140px; + user-select: none; } .sidebar-logo { @@ -42,7 +46,7 @@ > a.active { background: linear-gradient(135deg, $color-primary, $color-primary-dark); - color: #fff; + color: $color-white; box-shadow: 0 2px 8px rgba($color: $color-primary-dark, $alpha: 0.5); } } diff --git a/src/i18n/en_US.ts b/src/i18n/en_US.ts index 421a7ee..287e27f 100644 --- a/src/i18n/en_US.ts +++ b/src/i18n/en_US.ts @@ -43,6 +43,21 @@ export default { }, Proxies: { title: 'Proxies', + editDialog: { + title: 'Edit Proxy', + color: 'Color', + name: 'Name', + type: 'Type', + server: 'Server', + port: 'Port', + password: 'Password', + cipher: 'Cipher', + obfs: 'Obfs', + 'obfs-host': 'Obfs-host', + uuid: 'Uuid', + alterid: 'Alterid', + tls: 'TLS' + }, groupTitle: 'Policy Group' } } diff --git a/src/i18n/zh_CN.ts b/src/i18n/zh_CN.ts index af02d28..dc0dfea 100644 --- a/src/i18n/zh_CN.ts +++ b/src/i18n/zh_CN.ts @@ -43,6 +43,21 @@ export default { }, Proxies: { title: '代理', + editDialog: { + title: '编辑代理', + color: '颜色', + name: '名字', + type: '类型', + server: '服务器', + port: '端口', + password: '密码', + cipher: '加密方式', + obfs: 'Obfs', + 'obfs-host': 'Obfs-host', + uuid: 'Uuid', + alterid: 'Alterid', + tls: 'TLS' + }, groupTitle: '策略组' } } diff --git a/src/lib/helper.ts b/src/lib/helper.ts index 3e32a48..fb09a8f 100644 --- a/src/lib/helper.ts +++ b/src/lib/helper.ts @@ -10,6 +10,16 @@ export function removeLocalStorageItem (key: string) { return window.localStorage.removeItem(key) } +export function randomNumber (min: number, max: number) { + return (min + Math.random() * (max - min)) >> 0 +} + +export function sample (arr: T[]) { + return arr[randomNumber(0, arr.length)] +} + +export function noop () {} + /** * to return Promise<[T, Error]> * @param {Promise} promise diff --git a/src/models/TagColors.ts b/src/models/TagColors.ts new file mode 100644 index 0000000..2e57434 --- /dev/null +++ b/src/models/TagColors.ts @@ -0,0 +1,7 @@ +export const TagColors = [ + '#ff3e5e', + '#686fff', + '#ff9a28', + '#b83fe6', + '#00c520' +] diff --git a/src/models/index.ts b/src/models/index.ts index d69a472..5995a13 100644 --- a/src/models/index.ts +++ b/src/models/index.ts @@ -3,3 +3,4 @@ export * from './Config' export * from './Proxy' export * from './Rule' export * from './I18n' +export * from './TagColors' diff --git a/src/styles/common.scss b/src/styles/common.scss index f39c5fb..e667dce 100644 --- a/src/styles/common.scss +++ b/src/styles/common.scss @@ -22,8 +22,8 @@ body { } .app { - display: flex; min-height: 100vh; + padding-left: 150px; } .app.clash-x { @@ -32,13 +32,15 @@ body { .page-container { width: 100%; - margin: 20px 0; + height: 100vh; } .page { - padding: 10px 35px; + padding: 20px 35px; + padding-left: 0; + padding-bottom: 30px; width: 100%; - height: 100%; + height: 100vh; max-width: 1200px; margin: 0 auto; display: flex; diff --git a/src/styles/iconfont.scss b/src/styles/iconfont.scss index 83b18ed..2133e68 100644 --- a/src/styles/iconfont.scss +++ b/src/styles/iconfont.scss @@ -6,7 +6,7 @@ @font-face { font-family: "clash-iconfont"; - src: url('//at.alicdn.com/t/font_841708_h6oakuryxxb.ttf') format('truetype'); + src: url('//at.alicdn.com/t/font_841708_7ge2gqse7qv.ttf') format('truetype'); } .clash-iconfont { @@ -37,3 +37,5 @@ .icon-info::before { content: "\e60b"; } .icon-info-o::before { content: "\e60c"; } + +.icon-setting::before { content: "\e60d"; }