mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-04-13 05:20:28 +08:00
feat: add clear ingress/egress and data flow indicators for proxy chain
This commit is contained in:
parent
4d72d2d0df
commit
a4617d1fed
1
.gitignore
vendored
1
.gitignore
vendored
@ -13,3 +13,4 @@ scripts/_env.sh
|
||||
.eslintcache
|
||||
.changelog_backups
|
||||
target
|
||||
CLAUDE.md
|
||||
|
||||
@ -27,5 +27,6 @@
|
||||
- 避免脏订阅地址无法 Scheme 导入订阅
|
||||
- macOS TUN 覆盖 DNS 时使用 114.114.114.114
|
||||
- 连通性测试替换为更快的 https://1.1.1.1
|
||||
- 链式代理增加明显的入口出口与数据流向标识
|
||||
|
||||
</details>
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
} from "@dnd-kit/sortable";
|
||||
import { CSS } from "@dnd-kit/utilities";
|
||||
import {
|
||||
ArrowDownward,
|
||||
Delete as DeleteIcon,
|
||||
DragIndicator,
|
||||
Link,
|
||||
@ -69,10 +70,18 @@ interface ProxyChainProps {
|
||||
interface SortableItemProps {
|
||||
proxy: ProxyChainItem;
|
||||
index: number;
|
||||
isFirst: boolean;
|
||||
isLast: boolean;
|
||||
onRemove: (id: string) => void;
|
||||
}
|
||||
|
||||
const SortableItem = ({ proxy, index, onRemove }: SortableItemProps) => {
|
||||
const SortableItem = ({
|
||||
proxy,
|
||||
index,
|
||||
isFirst,
|
||||
isLast,
|
||||
onRemove,
|
||||
}: SortableItemProps) => {
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const {
|
||||
@ -90,12 +99,24 @@ const SortableItem = ({ proxy, index, onRemove }: SortableItemProps) => {
|
||||
opacity: isDragging ? 0.5 : 1,
|
||||
};
|
||||
|
||||
const roleLabel = isFirst
|
||||
? t("proxies.page.chain.entryNode")
|
||||
: isLast
|
||||
? t("proxies.page.chain.exitNode")
|
||||
: undefined;
|
||||
|
||||
const roleColor = isFirst
|
||||
? theme.palette.success.main
|
||||
: isLast
|
||||
? theme.palette.warning.main
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Box
|
||||
ref={setNodeRef}
|
||||
style={style}
|
||||
sx={{
|
||||
mb: 1,
|
||||
mb: 0,
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
p: 1,
|
||||
@ -103,7 +124,9 @@ const SortableItem = ({ proxy, index, onRemove }: SortableItemProps) => {
|
||||
? theme.palette.action.selected
|
||||
: theme.palette.background.default,
|
||||
borderRadius: 1,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
border: roleColor
|
||||
? `1.5px solid ${roleColor}`
|
||||
: `1px solid ${theme.palette.divider}`,
|
||||
boxShadow: isDragging ? theme.shadows[4] : theme.shadows[1],
|
||||
transition: "box-shadow 0.2s, background-color 0.2s",
|
||||
}}
|
||||
@ -125,12 +148,25 @@ const SortableItem = ({ proxy, index, onRemove }: SortableItemProps) => {
|
||||
<DragIndicator />
|
||||
</Box>
|
||||
|
||||
<Chip
|
||||
label={`${index + 1}`}
|
||||
size="small"
|
||||
color="primary"
|
||||
sx={{ mr: 1, minWidth: 32 }}
|
||||
/>
|
||||
{roleLabel ? (
|
||||
<Chip
|
||||
label={roleLabel}
|
||||
size="small"
|
||||
sx={{
|
||||
mr: 1,
|
||||
fontWeight: 700,
|
||||
color: "#fff",
|
||||
backgroundColor: roleColor,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Chip
|
||||
label={`${index + 1}`}
|
||||
size="small"
|
||||
color="primary"
|
||||
sx={{ mr: 1, minWidth: 32 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Typography
|
||||
variant="body2"
|
||||
@ -579,12 +615,34 @@ export const ProxyChain = ({
|
||||
}}
|
||||
>
|
||||
{proxyChain.map((proxy, index) => (
|
||||
<SortableItem
|
||||
key={proxy.id}
|
||||
proxy={proxy}
|
||||
index={index}
|
||||
onRemove={handleRemoveProxy}
|
||||
/>
|
||||
<Box key={proxy.id}>
|
||||
<SortableItem
|
||||
proxy={proxy}
|
||||
index={index}
|
||||
isFirst={index === 0}
|
||||
isLast={
|
||||
index === proxyChain.length - 1 && proxyChain.length > 1
|
||||
}
|
||||
onRemove={handleRemoveProxy}
|
||||
/>
|
||||
{index < proxyChain.length - 1 && (
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
py: 0.25,
|
||||
}}
|
||||
>
|
||||
<ArrowDownward
|
||||
sx={{
|
||||
fontSize: 20,
|
||||
color: theme.palette.primary.main,
|
||||
opacity: 0.7,
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
</SortableContext>
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "مدخل",
|
||||
"exitNode": "مخرج"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "الوضع المباشر"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Eingang",
|
||||
"exitNode": "Ausgang"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Direktverbindungs-Modus"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Entry",
|
||||
"exitNode": "Exit"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Direct Mode"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Entrada",
|
||||
"exitNode": "Salida"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Modo de conexión directa"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "ورودی",
|
||||
"exitNode": "خروجی"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "حالت مستقیم"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Masuk",
|
||||
"exitNode": "Keluar"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Mode Langsung"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "入口",
|
||||
"exitNode": "出口"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "直接接続モード"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "체인 프록시는 최소 2개의 노드가 필요합니다. 하나 더 추가하세요.",
|
||||
"connectFailed": "프록시 체인 연결 실패",
|
||||
"disconnectFailed": "프록시 체인 연결 해제 실패",
|
||||
"duplicateNode": "프록시 노드가 체인에 이미 존재합니다"
|
||||
"duplicateNode": "프록시 노드가 체인에 이미 존재합니다",
|
||||
"entryNode": "입구",
|
||||
"exitNode": "출구"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "직접 모드"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Вход",
|
||||
"exitNode": "Выход"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Прямой режим"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Giriş",
|
||||
"exitNode": "Çıkış"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Doğrudan Mod"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "Chain proxy requires at least 2 nodes. Please add one more node.",
|
||||
"connectFailed": "Failed to connect to proxy chain",
|
||||
"disconnectFailed": "Failed to disconnect from proxy chain",
|
||||
"duplicateNode": "Proxy node already exists in chain"
|
||||
"duplicateNode": "Proxy node already exists in chain",
|
||||
"entryNode": "Кереш",
|
||||
"exitNode": "Чыгыш"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "Туры режим"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "链式代理至少需要 2 个节点,请再添加一个节点。",
|
||||
"connectFailed": "连接链式代理失败",
|
||||
"disconnectFailed": "断开链式代理失败",
|
||||
"duplicateNode": "该节点已在链式代理表中"
|
||||
"duplicateNode": "该节点已在链式代理表中",
|
||||
"entryNode": "入口",
|
||||
"exitNode": "出口"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "直连模式"
|
||||
|
||||
@ -49,7 +49,9 @@
|
||||
"minimumNodesHint": "鏈式代理至少需要 2 個節點,請再新增一個節點。",
|
||||
"connectFailed": "連線鏈式代理失敗",
|
||||
"disconnectFailed": "中斷鏈式代理失敗",
|
||||
"duplicateNode": "該節點已在鏈式代理表中"
|
||||
"duplicateNode": "該節點已在鏈式代理表中",
|
||||
"entryNode": "入口",
|
||||
"exitNode": "出口"
|
||||
},
|
||||
"messages": {
|
||||
"directMode": "直連模式"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user