diff --git a/UPDATELOG.md b/UPDATELOG.md index 878befbe..37f49cd2 100644 --- a/UPDATELOG.md +++ b/UPDATELOG.md @@ -13,7 +13,6 @@ - 增强型流量监控,支持更详细的数据分析 - 新增流量图表多种显示模式 - 新增强制刷新配置和节点缓存功能 -- 添加首页卡片移动功能(测试阶段) - 首页流量统计支持查看刻度线详情 ### 🚀 性能优化 diff --git a/src/pages/home.tsx b/src/pages/home.tsx index e28151b2..1d9fbaa8 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -4,6 +4,7 @@ import { Button, IconButton, useTheme, + keyframes, Dialog, DialogTitle, DialogContent, @@ -28,7 +29,7 @@ import { useNavigate } from "react-router-dom"; import { ProxyTunCard } from "@/components/home/proxy-tun-card"; import { ClashModeCard } from "@/components/home/clash-mode-card"; import { EnhancedTrafficStats } from "@/components/home/enhanced-traffic-stats"; -import { useState, useEffect } from "react"; +import { useState } from "react"; import { HomeProfileCard } from "@/components/home/home-profile-card"; import { EnhancedCard } from "@/components/home/enhanced-card"; import { CurrentProxyCard } from "@/components/home/current-proxy-card"; @@ -39,14 +40,19 @@ import { useLockFn } from "ahooks"; import { entry_lightweight_mode, openWebUrl } from "@/services/cmds"; import { TestCard } from "@/components/home/test-card"; import { IpInfoCard } from "@/components/home/ip-info-card"; -import { - DragDropContext, - Droppable, - Draggable, - DropResult, - DroppableProvided, - DraggableProvided, -} from "react-beautiful-dnd"; + +// 定义旋转动画 +const round = keyframes` + from { transform: rotate(0deg); } + to { transform: rotate(360deg); } +`; + +// 辅助函数解析URL和过期时间 +function parseUrl(url?: string) { + if (!url) return "-"; + if (url.startsWith("http")) return new URL(url).host; + return "local"; +} // 定义首页卡片设置接口 interface HomeCardsSettings { @@ -63,13 +69,6 @@ interface HomeCardsSettings { [key: string]: boolean; } -// 卡片配置接口,包含排序信息 -interface CardConfig { - id: string; - size: number; - enabled: boolean; -} - // 首页设置对话框组件接口 interface HomeSettingsDialogProps { open: boolean; @@ -78,35 +77,6 @@ interface HomeSettingsDialogProps { onSave: (cards: HomeCardsSettings) => void; } -// 确保对象符合HomeCardsSettings类型的辅助函数 -const ensureHomeCardsSettings = (obj: any): HomeCardsSettings => { - const defaultSettings: HomeCardsSettings = { - profile: true, - proxy: true, - network: true, - mode: true, - traffic: true, - info: false, - clashinfo: true, - systeminfo: true, - test: true, - ip: true, - }; - - if (!obj || typeof obj !== "object") return defaultSettings; - - // 合并默认值和传入对象,确保所有必要属性都存在 - return Object.keys(defaultSettings).reduce((acc, key) => { - return { - ...acc, - [key]: - typeof obj[key] === "boolean" - ? obj[key] - : defaultSettings[key as keyof HomeCardsSettings], - }; - }, {} as HomeCardsSettings); -}; - // 首页设置对话框组件 const HomeSettingsDialog = ({ open, @@ -118,16 +88,15 @@ const HomeSettingsDialog = ({ const [cards, setCards] = useState(homeCards); const { patchVerge } = useVerge(); - const handleToggle = (key: keyof HomeCardsSettings) => { - setCards((prev) => ({ + const handleToggle = (key: string) => { + setCards((prev: HomeCardsSettings) => ({ ...prev, [key]: !prev[key], })); }; const handleSave = async () => { - // 明确类型为HomeCardsSettings - await patchVerge({ home_cards: cards as HomeCardsSettings }); + await patchVerge({ home_cards: cards }); onSave(cards); onClose(); }; @@ -140,7 +109,7 @@ const HomeSettingsDialog = ({ handleToggle("profile")} /> } @@ -149,7 +118,7 @@ const HomeSettingsDialog = ({ handleToggle("proxy")} /> } @@ -158,7 +127,7 @@ const HomeSettingsDialog = ({ handleToggle("network")} /> } @@ -167,7 +136,7 @@ const HomeSettingsDialog = ({ handleToggle("mode")} /> } @@ -176,7 +145,7 @@ const HomeSettingsDialog = ({ handleToggle("traffic")} /> } @@ -185,7 +154,7 @@ const HomeSettingsDialog = ({ handleToggle("test")} /> } @@ -194,7 +163,7 @@ const HomeSettingsDialog = ({ handleToggle("ip")} /> } @@ -203,7 +172,7 @@ const HomeSettingsDialog = ({ handleToggle("clashinfo")} /> } @@ -212,7 +181,7 @@ const HomeSettingsDialog = ({ handleToggle("systeminfo")} /> } @@ -232,74 +201,41 @@ const HomeSettingsDialog = ({ export const HomePage = () => { const { t } = useTranslation(); - const { verge, patchVerge } = useVerge(); + const { verge } = useVerge(); const { current, mutateProfiles } = useProfiles(); + const navigate = useNavigate(); const theme = useTheme(); // 设置弹窗的状态 const [settingsOpen, setSettingsOpen] = useState(false); - // 卡片显示状态 - 确保类型正确 + // 卡片显示状态 const [homeCards, setHomeCards] = useState( - ensureHomeCardsSettings(verge?.home_cards), + (verge?.home_cards as HomeCardsSettings) || { + profile: true, + proxy: true, + network: true, + mode: true, + traffic: true, + clashinfo: true, + systeminfo: true, + test: true, + ip: true, + }, ); - // 卡片排序配置 - 默认为初始顺序 - const [cardOrder, setCardOrder] = useState( - // 明确断言类型 - (verge?.card_order as string[]) || [ - "profile", - "proxy", - "network", - "mode", - "traffic", - "test", - "ip", - "clashinfo", - "systeminfo", - ], - ); + // 导航到订阅页面 + const goToProfiles = () => { + navigate("/profile"); + }; - // 当homeCards变化时,确保cardOrder中只包含启用的卡片 - useEffect(() => { - const enabledCards = Object.entries(homeCards) - .filter(([_, enabled]) => enabled) - .map(([id]) => id); + // 导航到代理页面 + const goToProxies = () => { + navigate("/"); + }; - // 过滤掉已禁用的卡片 - const filteredOrder = cardOrder.filter((id) => enabledCards.includes(id)); - - // 添加新启用但不在排序中的卡片 - const newCards = enabledCards.filter((id) => !filteredOrder.includes(id)); - - setCardOrder([...filteredOrder, ...newCards]); - }, [homeCards]); - - // 保存卡片排序 - const saveCardOrder = useLockFn(async (order: string[]) => { - await patchVerge({ card_order: order } as any); - setCardOrder(order); - }); - - // 处理拖拽结束 - const handleDragEnd = (result: DropResult) => { - const { destination, source, draggableId } = result; - - // 拖拽到无效位置或原位置,不做处理 - if ( - !destination || - (destination.droppableId === source.droppableId && - destination.index === source.index) - ) { - return; - } - - // 重新排序 - const newOrder = Array.from(cardOrder); - newOrder.splice(source.index, 1); - newOrder.splice(destination.index, 0, draggableId); - - // 保存新顺序 - saveCardOrder(newOrder); + // 导航到设置页面 + const goToSettings = () => { + navigate("/settings"); }; // 文档链接函数 @@ -307,12 +243,12 @@ export const HomePage = () => { return openWebUrl("https://clash-verge-rev.github.io/index.html"); }); - // 卡片设置弹窗 + // 新增:打开设置弹窗 const openSettings = () => { setSettingsOpen(true); }; - // 保存勾选设置 + // 新增:保存设置时用requestIdleCallback/setTimeout const handleSaveSettings = (newCards: HomeCardsSettings) => { if (window.requestIdleCallback) { window.requestIdleCallback(() => setHomeCards(newCards)); @@ -321,68 +257,6 @@ export const HomePage = () => { } }; - // 获取卡片配置信息 - const getCardConfig = (id: string): CardConfig => { - const configs: Record = { - profile: { id: "profile", size: 6, enabled: homeCards.profile }, - proxy: { id: "proxy", size: 6, enabled: homeCards.proxy }, - network: { id: "network", size: 6, enabled: homeCards.network }, - mode: { id: "mode", size: 6, enabled: homeCards.mode }, - traffic: { id: "traffic", size: 12, enabled: homeCards.traffic }, - test: { id: "test", size: 6, enabled: homeCards.test }, - ip: { id: "ip", size: 6, enabled: homeCards.ip }, - clashinfo: { id: "clashinfo", size: 6, enabled: homeCards.clashinfo }, - systeminfo: { id: "systeminfo", size: 6, enabled: homeCards.systeminfo }, - }; - - if (!configs[id]) { - console.warn(`检测到未知卡片ID: ${id},使用默认配置`); - return { id, size: 6, enabled: false }; - } - - return configs[id]; - }; - - // 渲染卡片内容 - const renderCardContent = (id: string) => { - switch (id) { - case "profile": - return ( - - ); - case "proxy": - return ; - case "network": - return ; - case "mode": - return ; - case "traffic": - return ( - } - iconColor="secondary" - > - - - ); - case "test": - return ; - case "ip": - return ; - case "clashinfo": - return ; - case "systeminfo": - return ; - default: - console.warn(`无法渲染未知卡片: ${id}`); - return null; - } - }; - return ( { } > - {/* 拖拽上下文 */} - - - {(provided: DroppableProvided) => ( - - {cardOrder - .filter((id) => { - const config = getCardConfig(id); - return homeCards[id] && config.enabled; - }) - .map((id, index) => { - const config = getCardConfig(id); - if (!config) return null; + + {/* 订阅和当前节点部分 */} + {homeCards.profile && ( + + + + )} - return ( - - {(provided: DraggableProvided) => ( - - {renderCardContent(id)} - - )} - - ); - })} - {provided.placeholder} - - )} - - + {homeCards.proxy && ( + + + + )} + + {/* 代理和网络设置区域 */} + {homeCards.network && ( + + + + )} + + {homeCards.mode && ( + + + + )} + + {/* 增强的流量统计区域 */} + {homeCards.traffic && ( + + } + iconColor="secondary" + > + + + + )} + {/* 测试网站部分 */} + {homeCards.test && ( + + + + )} + {/* IP信息卡片 */} + {homeCards.ip && ( + + + + )} + {/* Clash信息 */} + {homeCards.clashinfo && ( + + + + )} + {/* 系统信息 */} + {homeCards.systeminfo && ( + + + + )} + {/* 首页设置弹窗 */}