import { DirectionsRounded, LanguageRounded, MultipleStopRounded, } from "@mui/icons-material"; import { Box, Paper, Stack, Typography } from "@mui/material"; import { useLockFn } from "ahooks"; import { useMemo } from "react"; import { useTranslation } from "react-i18next"; import { closeAllConnections } from "tauri-plugin-mihomo-api"; import { useVerge } from "@/hooks/use-verge"; import { useAppData } from "@/providers/app-data-context"; import { patchClashMode } from "@/services/cmds"; import type { TranslationKey } from "@/types/generated/i18n-keys"; const CLASH_MODES = ["rule", "global", "direct"] as const; type ClashMode = (typeof CLASH_MODES)[number]; const isClashMode = (mode: string): mode is ClashMode => (CLASH_MODES as readonly string[]).includes(mode); const MODE_META: Record< ClashMode, { label: TranslationKey; description: TranslationKey } > = { rule: { label: "home.components.clashMode.labels.rule", description: "home.components.clashMode.descriptions.rule", }, global: { label: "home.components.clashMode.labels.global", description: "home.components.clashMode.descriptions.global", }, direct: { label: "home.components.clashMode.labels.direct", description: "home.components.clashMode.descriptions.direct", }, }; export const ClashModeCard = () => { const { t } = useTranslation(); const { verge } = useVerge(); const { clashConfig, refreshClashConfig } = useAppData(); // 支持的模式列表 const modeList = CLASH_MODES; // 直接使用API返回的模式,不维护本地状态 const currentMode = clashConfig?.mode?.toLowerCase(); const currentModeKey = typeof currentMode === "string" && isClashMode(currentMode) ? currentMode : undefined; const modeDescription = useMemo(() => { if (currentModeKey) { return t(MODE_META[currentModeKey].description); } return t("home.components.clashMode.errors.communication"); }, [currentModeKey, t]); // 模式图标映射 const modeIcons = useMemo( () => ({ rule: , global: , direct: , }), [], ); // 切换模式的处理函数 const onChangeMode = useLockFn(async (mode: ClashMode) => { if (mode === currentModeKey) return; if (verge?.auto_close_connection) { closeAllConnections(); } try { await patchClashMode(mode); // 使用共享的刷新方法 refreshClashConfig(); } catch (error) { console.error("Failed to change mode:", error); } }); // 按钮样式 const buttonStyles = (mode: ClashMode) => ({ cursor: "pointer", px: 2, py: 1.2, display: "flex", alignItems: "center", justifyContent: "center", gap: 1, bgcolor: mode === currentModeKey ? "primary.main" : "background.paper", color: mode === currentModeKey ? "primary.contrastText" : "text.primary", borderRadius: 1.5, transition: "all 0.2s ease-in-out", position: "relative", overflow: "visible", "&:hover": { transform: "translateY(-1px)", boxShadow: 1, }, "&:active": { transform: "translateY(1px)", }, "&::after": mode === currentModeKey ? { content: '""', position: "absolute", bottom: -16, left: "50%", width: 2, height: 16, bgcolor: "primary.main", transform: "translateX(-50%)", } : {}, }); // 描述样式 const descriptionStyles = { width: "95%", textAlign: "center", color: "text.secondary", p: 0.8, borderRadius: 1, borderColor: "primary.main", borderWidth: 1, borderStyle: "solid", backgroundColor: "background.paper", wordBreak: "break-word", hyphens: "auto", }; return ( {/* 模式选择按钮组 */} {modeList.map((mode) => ( onChangeMode(mode)} sx={buttonStyles(mode)} > {modeIcons[mode]} {t(MODE_META[mode].label)} ))} {/* 说明文本区域 */} {modeDescription} ); };