Update config page style

This commit is contained in:
Haishan 2021-06-05 16:40:07 +08:00
parent fcab7cad4f
commit a18efa9723
9 changed files with 120 additions and 125 deletions

View file

@ -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 = {

View file

@ -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;
}

View 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;
}

View file

@ -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,34 +203,39 @@ function ConfigImpl({
</div> </div>
) : null ) : null
)} )}
<div>
<div className={s0.label}>Allow LAN</div>
<Switch
name="allow-lan"
checked={configState['allow-lan']}
onChange={handleSwitchOnChange}
/>
</div>
<div> <div>
<div className={s0.label}>Mode</div> <div className={s0.label}>Mode</div>
<ToggleSwitch <Select
options={optionsRule} options={modeOptions}
name="mode" selected={mode}
value={mode} onChange={(e) =>
onChange={handleInputOnChange} handleChangeValue({ name: 'mode', value: e.target.value })
}
/> />
</div> </div>
<div> <div>
<div className={s0.label}>Log Level</div> <div className={s0.label}>Log Level</div>
<ToggleSwitch <Select
options={optionsLogLevel} options={logLeveOptions}
name="log-level" selected={configState['log-level']}
value={configState['log-level']} onChange={(e) =>
onChange={handleInputOnChange} handleChangeValue({ name: 'log-level', value: e.target.value })
}
/> />
</div> </div>
<div>
<div className={s0.label}>Allow LAN</div>
<div className={s0.wrapSwitch}>
<Switch
name="allow-lan"
checked={configState['allow-lan']}
onChange={handleSwitchOnChange}
/>
</div>
</div>
</div> </div>
<div className={s0.sep}> <div className={s0.sep}>
@ -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>
); );

View file

@ -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;
} }

View file

@ -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

View file

@ -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>
); );

View file

@ -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
View file

@ -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;