Update config page style
This commit is contained in:
parent
fcab7cad4f
commit
a18efa9723
9 changed files with 120 additions and 125 deletions
|
@ -10,7 +10,7 @@ type ButtonInternalProps = {
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
label?: string;
|
label?: string;
|
||||||
text?: string;
|
text?: string;
|
||||||
start?: React.ReactElement | (() => React.ReactElement);
|
start?: React.ReactNode | (() => React.ReactNode);
|
||||||
};
|
};
|
||||||
|
|
||||||
type ButtonProps = {
|
type ButtonProps = {
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
.root {
|
|
||||||
> div {
|
|
||||||
min-width: 345px;
|
|
||||||
@media (--breakpoint-not-small) {
|
|
||||||
width: 360px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.root,
|
|
||||||
.section {
|
|
||||||
padding: 6px 15px 15px;
|
|
||||||
@media (--breakpoint-not-small) {
|
|
||||||
padding: 0 40px 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.sep {
|
|
||||||
padding: 0 15px;
|
|
||||||
@media (--breakpoint-not-small) {
|
|
||||||
padding: 0 40px;
|
|
||||||
}
|
|
||||||
> div {
|
|
||||||
border-top: 1px dashed #373737;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
padding: 16px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.narrow {
|
|
||||||
width: 360px;
|
|
||||||
}
|
|
39
src/components/Config.module.scss
Normal file
39
src/components/Config.module.scss
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
.root,
|
||||||
|
.section {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(345px, 1fr));
|
||||||
|
max-width: 900px;
|
||||||
|
gap: 5px;
|
||||||
|
@media (--breakpoint-not-small) {
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.root,
|
||||||
|
.section {
|
||||||
|
padding: 6px 15px 10px;
|
||||||
|
@media (--breakpoint-not-small) {
|
||||||
|
padding: 10px 40px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.wrapSwitch {
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sep {
|
||||||
|
max-width: 900px;
|
||||||
|
padding: 0 15px;
|
||||||
|
@media (--breakpoint-not-small) {
|
||||||
|
padding: 0 40px;
|
||||||
|
}
|
||||||
|
> div {
|
||||||
|
border-top: 1px dashed #373737;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
padding: 11px 0;
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { LogOut } from 'react-feather';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Select from 'src/components/shared/Select';
|
import Select from 'src/components/shared/Select';
|
||||||
import { ClashGeneralConfig, DispatchFn, State } from 'src/store/types';
|
import { ClashGeneralConfig, DispatchFn, State } from 'src/store/types';
|
||||||
|
@ -12,55 +13,25 @@ import {
|
||||||
import { fetchConfigs, getConfigs, updateConfigs } from '../store/configs';
|
import { fetchConfigs, getConfigs, updateConfigs } from '../store/configs';
|
||||||
import { openModal } from '../store/modals';
|
import { openModal } from '../store/modals';
|
||||||
import Button from './Button';
|
import Button from './Button';
|
||||||
import s0 from './Config.module.css';
|
import s0 from './Config.module.scss';
|
||||||
import ContentHeader from './ContentHeader';
|
import ContentHeader from './ContentHeader';
|
||||||
import Input, { SelfControlledInput } from './Input';
|
import Input, { SelfControlledInput } from './Input';
|
||||||
import { Selection2 } from './Selection';
|
import { Selection2 } from './Selection';
|
||||||
import { connect, useStoreActions } from './StateProvider';
|
import { connect, useStoreActions } from './StateProvider';
|
||||||
import Switch from './SwitchThemed';
|
import Switch from './SwitchThemed';
|
||||||
import ToggleSwitch from './ToggleSwitch';
|
|
||||||
import TrafficChartSample from './TrafficChartSample';
|
import TrafficChartSample from './TrafficChartSample';
|
||||||
|
// import ToggleSwitch from './ToggleSwitch';
|
||||||
|
|
||||||
const { useEffect, useState, useCallback, useRef, useMemo } = React;
|
const { useEffect, useState, useCallback, useRef, useMemo } = React;
|
||||||
|
|
||||||
const propsList = [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }];
|
const propsList = [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }];
|
||||||
|
|
||||||
const optionsRule = [
|
const logLeveOptions = [
|
||||||
{
|
['debug', 'Debug'],
|
||||||
label: 'Global',
|
['warning', 'Warning'],
|
||||||
value: 'Global',
|
['info', 'Info'],
|
||||||
},
|
['error', 'Error'],
|
||||||
{
|
['silent', 'Silent'],
|
||||||
label: 'Rule',
|
|
||||||
value: 'Rule',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Direct',
|
|
||||||
value: 'Direct',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const optionsLogLevel = [
|
|
||||||
{
|
|
||||||
label: 'Debug',
|
|
||||||
value: 'debug',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Warning',
|
|
||||||
value: 'warning',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Info',
|
|
||||||
value: 'info',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Error',
|
|
||||||
value: 'error',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: 'Silent',
|
|
||||||
value: 'silent',
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const portFields = [
|
const portFields = [
|
||||||
|
@ -75,6 +46,12 @@ const langOptions = [
|
||||||
['en', 'English'],
|
['en', 'English'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const modeOptions = [
|
||||||
|
['Global', 'Global'],
|
||||||
|
['Rule', 'Rule'],
|
||||||
|
['Direct', 'Direct'],
|
||||||
|
];
|
||||||
|
|
||||||
const mapState = (s: State) => ({
|
const mapState = (s: State) => ({
|
||||||
configs: getConfigs(s),
|
configs: getConfigs(s),
|
||||||
apiConfig: getClashAPIConfig(s),
|
apiConfig: getClashAPIConfig(s),
|
||||||
|
@ -144,12 +121,9 @@ function ConfigImpl({
|
||||||
[apiConfig, dispatch, setConfigState]
|
[apiConfig, dispatch, setConfigState]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleInputOnChange = useCallback(
|
const handleChangeValue = useCallback(
|
||||||
(e) => {
|
({ name, value }) => {
|
||||||
const target = e.target;
|
switch (name) {
|
||||||
const { name } = target;
|
|
||||||
const { value } = target;
|
|
||||||
switch (target.name) {
|
|
||||||
case 'mode':
|
case 'mode':
|
||||||
case 'log-level':
|
case 'log-level':
|
||||||
setConfigState(name, value);
|
setConfigState(name, value);
|
||||||
|
@ -159,8 +133,8 @@ function ConfigImpl({
|
||||||
case 'socks-port':
|
case 'socks-port':
|
||||||
case 'mixed-port':
|
case 'mixed-port':
|
||||||
case 'port':
|
case 'port':
|
||||||
if (target.value !== '') {
|
if (value !== '') {
|
||||||
const num = parseInt(target.value, 10);
|
const num = parseInt(value, 10);
|
||||||
if (num < 0 || num > 65535) return;
|
if (num < 0 || num > 65535) return;
|
||||||
}
|
}
|
||||||
setConfigState(name, value);
|
setConfigState(name, value);
|
||||||
|
@ -172,6 +146,11 @@ function ConfigImpl({
|
||||||
[apiConfig, dispatch, setConfigState]
|
[apiConfig, dispatch, setConfigState]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleInputOnChange = useCallback(
|
||||||
|
(e) => handleChangeValue(e.target),
|
||||||
|
[handleChangeValue]
|
||||||
|
);
|
||||||
|
|
||||||
const { selectChartStyleIndex, updateAppConfig } = useStoreActions();
|
const { selectChartStyleIndex, updateAppConfig } = useStoreActions();
|
||||||
|
|
||||||
const handleInputOnBlur = useCallback(
|
const handleInputOnBlur = useCallback(
|
||||||
|
@ -224,33 +203,38 @@ function ConfigImpl({
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={s0.label}>Mode</div>
|
||||||
|
<Select
|
||||||
|
options={modeOptions}
|
||||||
|
selected={mode}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleChangeValue({ name: 'mode', value: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={s0.label}>Log Level</div>
|
||||||
|
<Select
|
||||||
|
options={logLeveOptions}
|
||||||
|
selected={configState['log-level']}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleChangeValue({ name: 'log-level', value: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div className={s0.label}>Allow LAN</div>
|
<div className={s0.label}>Allow LAN</div>
|
||||||
|
<div className={s0.wrapSwitch}>
|
||||||
<Switch
|
<Switch
|
||||||
name="allow-lan"
|
name="allow-lan"
|
||||||
checked={configState['allow-lan']}
|
checked={configState['allow-lan']}
|
||||||
onChange={handleSwitchOnChange}
|
onChange={handleSwitchOnChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className={s0.label}>Mode</div>
|
|
||||||
<ToggleSwitch
|
|
||||||
options={optionsRule}
|
|
||||||
name="mode"
|
|
||||||
value={mode}
|
|
||||||
onChange={handleInputOnChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div className={s0.label}>Log Level</div>
|
|
||||||
<ToggleSwitch
|
|
||||||
options={optionsLogLevel}
|
|
||||||
name="log-level"
|
|
||||||
value={configState['log-level']}
|
|
||||||
onChange={handleInputOnChange}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -260,15 +244,6 @@ function ConfigImpl({
|
||||||
|
|
||||||
<div className={s0.section}>
|
<div className={s0.section}>
|
||||||
<div>
|
<div>
|
||||||
<div className={s0.label}>{t('chart_style')}</div>
|
|
||||||
<Selection2
|
|
||||||
OptionComponent={TrafficChartSample}
|
|
||||||
optionPropsList={propsList}
|
|
||||||
selectedIndex={selectedChartStyleIndex}
|
|
||||||
onChange={selectChartStyleIndex}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={s0.narrow}>
|
|
||||||
<div className={s0.label}>{t('latency_test_url')}</div>
|
<div className={s0.label}>{t('latency_test_url')}</div>
|
||||||
<SelfControlledInput
|
<SelfControlledInput
|
||||||
name="latencyTestUrl"
|
name="latencyTestUrl"
|
||||||
|
@ -277,13 +252,9 @@ function ConfigImpl({
|
||||||
onBlur={handleInputOnBlur}
|
onBlur={handleInputOnBlur}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<div className={s0.label}>Action</div>
|
|
||||||
<Button label="Switch backend" onClick={openAPIConfigModal} />
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div className={s0.label}>{t('lang')}</div>
|
<div className={s0.label}>{t('lang')}</div>
|
||||||
<div className={s0.narrow}>
|
<div>
|
||||||
<Select
|
<Select
|
||||||
options={langOptions}
|
options={langOptions}
|
||||||
selected={i18n.language}
|
selected={i18n.language}
|
||||||
|
@ -291,6 +262,25 @@ function ConfigImpl({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={s0.label}>{t('chart_style')}</div>
|
||||||
|
<Selection2
|
||||||
|
OptionComponent={TrafficChartSample}
|
||||||
|
optionPropsList={propsList}
|
||||||
|
selectedIndex={selectedChartStyleIndex}
|
||||||
|
onChange={selectChartStyleIndex}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div className={s0.label}>Action</div>
|
||||||
|
<Button
|
||||||
|
start={<LogOut size={16} />}
|
||||||
|
label="Switch backend"
|
||||||
|
onClick={openAPIConfigModal}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid var(--color-input-border);
|
border: 1px solid var(--color-input-border);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: #c1c1c1;
|
color: inherit;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
|
@ -13,6 +13,7 @@
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input:focus {
|
.input:focus {
|
||||||
box-shadow: rgba(66, 153, 225, 0.6) 0px 0px 0px 3px;
|
box-shadow: rgba(66, 153, 225, 0.6) 0px 0px 0px 3px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,10 @@ export function SelfControlledInput({ value, ...restProps }) {
|
||||||
}
|
}
|
||||||
refValue.current = value;
|
refValue.current = value;
|
||||||
}, [value]);
|
}, [value]);
|
||||||
const onChange = useCallback((e) => setInternalValue(e.target.value), [
|
const onChange = useCallback(
|
||||||
setInternalValue,
|
(e) => setInternalValue(e.target.value),
|
||||||
]);
|
[setInternalValue]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<input
|
<input
|
||||||
|
|
|
@ -47,12 +47,7 @@ export default function TrafficChart({ id }) {
|
||||||
useLineChart(Chart, eleId, data, null, extraChartOptions);
|
useLineChart(Chart, eleId, data, null, extraChartOptions);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div style={{ width: 100, padding: 5 }}>
|
||||||
style={{
|
|
||||||
width: 130,
|
|
||||||
padding: 5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<canvas id={eleId} />
|
<canvas id={eleId} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid var(--color-input-border);
|
border: 1px solid var(--color-input-border);
|
||||||
transition: all 100ms ease 0s;
|
|
||||||
background-image: url(data:image/svg+xml,%0A%20%20%20%20%3Csvg%20width%3D%228%22%20height%3D%2224%22%20viewBox%3D%220%200%208%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%207L7%2011H1L4%207Z%22%20fill%3D%22%23999999%22%20%2F%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%2017L1%2013L7%2013L4%2017Z%22%20fill%3D%22%23999999%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A%20%20);
|
background-image: url(data:image/svg+xml,%0A%20%20%20%20%3Csvg%20width%3D%228%22%20height%3D%2224%22%20viewBox%3D%220%200%208%2024%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%207L7%2011H1L4%207Z%22%20fill%3D%22%23999999%22%20%2F%3E%0A%20%20%20%20%20%20%3Cpath%20d%3D%22M4%2017L1%2013L7%2013L4%2017Z%22%20fill%3D%22%23999999%22%20%2F%3E%0A%20%20%20%20%3C%2Fsvg%3E%0A%20%20);
|
||||||
background-position: calc(100% - 8px) center;
|
background-position: right 8px center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
4
src/custom.d.ts
vendored
4
src/custom.d.ts
vendored
|
@ -6,6 +6,10 @@ declare module '*.module.css' {
|
||||||
const classes: { [key: string]: string };
|
const classes: { [key: string]: string };
|
||||||
export default classes;
|
export default classes;
|
||||||
}
|
}
|
||||||
|
declare module '*.module.scss' {
|
||||||
|
const classes: { [key: string]: string };
|
||||||
|
export default classes;
|
||||||
|
}
|
||||||
|
|
||||||
interface Window {
|
interface Window {
|
||||||
i18n: any;
|
i18n: any;
|
||||||
|
|
Loading…
Reference in a new issue