mirror of
https://github.com/woodchen-ink/clash-and-dashboard.git
synced 2025-07-18 22:11:56 +08:00
Update: refactor proxy
This commit is contained in:
parent
498e7c1f7c
commit
27af0a636b
@ -3,6 +3,6 @@
|
|||||||
.card {
|
.card {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
box-shadow: 0 0 20px rgba($color-primary-dark, 0.2);
|
box-shadow: 0 0 20px rgba($color-primary-dark, 0.2);
|
||||||
background-color: #fff;
|
background-color: $color-white;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,7 @@ $width: 32px;
|
|||||||
height: $switch-radius;
|
height: $switch-radius;
|
||||||
width: $switch-radius;
|
width: $switch-radius;
|
||||||
border-radius: $switch-radius / 2;
|
border-radius: $switch-radius / 2;
|
||||||
background-color: #fff;
|
background-color: $color-white;
|
||||||
box-shadow: 0 0 8px rgba($color-primary-dark, 0.4);
|
box-shadow: 0 0 8px rgba($color-primary-dark, 0.4);
|
||||||
transition: transform 0.3s ease;
|
transition: transform 0.3s ease;
|
||||||
transform: translateX($width - $switch-radius + $switch-offset);
|
transform: translateX($width - $switch-radius + $switch-offset);
|
||||||
@ -54,6 +54,6 @@ $width: 32px;
|
|||||||
.switch-icon {
|
.switch-icon {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
transform: translateX(13px) scale(0.4);
|
transform: translateX(13px) scale(0.4);
|
||||||
color: #fff;
|
color: $color-white;
|
||||||
line-height: $height;
|
line-height: $height;
|
||||||
}
|
}
|
||||||
|
@ -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<ModifyProxyDialogProps, ModifyProxyDialogState> {
|
||||||
|
|
||||||
|
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 <Modal
|
||||||
|
className="proxy-editor"
|
||||||
|
title={t('editDialog.title')}
|
||||||
|
onOk={this.handleOk}
|
||||||
|
onClose={onCancel}
|
||||||
|
>
|
||||||
|
<Row gutter={24} style={{ padding: '12px 0' }}>
|
||||||
|
<Col span={6} style={{ paddingLeft: 0 }}>{t('editDialog.color')}</Col>
|
||||||
|
<Col span={18}>
|
||||||
|
<div className="proxy-editor-color-selector">
|
||||||
|
{
|
||||||
|
TagColors.map(color => (
|
||||||
|
<span
|
||||||
|
className={classnames('color-item', {
|
||||||
|
'color-item-active': currentColor === color
|
||||||
|
})}
|
||||||
|
key={color}
|
||||||
|
style={{ background: color }}
|
||||||
|
onClick={() => this.setState({ currentColor: color })}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Modal>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ModifyProxyDialog = translate(['Proxies'])(RawDialog)
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,51 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import classnames from 'classnames'
|
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 { getProxyDelay } from '@lib/request'
|
||||||
import { to } from '@lib/helper'
|
import { to, getLocalStorageItem, setLocalStorageItem, sample, noop } from '@lib/helper'
|
||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
interface ProxyProps extends BaseComponentProps {
|
interface ProxyProps extends BaseComponentProps {
|
||||||
config: IProxy
|
config: IProxy
|
||||||
|
onEdit?: (e: React.MouseEvent<HTMLElement>) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProxyState {
|
interface ProxyState {
|
||||||
delay: number
|
delay: number
|
||||||
hasError: boolean
|
hasError: boolean
|
||||||
|
color: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
||||||
|
|
||||||
state = {
|
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,
|
delay: -1,
|
||||||
hasError: false
|
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 () {
|
async componentDidMount () {
|
||||||
@ -34,13 +61,16 @@ export class Proxy extends React.Component<ProxyProps , ProxyState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { config, className } = this.props
|
const { config, className, onEdit = noop } = this.props
|
||||||
const { delay, hasError } = this.state
|
const { delay, color, hasError } = this.state
|
||||||
|
const backgroundColor = hasError ? undefined : color
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('proxy-item', { 'proxy-error': hasError }, className)}>
|
<div className={classnames('proxy-item', { 'proxy-error': hasError }, className)}>
|
||||||
<span className="proxy-name">{config.name}</span>
|
<span className="proxy-type" style={{ backgroundColor }}>{config.type}</span>
|
||||||
<span className="proxy-delay">{delay === -1 ? '-' : `${delay}s`}</span>
|
<p className="proxy-name">{config.name}</p>
|
||||||
|
<p className="proxy-delay">{delay === -1 ? '-' : `${delay}ms`}</p>
|
||||||
|
<Icon className="proxy-editor" type="setting" onClick={onEdit} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,37 +1,65 @@
|
|||||||
@import '~@styles/variables';
|
@import '~@styles/variables';
|
||||||
|
|
||||||
.proxy-item {
|
.proxy-item {
|
||||||
display: flex;
|
position: relative;
|
||||||
flex-direction: column;
|
padding: 10px;
|
||||||
align-items: center;
|
height: 110px;
|
||||||
justify-content: center;
|
width: 110px;
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
box-shadow: 0 0 20px rgba($color-primary-dark, 0.2);
|
|
||||||
border-radius: 4px;
|
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 {
|
.proxy-type {
|
||||||
height: 40px;
|
padding: 2px 5px;
|
||||||
width: 40px;
|
font-size: 10px;
|
||||||
|
color: $color-white;
|
||||||
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.proxy-name {
|
.proxy-name {
|
||||||
width: 80%;
|
max-height: 30px;
|
||||||
margin-top: 8px;
|
margin-top: 10px;
|
||||||
color: $color-primary-dark;
|
color: $color-primary-darken;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.proxy-delay {
|
.proxy-delay {
|
||||||
width: 80%;
|
position: absolute;
|
||||||
margin-top: 8px;
|
left: 10px;
|
||||||
color: $color-primary-dark;
|
bottom: 13px;
|
||||||
font-size: 12px;
|
font-size: 10px;
|
||||||
text-overflow: ellipsis;
|
color: rgba($color: $color-primary-darken, $alpha: 0.8);
|
||||||
overflow: hidden;
|
}
|
||||||
text-align: center;
|
|
||||||
|
.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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1 +1,2 @@
|
|||||||
export * from './Proxy'
|
export * from './Proxy'
|
||||||
|
export * from './ModifyProxyDialog'
|
||||||
|
@ -3,16 +3,26 @@ import { translate } 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 { Header, Icon } from '@components'
|
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'
|
import './style.scss'
|
||||||
|
|
||||||
interface ProxiesProps extends BaseRouterProps, I18nProps {}
|
interface ProxiesProps extends BaseRouterProps, I18nProps {}
|
||||||
|
|
||||||
|
interface ProxiesState {
|
||||||
|
showModifyProxyDialog: boolean
|
||||||
|
activeConfig?: IProxy
|
||||||
|
}
|
||||||
|
|
||||||
@inject(...storeKeys)
|
@inject(...storeKeys)
|
||||||
@observer
|
@observer
|
||||||
class Proxies extends React.Component<ProxiesProps, {}> {
|
class Proxies extends React.Component<ProxiesProps, ProxiesState> {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
showModifyProxyDialog: false,
|
||||||
|
activeConfig: null
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.props.config.fetchAndParseConfig()
|
this.props.config.fetchAndParseConfig()
|
||||||
@ -20,8 +30,10 @@ class Proxies extends React.Component<ProxiesProps, {}> {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { t, config } = this.props
|
const { t, config } = this.props
|
||||||
|
const { showModifyProxyDialog, activeConfig } = this.state
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<div className="page">
|
<div className="page">
|
||||||
<div className="proxies-container">
|
<div className="proxies-container">
|
||||||
<Header title={t('title')} >
|
<Header title={t('title')} >
|
||||||
@ -30,13 +42,14 @@ class Proxies extends React.Component<ProxiesProps, {}> {
|
|||||||
{
|
{
|
||||||
config.state === 'ok' && <ul className="proxies-list">
|
config.state === 'ok' && <ul className="proxies-list">
|
||||||
{
|
{
|
||||||
config.config.proxy.map(
|
config.config.proxy.map((p, index) => (
|
||||||
(p, index) => (
|
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
<Proxy config={p} />
|
<Proxy config={p} onEdit={() => this.setState({
|
||||||
|
showModifyProxyDialog: true,
|
||||||
|
activeConfig: p
|
||||||
|
})} />
|
||||||
</li>
|
</li>
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
}
|
}
|
||||||
@ -44,7 +57,19 @@ class Proxies extends React.Component<ProxiesProps, {}> {
|
|||||||
<div className="proxies-container">
|
<div className="proxies-container">
|
||||||
<Header title={t('groupTitle')} />
|
<Header title={t('groupTitle')} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{
|
||||||
|
showModifyProxyDialog && <ModifyProxyDialog
|
||||||
|
config={activeConfig}
|
||||||
|
onOk={config => {
|
||||||
|
console.log(config)
|
||||||
|
this.setState({ showModifyProxyDialog: false, activeConfig: null })
|
||||||
|
}}
|
||||||
|
onCancel={() => this.setState({ showModifyProxyDialog: false, activeConfig: null })}
|
||||||
|
/>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,11 @@
|
|||||||
list-style: none;
|
list-style: none;
|
||||||
|
|
||||||
li {
|
li {
|
||||||
margin: 20px 15px 20px 0;
|
margin: 8px 0;
|
||||||
|
margin-right: 15px;
|
||||||
|
|
||||||
|
&:nth-child(6n) {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
> i {
|
> i {
|
||||||
transform: scale(0.5);
|
transform: scale(0.5);
|
||||||
color: #fff;
|
color: $color-white;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
@import '~@styles/variables';
|
@import '~@styles/variables';
|
||||||
|
|
||||||
.sidebar {
|
.sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
width: 140px;
|
width: 140px;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebar-logo {
|
.sidebar-logo {
|
||||||
@ -42,7 +46,7 @@
|
|||||||
|
|
||||||
> a.active {
|
> a.active {
|
||||||
background: linear-gradient(135deg, $color-primary, $color-primary-dark);
|
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);
|
box-shadow: 0 2px 8px rgba($color: $color-primary-dark, $alpha: 0.5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,21 @@ export default {
|
|||||||
},
|
},
|
||||||
Proxies: {
|
Proxies: {
|
||||||
title: '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'
|
groupTitle: 'Policy Group'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,21 @@ export default {
|
|||||||
},
|
},
|
||||||
Proxies: {
|
Proxies: {
|
||||||
title: '代理',
|
title: '代理',
|
||||||
|
editDialog: {
|
||||||
|
title: '编辑代理',
|
||||||
|
color: '颜色',
|
||||||
|
name: '名字',
|
||||||
|
type: '类型',
|
||||||
|
server: '服务器',
|
||||||
|
port: '端口',
|
||||||
|
password: '密码',
|
||||||
|
cipher: '加密方式',
|
||||||
|
obfs: 'Obfs',
|
||||||
|
'obfs-host': 'Obfs-host',
|
||||||
|
uuid: 'Uuid',
|
||||||
|
alterid: 'Alterid',
|
||||||
|
tls: 'TLS'
|
||||||
|
},
|
||||||
groupTitle: '策略组'
|
groupTitle: '策略组'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,16 @@ export function removeLocalStorageItem (key: string) {
|
|||||||
return window.localStorage.removeItem(key)
|
return window.localStorage.removeItem(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function randomNumber (min: number, max: number) {
|
||||||
|
return (min + Math.random() * (max - min)) >> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sample<T> (arr: T[]) {
|
||||||
|
return arr[randomNumber(0, arr.length)]
|
||||||
|
}
|
||||||
|
|
||||||
|
export function noop () {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* to return Promise<[T, Error]>
|
* to return Promise<[T, Error]>
|
||||||
* @param {Promise<T>} promise
|
* @param {Promise<T>} promise
|
||||||
|
7
src/models/TagColors.ts
Normal file
7
src/models/TagColors.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const TagColors = [
|
||||||
|
'#ff3e5e',
|
||||||
|
'#686fff',
|
||||||
|
'#ff9a28',
|
||||||
|
'#b83fe6',
|
||||||
|
'#00c520'
|
||||||
|
]
|
@ -3,3 +3,4 @@ export * from './Config'
|
|||||||
export * from './Proxy'
|
export * from './Proxy'
|
||||||
export * from './Rule'
|
export * from './Rule'
|
||||||
export * from './I18n'
|
export * from './I18n'
|
||||||
|
export * from './TagColors'
|
||||||
|
@ -22,8 +22,8 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app {
|
.app {
|
||||||
display: flex;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
|
padding-left: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app.clash-x {
|
.app.clash-x {
|
||||||
@ -32,13 +32,15 @@ body {
|
|||||||
|
|
||||||
.page-container {
|
.page-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 20px 0;
|
height: 100vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page {
|
.page {
|
||||||
padding: 10px 35px;
|
padding: 20px 35px;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-bottom: 30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
max-width: 1200px;
|
max-width: 1200px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "clash-iconfont";
|
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 {
|
.clash-iconfont {
|
||||||
@ -37,3 +37,5 @@
|
|||||||
.icon-info::before { content: "\e60b"; }
|
.icon-info::before { content: "\e60b"; }
|
||||||
|
|
||||||
.icon-info-o::before { content: "\e60c"; }
|
.icon-info-o::before { content: "\e60c"; }
|
||||||
|
|
||||||
|
.icon-setting::before { content: "\e60d"; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user