mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-27 05:31:53 +08:00
style: 样式调整
This commit is contained in:
@@ -310,6 +310,9 @@ module.exports = function (webpackEnv) {
|
|||||||
.map(ext => `.${ext}`)
|
.map(ext => `.${ext}`)
|
||||||
.filter(ext => useTypeScript || !ext.includes('ts')),
|
.filter(ext => useTypeScript || !ext.includes('ts')),
|
||||||
alias: {
|
alias: {
|
||||||
|
'@assets': path.resolve(__dirname, '../src/assets'),
|
||||||
|
'@components': path.resolve(__dirname, '../src/components'),
|
||||||
|
'@network': path.resolve(__dirname, '../src/network'),
|
||||||
// Support React Native Web
|
// Support React Native Web
|
||||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
|
||||||
'react-native': 'react-native-web',
|
'react-native': 'react-native-web',
|
||||||
|
|||||||
Generated
+15
-14055
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,7 @@
|
|||||||
"browserslist": "^4.18.1",
|
"browserslist": "^4.18.1",
|
||||||
"camelcase": "^6.2.1",
|
"camelcase": "^6.2.1",
|
||||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
"css-minimizer-webpack-plugin": "^3.2.0",
|
"css-minimizer-webpack-plugin": "^3.2.0",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^10.0.0",
|
||||||
"dotenv-expand": "^5.1.0",
|
"dotenv-expand": "^5.1.0",
|
||||||
|
|||||||
+8
-2
@@ -1,5 +1,10 @@
|
|||||||
.App {
|
.App {
|
||||||
text-align: center;
|
width: 420px;
|
||||||
|
border-radius: 0px 0px 4px 4px;
|
||||||
|
border-right: 1px solid #EAECF3;
|
||||||
|
border-bottom: 1px solid #EAECF3;
|
||||||
|
border-left: 1px solid #EAECF3;
|
||||||
|
background: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.App-logo {
|
.App-logo {
|
||||||
@@ -32,7 +37,8 @@
|
|||||||
from {
|
from {
|
||||||
transform: rotate(0deg);
|
transform: rotate(0deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
transform: rotate(360deg);
|
transform: rotate(360deg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+22
-16
@@ -1,22 +1,28 @@
|
|||||||
import React from 'react';
|
import React from "react";
|
||||||
import './App.css';
|
import "./App.css";
|
||||||
import {Layout, Row} from 'antd';
|
import { ConfigProvider } from "antd";
|
||||||
import {Controller} from "./components/Controller";
|
import { Contro } from "@components/Contro";
|
||||||
|
import { Prox } from "@components/Prox";
|
||||||
|
// import { Controller } from "./components/Controller";
|
||||||
import {Proxifier} from "./components/Proxifier";
|
import {Proxifier} from "./components/Proxifier";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<div className="App" style={{width: 300, backgroundColor: "#eee", padding: 8}}>
|
<ConfigProvider
|
||||||
<Layout>
|
theme={{
|
||||||
<Row>
|
token: {
|
||||||
<Controller/>
|
colorPrimary: "#F28B44",
|
||||||
</Row>
|
},
|
||||||
<Row>
|
}}
|
||||||
<Proxifier/>
|
>
|
||||||
</Row>
|
<div className="App">
|
||||||
</Layout>
|
{/* <Contro /> */}
|
||||||
</div>
|
<Prox />
|
||||||
);
|
{/* <Controller/> */}
|
||||||
|
{/* <Proxifier/> */}
|
||||||
|
</div>
|
||||||
|
</ConfigProvider>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
import Icon from "@ant-design/icons";
|
||||||
|
import { CustomIconComponentProps } from "@ant-design/icons/lib/components/Icon";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface IconProps extends CustomIconComponentProps {
|
||||||
|
onClick: (e: React.MouseEvent) => void;
|
||||||
|
ref?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
const X = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M4 12L12 4M4 4L12 12"
|
||||||
|
stroke="#85899E"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/x
|
||||||
|
*/
|
||||||
|
export const XIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={X} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Check = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M3.33337 8.66669L6.00004 11.3334L12.6667 4.66669"
|
||||||
|
stroke="#56C991"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/check
|
||||||
|
*/
|
||||||
|
export const CheckIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={Check} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PencilAlt = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M7.33329 3.33334H3.99996C3.26358 3.33334 2.66663 3.93029 2.66663 4.66667V12C2.66663 12.7364 3.26358 13.3333 3.99996 13.3333H11.3333C12.0697 13.3333 12.6666 12.7364 12.6666 12V8.66667M11.7238 2.39052C12.2445 1.86983 13.0887 1.86983 13.6094 2.39052C14.1301 2.91122 14.1301 3.75544 13.6094 4.27614L7.88557 10H5.99996L5.99996 8.11438L11.7238 2.39052Z"
|
||||||
|
stroke="#85899E"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/pencil-alt
|
||||||
|
*/
|
||||||
|
export const PencilAltIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={PencilAlt} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Refresh = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M2.66663 2.66669V6.00002H3.0543M13.292 7.33335C12.964 4.70248 10.7197 2.66669 7.99996 2.66669C5.76171 2.66669 3.84549 4.04547 3.0543 6.00002M3.0543 6.00002H5.99996M13.3333 13.3334V10H12.9456M12.9456 10C12.1544 11.9546 10.2382 13.3334 7.99996 13.3334C5.28021 13.3334 3.03595 11.2976 2.70789 8.66669M12.9456 10H9.99996"
|
||||||
|
stroke="#85899E"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/refresh
|
||||||
|
*/
|
||||||
|
export const RefreshIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={Refresh} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Exit = () => (
|
||||||
|
<svg
|
||||||
|
width="24"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
fill="none"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M9.33333 6.66668C9.10226 6.78107 8.87965 6.90988 8.66667 7.0519C7.05869 8.12418 6 9.95027 6 12.0227C6 15.3239 8.68629 18 12 18C15.3137 18 18 15.3239 18 12.0227C18 9.95027 16.9413 8.12418 15.3333 7.0519C15.1204 6.90988 14.8977 6.78107 14.6667 6.66668M12 5.33334V10.6667"
|
||||||
|
stroke="#F7544A"
|
||||||
|
stroke-linecap="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description 退出
|
||||||
|
*/
|
||||||
|
export const ExitIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={Exit} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const PlusSm = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M8 4V8M8 8V12M8 8H12M8 8L4 8"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/plus-sm
|
||||||
|
*/
|
||||||
|
export const PlusSmIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={PlusSm} {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Trash = () => (
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16"
|
||||||
|
fill="none"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M12.6666 4.66667L12.0884 12.7617C12.0386 13.4594 11.458 14 10.7585 14H5.24145C4.54193 14 3.96135 13.4594 3.91151 12.7617L3.33329 4.66667M6.66663 7.33333V11.3333M9.33329 7.33333V11.3333M9.99996 4.66667V2.66667C9.99996 2.29848 9.70148 2 9.33329 2H6.66663C6.29844 2 5.99996 2.29848 5.99996 2.66667V4.66667M2.66663 4.66667H13.3333"
|
||||||
|
stroke="#F7544A"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
/**
|
||||||
|
* @description Icon/Outline/trash
|
||||||
|
*/
|
||||||
|
export const TrashIcon = (props: Partial<IconProps>) => {
|
||||||
|
return <Icon component={Trash} {...props} />;
|
||||||
|
};
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
.Contro {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 40px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-error-bg {
|
||||||
|
background-color: rgba(244, 115, 107, .10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-success-bg {
|
||||||
|
background-color: rgba(86, 201, 145, .10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-cont-input {
|
||||||
|
height: 24px;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-lable {
|
||||||
|
color: #85899E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-cont {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-cont-text-error {
|
||||||
|
color: #F6544A;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-cont-text-success {
|
||||||
|
color: #56C991;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-handle-icon {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-handle-icon svg {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contro-handle-icon-check {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-p {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Contro-cont span.anticon:hover {
|
||||||
|
background: #F0F1F3;
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Divider, Tooltip, Input } from "antd";
|
||||||
|
import classNames from "classnames";
|
||||||
|
import {
|
||||||
|
CheckIcon,
|
||||||
|
ExitIcon,
|
||||||
|
PencilAltIcon,
|
||||||
|
RefreshIcon,
|
||||||
|
XIcon,
|
||||||
|
} from "@assets/icon/icon";
|
||||||
|
import "./Contro.css";
|
||||||
|
|
||||||
|
interface ControProps {}
|
||||||
|
export const Contro: React.FC<ControProps> = () => {
|
||||||
|
const [isEdit, setIsEdit] = useState<boolean>(false);
|
||||||
|
const [connected, setConnected] = useState(false);
|
||||||
|
const [autoFindFailedReason, setAutoFindFailedReason] = useState<string>("");
|
||||||
|
const [enginePort, setEnginePort] = useState<string>("0");
|
||||||
|
const [enginePortTemp, setEnginePortTemp] = useState<string>(enginePort);
|
||||||
|
|
||||||
|
// useEffect(() => {
|
||||||
|
// const updateStatus = () => {
|
||||||
|
// wsc.updateWSCStatus();
|
||||||
|
// };
|
||||||
|
// updateStatus();
|
||||||
|
// const id = setInterval(updateStatus, 500);
|
||||||
|
|
||||||
|
// wsc.onWSCMessage((req: { connected: boolean }) => {
|
||||||
|
// if (req["connected"] === undefined) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// console.log("connected", req.connected);
|
||||||
|
// setConnected(req.connected);
|
||||||
|
// });
|
||||||
|
// return () => {
|
||||||
|
// clearInterval(id);
|
||||||
|
// };
|
||||||
|
// }, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames("Contro", {
|
||||||
|
["Contro-success-bg"]: !autoFindFailedReason,
|
||||||
|
["Contro-error-bg"]: autoFindFailedReason,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<div className="Contro-lable">Yakit 引擎连接状态:</div>
|
||||||
|
<div className="Contro-cont">
|
||||||
|
{isEdit ? (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
rootClassName="Contro-cont-input"
|
||||||
|
value={enginePortTemp}
|
||||||
|
onChange={(e) => {
|
||||||
|
// TODO 需要校验
|
||||||
|
const value = e.target.value;
|
||||||
|
setEnginePortTemp(value);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<div className="Contro-handle-icon">
|
||||||
|
<XIcon
|
||||||
|
className="icon-p"
|
||||||
|
onClick={() => {
|
||||||
|
setIsEdit(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<CheckIcon
|
||||||
|
className="contro-handle-icon-check icon-p"
|
||||||
|
onClick={() => {
|
||||||
|
setIsEdit(false);
|
||||||
|
setEnginePort(enginePortTemp);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={classNames("Contro-cont-text", {
|
||||||
|
["Contro-cont-text-success"]: !autoFindFailedReason,
|
||||||
|
["Contro-cont-text-error"]: autoFindFailedReason,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
{autoFindFailedReason
|
||||||
|
? autoFindFailedReason + "(" + enginePort + ")"
|
||||||
|
: "已连接(" + enginePort + ")"}
|
||||||
|
</div>
|
||||||
|
<div className="Contro-handle-icon">
|
||||||
|
<Tooltip title="修改监听端口">
|
||||||
|
<PencilAltIcon
|
||||||
|
className="icon-p"
|
||||||
|
onClick={() => {
|
||||||
|
setIsEdit(true);
|
||||||
|
setEnginePortTemp(enginePort);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<Divider type="vertical" style={{ height: 16 }} />
|
||||||
|
{autoFindFailedReason ? (
|
||||||
|
<Tooltip title="重新连接">
|
||||||
|
<RefreshIcon />
|
||||||
|
</Tooltip>
|
||||||
|
) : (
|
||||||
|
<Tooltip title="断开连接">
|
||||||
|
<ExitIcon />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
.Prox-title-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px 24px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-left .prox-title {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: #31343F;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-left .prox-number {
|
||||||
|
display: inline-block;
|
||||||
|
width: 18px;
|
||||||
|
height: 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: #85899E;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #F0F1F3;
|
||||||
|
font-size: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-right .Prox-add-text {
|
||||||
|
margin-right: 4px;
|
||||||
|
color: var(--yakit-primary);
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-title-wrap-right .Prox-add-icon svg {
|
||||||
|
color: var(--yakit-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-wrap {
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 305px;
|
||||||
|
padding: 16px;
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-list {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 28px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid #EAECF3;
|
||||||
|
border-radius: 4px;
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-list:hover {
|
||||||
|
border: 1px solid var(--yakit-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-list .add-list-icon svg {
|
||||||
|
color: #85899E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-wrap .add-list .add-list-text {
|
||||||
|
margin-left: 4px;
|
||||||
|
color: #31343F;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-wrap .Prox-list-item-wrap {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 10px 8px;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-wrap .Prox-list-item-wrap:hover {
|
||||||
|
background-color: #F8F8F8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-item-space .ant-space-item .ant-space-compact {
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-item-space .ant-space-item .ant-space-compact .ant-select-single {
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Prox-list-wrap .Prox-list-item-wrap:hover .proxy-list-del-icon {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-list-del-icon {
|
||||||
|
display: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.proxy-list-del-icon:hover {
|
||||||
|
background: #F0F1F3;
|
||||||
|
}
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Space, Select, Input, Switch } from "antd";
|
||||||
|
import { PlusSmIcon, TrashIcon } from "@assets/icon/icon";
|
||||||
|
import { wsc } from "@network/chrome";
|
||||||
|
import "./Prox.css";
|
||||||
|
|
||||||
|
interface ProxyConfig {
|
||||||
|
id: string;
|
||||||
|
scheme: "http" | "socks5";
|
||||||
|
host: string;
|
||||||
|
port: string;
|
||||||
|
hostStatus: "error" | "";
|
||||||
|
portStatus: "error" | "";
|
||||||
|
open: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProxProps {}
|
||||||
|
export const Prox: React.FC<ProxProps> = () => {
|
||||||
|
const [proxyList, setProxyList] = useState<ProxyConfig[]>([]);
|
||||||
|
|
||||||
|
// proxy
|
||||||
|
useEffect(() => {
|
||||||
|
const update = () => {
|
||||||
|
wsc.updateProxyStatus();
|
||||||
|
};
|
||||||
|
update();
|
||||||
|
|
||||||
|
const id = setInterval(update, 500);
|
||||||
|
return () => {
|
||||||
|
clearInterval(id);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
wsc.onProxyStatusMessage((msg) => {
|
||||||
|
if (msg["proxy"] === undefined || msg["enable"] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
console.log("当前代理:", msg);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const hostOnchange = (value: string, id: string) => {
|
||||||
|
const ipPattern = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
|
||||||
|
const domainPattern = /^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
|
||||||
|
const copyProxyList = structuredClone(proxyList);
|
||||||
|
if (value === "" || ipPattern.test(value) || domainPattern.test(value)) {
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === id) {
|
||||||
|
i.hostStatus = "";
|
||||||
|
i.host = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === id) {
|
||||||
|
i.hostStatus = "error";
|
||||||
|
i.host = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setProxyList(copyProxyList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const portOnchange = (value: string, id: string) => {
|
||||||
|
const portNumber = parseInt(value, 10);
|
||||||
|
const copyProxyList = structuredClone(proxyList);
|
||||||
|
if (
|
||||||
|
value === "" ||
|
||||||
|
(/^\d+$/.test(value) && portNumber >= 0 && portNumber <= 65535)
|
||||||
|
) {
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === id) {
|
||||||
|
i.portStatus = "";
|
||||||
|
i.port = value === "" ? "" : portNumber + "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === id) {
|
||||||
|
i.portStatus = "error";
|
||||||
|
i.port = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
setProxyList(copyProxyList);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="Prox">
|
||||||
|
<div className="Prox-title-wrap">
|
||||||
|
<div className="Prox-title-wrap-left">
|
||||||
|
<span className="prox-title">设置代理</span>
|
||||||
|
<span className="prox-number">{proxyList.length}</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="Prox-title-wrap-right"
|
||||||
|
onClick={() => {
|
||||||
|
setProxyList([
|
||||||
|
...proxyList,
|
||||||
|
{
|
||||||
|
id: Math.random() + "",
|
||||||
|
scheme: "http",
|
||||||
|
host: "",
|
||||||
|
port: "",
|
||||||
|
hostStatus: "",
|
||||||
|
portStatus: "",
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="Prox-add-text">添加</span>
|
||||||
|
<PlusSmIcon className="Prox-add-icon" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="Prox-list-wrap">
|
||||||
|
{proxyList.length ? (
|
||||||
|
proxyList.map((item) => (
|
||||||
|
<div className="Prox-list-item-wrap" key={item.id}>
|
||||||
|
<Space className="Prox-list-item-space">
|
||||||
|
<Space.Compact>
|
||||||
|
<Select
|
||||||
|
value={item.scheme}
|
||||||
|
style={{ width: 88 }}
|
||||||
|
disabled={item.open}
|
||||||
|
onChange={(value, option) => {
|
||||||
|
const copyProxyList = structuredClone(proxyList);
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === item.id) {
|
||||||
|
i.scheme = value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setProxyList(copyProxyList);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Select.Option value="http">HTTP</Select.Option>
|
||||||
|
<Select.Option value="socks5">Socks5</Select.Option>
|
||||||
|
</Select>
|
||||||
|
<Input
|
||||||
|
value={item.host}
|
||||||
|
style={{ width: 136 }}
|
||||||
|
disabled={item.open}
|
||||||
|
status={item.hostStatus}
|
||||||
|
onChange={(e) => hostOnchange(e.target.value, item.id)}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
value={item.port}
|
||||||
|
style={{ width: 64 }}
|
||||||
|
disabled={item.open}
|
||||||
|
status={item.portStatus}
|
||||||
|
onChange={(e) => portOnchange(e.target.value, item.id)}
|
||||||
|
/>
|
||||||
|
</Space.Compact>
|
||||||
|
</Space>
|
||||||
|
{!item.open && (
|
||||||
|
<TrashIcon
|
||||||
|
className="proxy-list-del-icon"
|
||||||
|
onClick={() => {
|
||||||
|
setProxyList(proxyList.filter((i) => i.id !== item.id));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<Switch
|
||||||
|
checkedChildren="启"
|
||||||
|
unCheckedChildren="停"
|
||||||
|
value={item.open}
|
||||||
|
disabled={
|
||||||
|
item.hostStatus === "error" ||
|
||||||
|
item.portStatus === "error" ||
|
||||||
|
item.host === "" ||
|
||||||
|
item.port === ""
|
||||||
|
}
|
||||||
|
onChange={(checked: boolean) => {
|
||||||
|
wsc.clearproxy();
|
||||||
|
const copyProxyList = structuredClone(proxyList);
|
||||||
|
copyProxyList.forEach((i) => {
|
||||||
|
if (i.id === item.id) {
|
||||||
|
i.open = checked;
|
||||||
|
if (checked) {
|
||||||
|
wsc.setproxy(item.scheme, item.host, Number(item.port));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
i.open = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setProxyList(copyProxyList);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div
|
||||||
|
className="add-list"
|
||||||
|
onClick={() => {
|
||||||
|
setProxyList([
|
||||||
|
{
|
||||||
|
id: Math.random() + "",
|
||||||
|
scheme: "http",
|
||||||
|
host: "127.0.0.1",
|
||||||
|
port: "8083",
|
||||||
|
hostStatus: "",
|
||||||
|
portStatus: "",
|
||||||
|
open: false,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<PlusSmIcon className="add-list-icon" />
|
||||||
|
<span className="add-list-text">添加</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
+29
-3
@@ -1,3 +1,7 @@
|
|||||||
|
html:root {
|
||||||
|
--yakit-primary: #F28B44
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||||
@@ -7,7 +11,29 @@ body {
|
|||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
code {
|
*,
|
||||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
*::before,
|
||||||
monospace;
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
/*滚动条整体样式*/
|
||||||
|
width: 8px;
|
||||||
|
/*高宽分别对应横竖滚动条的尺寸*/
|
||||||
|
height: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
/*滚动条里面小方块*/
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: inset 0 0 5px rgba(193, 193, 193);
|
||||||
|
background: #c1c1c1;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
/*滚动条里面轨道*/
|
||||||
|
box-shadow: inset 0 0 5px rgba(193, 193, 193);
|
||||||
|
border-radius: 10px;
|
||||||
|
background: #ededed;
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-4
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./dist/",
|
|
||||||
"noImplicitAny": true,
|
"noImplicitAny": true,
|
||||||
"module": "es6",
|
"module": "es6",
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
@@ -8,9 +7,16 @@
|
|||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
"allowSyntheticDefaultImports": true,
|
"allowSyntheticDefaultImports": true,
|
||||||
"moduleResolution": "node"
|
"moduleResolution": "node",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"paths": {
|
||||||
|
"@*": ["src/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*"
|
"./src/**/*",
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
+62
-57
@@ -5,60 +5,65 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
|||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: 'development', // 设置模式为开发模式
|
mode: 'development', // 设置模式为开发模式
|
||||||
entry: './src/index.jsx', // 指定入口文件
|
entry: './src/index.jsx', // 指定入口文件
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, 'build'), // 输出目录
|
path: path.resolve(__dirname, 'build'), // 输出目录
|
||||||
filename: 'bundle.js', // 输出文件名
|
filename: 'bundle.js', // 输出文件名
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||||
'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV || 'development'),
|
'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV || 'development'),
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
template: './public/index.html',
|
template: './public/index.html',
|
||||||
filename: 'index.html'
|
filename: 'index.html'
|
||||||
}),
|
}),
|
||||||
new CopyWebpackPlugin({
|
new CopyWebpackPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
// copy public assets exclude index.html
|
// copy public assets exclude index.html
|
||||||
{
|
{
|
||||||
from: path.resolve(__dirname, 'public'),
|
from: path.resolve(__dirname, 'public'),
|
||||||
to: path.resolve(__dirname, 'build'),
|
to: path.resolve(__dirname, 'build'),
|
||||||
globOptions: {
|
globOptions: {
|
||||||
ignore: ['**/index.html']
|
ignore: ['**/index.html']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
watch: true, // 开启实时监控
|
watch: true, // 开启实时监控
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.css$/, // 匹配所有的 css 文件
|
test: /\.css$/, // 匹配所有的 css 文件
|
||||||
use: ['style-loader', 'css-loader'] // 对匹配到的文件使用这两个 loader
|
use: ['style-loader', 'css-loader'] // 对匹配到的文件使用这两个 loader
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/, // 匹配TS和TSX文件
|
test: /\.tsx?$/, // 匹配TS和TSX文件
|
||||||
use: 'ts-loader',
|
use: 'ts-loader',
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(js|jsx)$/, // 匹配JS和JSX文件
|
test: /\.(js|jsx)$/, // 匹配JS和JSX文件
|
||||||
exclude: /node_modules/, // 排除node_modules目录
|
exclude: /node_modules/, // 排除node_modules目录
|
||||||
use: {
|
use: {
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
options: {
|
||||||
presets: ['@babel/preset-env', '@babel/preset-react'] // 使用的babel预设
|
presets: ['@babel/preset-env', '@babel/preset-react'] // 使用的babel预设
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.tsx', '.ts', '.js', '.jsx'] // 解析扩展(确保能够解析JS和JSX文件)
|
extensions: ['.tsx', '.ts', '.js', '.jsx'], // 解析扩展(确保能够解析JS和JSX文件)
|
||||||
},
|
alias: {
|
||||||
devtool: 'inline-source-map', // 生成内联源映射,便于调试
|
'@assets': path.resolve(__dirname, './src/assets'),
|
||||||
};
|
'@components': path.resolve(__dirname, './src/components'),
|
||||||
|
'@network': path.resolve(__dirname, './src/network'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
devtool: 'inline-source-map', // 生成内联源映射,便于调试
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user