mirror of
https://github.com/yaklang/yaklang-chrome-extension.git
synced 2026-09-22 03:10:43 +08:00
style: 样式调整
This commit is contained in:
@@ -310,6 +310,9 @@ module.exports = function (webpackEnv) {
|
||||
.map(ext => `.${ext}`)
|
||||
.filter(ext => useTypeScript || !ext.includes('ts')),
|
||||
alias: {
|
||||
'@assets': path.resolve(__dirname, '../src/assets'),
|
||||
'@components': path.resolve(__dirname, '../src/components'),
|
||||
'@network': path.resolve(__dirname, '../src/network'),
|
||||
// Support React Native Web
|
||||
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-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",
|
||||
"camelcase": "^6.2.1",
|
||||
"case-sensitive-paths-webpack-plugin": "^2.4.0",
|
||||
"classnames": "^2.5.1",
|
||||
"css-minimizer-webpack-plugin": "^3.2.0",
|
||||
"dotenv": "^10.0.0",
|
||||
"dotenv-expand": "^5.1.0",
|
||||
|
||||
+8
-2
@@ -1,5 +1,10 @@
|
||||
.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 {
|
||||
@@ -32,7 +37,8 @@
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-16
@@ -1,22 +1,28 @@
|
||||
import React from 'react';
|
||||
import './App.css';
|
||||
import {Layout, Row} from 'antd';
|
||||
import {Controller} from "./components/Controller";
|
||||
import React from "react";
|
||||
import "./App.css";
|
||||
import { ConfigProvider } from "antd";
|
||||
import { Contro } from "@components/Contro";
|
||||
import { Prox } from "@components/Prox";
|
||||
// import { Controller } from "./components/Controller";
|
||||
import {Proxifier} from "./components/Proxifier";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div className="App" style={{width: 300, backgroundColor: "#eee", padding: 8}}>
|
||||
<Layout>
|
||||
<Row>
|
||||
<Controller/>
|
||||
</Row>
|
||||
<Row>
|
||||
<Proxifier/>
|
||||
</Row>
|
||||
</Layout>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
token: {
|
||||
colorPrimary: "#F28B44",
|
||||
},
|
||||
}}
|
||||
>
|
||||
<div className="App">
|
||||
{/* <Contro /> */}
|
||||
<Prox />
|
||||
{/* <Controller/> */}
|
||||
{/* <Proxifier/> */}
|
||||
</div>
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
|
||||
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 {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
@@ -7,7 +11,29 @@ body {
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
*,
|
||||
*::before,
|
||||
*::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": {
|
||||
"outDir": "./dist/",
|
||||
"noImplicitAny": true,
|
||||
"module": "es6",
|
||||
"target": "es5",
|
||||
@@ -8,9 +7,16 @@
|
||||
"allowJs": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"moduleResolution": "node"
|
||||
"moduleResolution": "node",
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@*": ["src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"./src/**/*"
|
||||
"./src/**/*",
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+62
-57
@@ -5,60 +5,65 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
const webpack = require('webpack');
|
||||
|
||||
module.exports = {
|
||||
mode: 'development', // 设置模式为开发模式
|
||||
entry: './src/index.jsx', // 指定入口文件
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build'), // 输出目录
|
||||
filename: 'bundle.js', // 输出文件名
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV || 'development'),
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './public/index.html',
|
||||
filename: 'index.html'
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
// copy public assets exclude index.html
|
||||
{
|
||||
from: path.resolve(__dirname, 'public'),
|
||||
to: path.resolve(__dirname, 'build'),
|
||||
globOptions: {
|
||||
ignore: ['**/index.html']
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
watch: true, // 开启实时监控
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/, // 匹配所有的 css 文件
|
||||
use: ['style-loader', 'css-loader'] // 对匹配到的文件使用这两个 loader
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/, // 匹配TS和TSX文件
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/, // 匹配JS和JSX文件
|
||||
exclude: /node_modules/, // 排除node_modules目录
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'] // 使用的babel预设
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js', '.jsx'] // 解析扩展(确保能够解析JS和JSX文件)
|
||||
},
|
||||
devtool: 'inline-source-map', // 生成内联源映射,便于调试
|
||||
};
|
||||
mode: 'development', // 设置模式为开发模式
|
||||
entry: './src/index.jsx', // 指定入口文件
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'build'), // 输出目录
|
||||
filename: 'bundle.js', // 输出文件名
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
||||
'process.env.BABEL_ENV': JSON.stringify(process.env.BABEL_ENV || 'development'),
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
template: './public/index.html',
|
||||
filename: 'index.html'
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
// copy public assets exclude index.html
|
||||
{
|
||||
from: path.resolve(__dirname, 'public'),
|
||||
to: path.resolve(__dirname, 'build'),
|
||||
globOptions: {
|
||||
ignore: ['**/index.html']
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
watch: true, // 开启实时监控
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.css$/, // 匹配所有的 css 文件
|
||||
use: ['style-loader', 'css-loader'] // 对匹配到的文件使用这两个 loader
|
||||
},
|
||||
{
|
||||
test: /\.tsx?$/, // 匹配TS和TSX文件
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.(js|jsx)$/, // 匹配JS和JSX文件
|
||||
exclude: /node_modules/, // 排除node_modules目录
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['@babel/preset-env', '@babel/preset-react'] // 使用的babel预设
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.tsx', '.ts', '.js', '.jsx'], // 解析扩展(确保能够解析JS和JSX文件)
|
||||
alias: {
|
||||
'@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