增加浅色主题

This commit is contained in:
dushixiang committed 2025-12-20 17:33:27 +08:00
1 parent a710e1823c
commit 7e3eb7a7b3
31 files changed
+935 -786

No files matched your search

+321
View File
@@ -9,6 +9,7 @@
"version": "0.0.0",
"dependencies": {
"@ant-design/pro-components": "^2.8.10",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.14",
"@tanstack/react-query": "^5.90.6",
@@ -1605,6 +1606,32 @@
}
}
},
"node_modules/@radix-ui/react-collection": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-slot": "1.2.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
@@ -1635,6 +1662,21 @@
}
}
},
"node_modules/@radix-ui/react-direction": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-dismissable-layer": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
@@ -1662,6 +1704,75 @@
}
}
},
"node_modules/@radix-ui/react-dropdown-menu": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz",
"integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-menu": "2.1.16",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-use-controllable-state": "1.2.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz",
"integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-focus-scope": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
"integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
"license": "MIT",
"dependencies": {
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-use-callback-ref": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-id": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
@@ -1680,6 +1791,46 @@
}
}
},
"node_modules/@radix-ui/react-menu": {
"version": "2.1.16",
"resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz",
"integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-collection": "1.1.7",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-direction": "1.1.1",
"@radix-ui/react-dismissable-layer": "1.1.11",
"@radix-ui/react-focus-guards": "1.1.3",
"@radix-ui/react-focus-scope": "1.1.7",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-popper": "1.2.8",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-presence": "1.1.5",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-roving-focus": "1.1.11",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-use-callback-ref": "1.1.1",
"aria-hidden": "^1.2.4",
"react-remove-scroll": "^2.6.3"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-popper": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
@@ -1783,6 +1934,37 @@
}
}
},
"node_modules/@radix-ui/react-roving-focus": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
"integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.3",
"@radix-ui/react-collection": "1.1.7",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-direction": "1.1.1",
"@radix-ui/react-id": "1.1.1",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-use-callback-ref": "1.1.1",
"@radix-ui/react-use-controllable-state": "1.2.2"
},
"peerDependencies": {
"@types/react": "*",
"@types/react-dom": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
},
"@types/react-dom": {
"optional": true
}
}
},
"node_modules/@radix-ui/react-slot": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
@@ -3366,6 +3548,18 @@
"dev": true,
"license": "Python-2.0"
},
"node_modules/aria-hidden": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
"integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
"license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -3797,6 +3991,12 @@
"node": ">=8"
}
},
"node_modules/detect-node-es": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz",
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
"license": "MIT"
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -4301,6 +4501,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-nonce": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz",
"integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
@@ -5917,6 +6126,53 @@
"node": ">=0.10.0"
}
},
"node_modules/react-remove-scroll": {
"version": "2.7.2",
"resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz",
"integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==",
"license": "MIT",
"dependencies": {
"react-remove-scroll-bar": "^2.3.7",
"react-style-singleton": "^2.2.3",
"tslib": "^2.1.0",
"use-callback-ref": "^1.3.3",
"use-sidecar": "^1.1.3"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-remove-scroll-bar": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz",
"integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==",
"license": "MIT",
"dependencies": {
"react-style-singleton": "^2.2.2",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/react-router": {
"version": "7.9.4",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.9.4.tgz",
@@ -5955,6 +6211,28 @@
"react-dom": ">=18"
}
},
"node_modules/react-style-singleton": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz",
"integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==",
"license": "MIT",
"dependencies": {
"get-nonce": "^1.0.0",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
@@ -6562,6 +6840,49 @@
"punycode": "^2.1.0"
}
},
"node_modules/use-callback-ref": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz",
"integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==",
"license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sidecar": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz",
"integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==",
"license": "MIT",
"dependencies": {
"detect-node-es": "^1.1.0",
"tslib": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"@types/react": "*",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/use-sync-external-store": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
+1
View File
@@ -11,6 +11,7 @@
},
"dependencies": {
"@ant-design/pro-components": "^2.8.10",
"@radix-ui/react-dropdown-menu": "^2.1.16",
"@radix-ui/react-tooltip": "^1.2.8",
"@tailwindcss/vite": "^4.1.14",
"@tanstack/react-query": "^5.90.6",
+8 -8
View File
@@ -12,21 +12,21 @@ const CyberCard = ({className, children, animation, hover}: Props) => {
return (
<div
className={cn(
"group bg-[#0f1016]/80 backdrop-blur-md border border-cyan-500/20 shadow-[0_0_15px_rgba(6,182,212,0.05)] transition-all duration-300 cursor-pointer overflow-hidden relative",
hover && "hover:border-cyan-500/50 hover:shadow-[0_0_25px_rgba(6,182,212,0.15)] hover:bg-[#0f1016]/90"
"group bg-white/90 dark:bg-[#0f1016]/80 backdrop-blur-md border border-slate-200 dark:border-cyan-500/20 shadow-sm dark:shadow-[0_0_15px_rgba(6,182,212,0.05)] transition-all duration-300 cursor-pointer overflow-hidden relative rounded-xl dark:rounded-none",
hover && "hover:border-slate-300 dark:hover:border-cyan-500/50 hover:bg-white dark:hover:bg-[#0f1016]/90"
)}>
{/* 装饰性边框 */}
{/* 装饰性边框 - 仅在暗色模式下显示 */}
<div
className="absolute top-0 left-0 w-2 h-2 border-t-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
className="hidden dark:block absolute top-0 left-0 w-2 h-2 border-t-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute top-0 right-0 w-2 h-2 border-t-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
className="hidden dark:block absolute top-0 right-0 w-2 h-2 border-t-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute bottom-0 left-0 w-2 h-2 border-b-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
className="hidden dark:block absolute bottom-0 left-0 w-2 h-2 border-b-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute bottom-0 right-0 w-2 h-2 border-b-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
className="hidden dark:block absolute bottom-0 right-0 w-2 h-2 border-b-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
{animation &&
<div
className="absolute inset-0 bg-gradient-to-b from-transparent via-cyan-500/5 to-transparent -translate-y-full group-hover:translate-y-full transition-transform duration-1000 ease-in-out pointer-events-none"/>
className="hidden dark:block absolute inset-0 bg-gradient-to-b from-transparent via-cyan-500/5 to-transparent -translate-y-full group-hover:translate-y-full transition-transform duration-1000 ease-in-out pointer-events-none"/>
}
<div className={cn("relative z-10 p-4", className)}>
+118 -53
View File
@@ -1,5 +1,6 @@
import {useEffect, useState} from 'react';
import {Activity, LogIn, Menu, ServerIcon, Settings, X, Sun, Moon, Monitor} from 'lucide-react';
import {Activity, LogIn, Menu, ServerIcon, Settings, X, Sun, Moon, Monitor, ChevronDown} from 'lucide-react';
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import {getCurrentUser} from '../api/auth';
import {Link, useLocation} from "react-router-dom";
import {useTheme, type Theme} from '../contexts/ThemeContext';
@@ -11,27 +12,6 @@ const PublicHeader = () => {
const {theme, setTheme} = useTheme();
let location = useLocation();
// 主题切换函数
const cycleTheme = () => {
const themes: Theme[] = ['light', 'dark', 'auto'];
const currentIndex = themes.indexOf(theme);
const nextIndex = (currentIndex + 1) % themes.length;
setTheme(themes[nextIndex]);
};
// 获取当前主题图标
const getThemeIcon = () => {
switch (theme) {
case 'light':
return Sun;
case 'dark':
return Moon;
case 'auto':
return Monitor;
}
};
const ThemeIcon = getThemeIcon();
useEffect(() => {
// 检查本地是否有 token
@@ -75,11 +55,19 @@ const PublicHeader = () => {
let leftName = '';
let rightName = '';
if (systemName) {
const mid = Math.floor(systemName.length / 2);
leftName = systemName.substring(0, mid);
rightName = systemName.substring(mid);
// 优先在空格处分割
const spaceIndex = systemName.indexOf(' ');
if (spaceIndex > 0) {
leftName = systemName.substring(0, spaceIndex);
rightName = systemName.substring(spaceIndex); // 保留空格
} else {
// 如果没有空格,从中间分割
const mid = Math.floor(systemName.length / 2);
leftName = systemName.substring(0, mid);
rightName = systemName.substring(mid);
}
}
return (
@@ -120,16 +108,16 @@ const PublicHeader = () => {
<button
className={`
relative group flex items-center gap-2 py-2 text-xs font-bold tracking-widest transition-colors cursor-pointer font-mono uppercase
${activeTab === tab.id ? 'text-cyan-500' : 'text-slate-500 dark:text-slate-400 hover:text-cyan-500 dark:hover:text-cyan-200'}
${activeTab === tab.id ? 'text-blue-600 dark:text-cyan-500' : 'text-slate-500 dark:text-slate-400 hover:text-blue-500 dark:hover:text-cyan-200'}
`}
>
<tab.icon
className={`w-4 h-4 ${activeTab === tab.id ? 'text-cyan-500' : 'text-slate-400 dark:text-slate-600 group-hover:text-cyan-500 dark:group-hover:text-cyan-200'}`}/>
className={`w-4 h-4 ${activeTab === tab.id ? 'text-blue-600 dark:text-cyan-500' : 'text-slate-400 dark:text-slate-600 group-hover:text-blue-500 dark:group-hover:text-cyan-200'}`}/>
{tab.label}
{/* Active Indicator (Underline Glow) */}
<span
className={`absolute -bottom-1 left-0 w-full h-[2px] bg-cyan-500 shadow-[0_0_10px_rgba(34,211,238,0.8)] transition-transform duration-300 origin-left ${activeTab === tab.id ? 'scale-x-100' : 'scale-x-0'}`}></span>
className={`absolute -bottom-1 left-0 w-full h-[2px] bg-blue-600 dark:bg-cyan-500 shadow-[0_0_10px_rgba(37,99,235,0.8)] dark:shadow-[0_0_10px_rgba(34,211,238,0.8)] transition-transform duration-300 origin-left ${activeTab === tab.id ? 'scale-x-100' : 'scale-x-0'}`}></span>
</button>
</Link>
))}
@@ -137,7 +125,7 @@ const PublicHeader = () => {
</div>
{/* Desktop Right Section */}
<div className="hidden md:flex items-center gap-6">
<div className="hidden md:flex items-center gap-2">
<div className="hidden lg:flex flex-col items-end">
<span className="text-xs font-mono text-slate-800 dark:text-cyan-500 font-bold">{currentTime.toLocaleTimeString()}</span>
<span
@@ -145,21 +133,60 @@ const PublicHeader = () => {
</div>
<div className="h-6 w-[1px] bg-slate-300 dark:bg-cyan-900/50 hidden lg:block"></div>
{/* 主题切换按钮 - Desktop */}
<button
onClick={cycleTheme}
className="flex items-center gap-2 px-3 py-2 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded transition-all text-xs font-bold tracking-wider uppercase group"
title={`当前主题: ${theme === 'light' ? '亮色' : theme === 'dark' ? '暗色' : '自动'}`}
>
<ThemeIcon className="w-3 h-3 group-hover:rotate-12 transition-transform"/>
<span className="hidden xl:inline">{theme === 'light' ? '亮色' : theme === 'dark' ? '暗色' : '自动'}</span>
</button>
{/* 主题切换下拉框 - Desktop */}
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<button
className="flex items-center gap-2 px-3 py-2 cursor-pointer rounded transition-all text-xs font-bold tracking-wider uppercase"
>
{theme === 'light' && <Sun className="w-3 h-3"/>}
{theme === 'dark' && <Moon className="w-3 h-3"/>}
{theme === 'auto' && <Monitor className="w-3 h-3"/>}
<span className="hidden xl:inline">
{theme === 'light' ? '浅色主题' : theme === 'dark' ? '暗黑主题' : '跟随系统'}
</span>
<ChevronDown className="w-3 h-3"/>
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="min-w-[140px] bg-white dark:bg-[#0f1016] border border-slate-200 dark:border-cyan-500/30 rounded-lg shadow-lg p-1 z-50"
sideOffset={5}
>
<DropdownMenu.Item
className="flex items-center gap-2 px-3 py-2 text-xs font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded cursor-pointer outline-none font-mono"
onSelect={() => setTheme('auto')}
>
<Monitor className="w-3 h-3"/>
<span>跟随系统</span>
{theme === 'auto' && <span className="ml-auto text-cyan-500">✓</span>}
</DropdownMenu.Item>
<DropdownMenu.Item
className="flex items-center gap-2 px-3 py-2 text-xs font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded cursor-pointer outline-none font-mono"
onSelect={() => setTheme('light')}
>
<Sun className="w-3 h-3"/>
<span>浅色主题</span>
{theme === 'light' && <span className="ml-auto text-cyan-500">✓</span>}
</DropdownMenu.Item>
<DropdownMenu.Item
className="flex items-center gap-2 px-3 py-2 text-xs font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded cursor-pointer outline-none font-mono"
onSelect={() => setTheme('dark')}
>
<Moon className="w-3 h-3"/>
<span>暗黑主题</span>
{theme === 'dark' && <span className="ml-auto text-cyan-500">✓</span>}
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
{/* 登录/管理后台按钮 - Desktop */}
{isLoggedIn ? (
<a
href="/admin"
className="flex items-center gap-2 px-4 py-2 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded transition-all text-xs font-bold tracking-wider uppercase group"
className="flex items-center gap-2 px-4 py-2 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 text-cyan-500 rounded transition-all text-xs font-bold tracking-wider uppercase group"
target="_blank"
>
<Settings className="w-3 h-3 group-hover:rotate-90 transition-transform"/>
@@ -168,7 +195,7 @@ const PublicHeader = () => {
) : (
<a
href="/login"
className="flex items-center gap-2 px-4 py-2 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded transition-all text-xs font-bold tracking-wider uppercase group"
className="flex items-center gap-2 px-4 py-2 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 text-cyan-500 rounded transition-all text-xs font-bold tracking-wider uppercase group"
target="_blank"
>
<LogIn className="w-3 h-3"/>
@@ -210,8 +237,8 @@ const PublicHeader = () => {
className={`
flex items-center gap-3 p-4 rounded-lg border transition-all
${activeTab === tab.id
? 'bg-cyan-500/20 border-cyan-500/80 text-cyan-500'
: 'bg-cyan-500/5 border-slate-200 dark:border-cyan-500/30 text-slate-600 dark:text-slate-400 hover:bg-cyan-500/10 hover:border-cyan-500/50'
? 'bg-blue-50 dark:bg-cyan-500/20 border-blue-500 dark:border-cyan-500/80 text-blue-600 dark:text-cyan-500'
: 'bg-slate-50/50 dark:bg-cyan-500/5 border-slate-200 dark:border-cyan-500/30 text-slate-600 dark:text-slate-400 hover:bg-blue-50 dark:hover:bg-cyan-500/10 hover:border-blue-300 dark:hover:border-cyan-500/50'
}
`}
>
@@ -223,21 +250,59 @@ const PublicHeader = () => {
{/* Divider */}
<div className="h-[1px] bg-slate-200 dark:bg-cyan-900/50 my-2"></div>
{/* Mobile Theme Toggle Button */}
<button
onClick={cycleTheme}
className="flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase"
>
<ThemeIcon className="w-5 h-5"/>
<span>主题: {theme === 'light' ? '亮色' : theme === 'dark' ? '暗色' : '自动'}</span>
</button>
{/* Mobile Theme Toggle DropdownMenu */}
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<button
className="w-full flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase focus:outline-none focus:ring-2 focus:ring-cyan-500/50"
>
{theme === 'light' && <Sun className="w-5 h-5"/>}
{theme === 'dark' && <Moon className="w-5 h-5"/>}
{theme === 'auto' && <Monitor className="w-5 h-5"/>}
<span>主题: {theme === 'light' ? '浅色' : theme === 'dark' ? '暗黑' : '跟随'}</span>
<ChevronDown className="w-5 h-5"/>
</button>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="w-[calc(100vw-2rem)] max-w-md bg-white dark:bg-[#0f1016] border border-slate-200 dark:border-cyan-500/30 rounded-lg shadow-lg p-2 z-50"
sideOffset={5}
>
<DropdownMenu.Item
className="flex items-center gap-3 px-4 py-3 text-sm font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded-lg cursor-pointer outline-none"
onSelect={() => setTheme('auto')}
>
<Monitor className="w-5 h-5"/>
<span>跟随系统</span>
{theme === 'auto' && <span className="ml-auto text-cyan-500 text-lg">✓</span>}
</DropdownMenu.Item>
<DropdownMenu.Item
className="flex items-center gap-3 px-4 py-3 text-sm font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded-lg cursor-pointer outline-none"
onSelect={() => setTheme('light')}
>
<Sun className="w-5 h-5"/>
<span>浅色主题</span>
{theme === 'light' && <span className="ml-auto text-cyan-500 text-lg">✓</span>}
</DropdownMenu.Item>
<DropdownMenu.Item
className="flex items-center gap-3 px-4 py-3 text-sm font-medium text-slate-700 dark:text-cyan-300 hover:bg-slate-100 dark:hover:bg-cyan-500/20 rounded-lg cursor-pointer outline-none"
onSelect={() => setTheme('dark')}
>
<Moon className="w-5 h-5"/>
<span>暗黑主题</span>
{theme === 'dark' && <span className="ml-auto text-cyan-500 text-lg">✓</span>}
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
{/* Mobile Login/Admin Button */}
{isLoggedIn ? (
<a
href="/admin"
target="_blank"
className="flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase"
className="flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase"
>
<Settings className="w-5 h-5"/>
<span>管理后台</span>
@@ -246,7 +311,7 @@ const PublicHeader = () => {
<a
href="/login"
target="_blank"
className="flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 border border-cyan-200 dark:border-cyan-500/50 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase"
className="flex items-center justify-center gap-3 p-4 bg-cyan-50 dark:bg-cyan-500/10 hover:bg-cyan-100 dark:hover:bg-cyan-500/20 text-cyan-500 rounded-lg transition-all font-bold tracking-wider uppercase"
>
<LogIn className="w-5 h-5"/>
<span>登录</span>
+151 -154
View File
@@ -1,8 +1,22 @@
import type {FC} from 'react';
import {Activity, AlertTriangle, ArrowDown, ArrowUp, Calendar, Clock, Cpu, HardDrive, MemoryStick, Network, Thermometer} from 'lucide-react';
import {
Activity,
AlertTriangle,
ArrowDown,
ArrowUp,
Calendar,
Clock,
Cpu,
HardDrive,
MemoryStick,
Network,
Thermometer
} from 'lucide-react';
import type {Agent, LatestMetrics} from '@/types';
import CompactResourceBar from '@/components/CompactResourceBar';
import {formatBytes, formatSpeed, formatUptime} from '@/utils/util';
import CyberCard from "@/components/CyberCard.tsx";
import {Link} from "react-router-dom";
interface AgentWithMetrics extends Agent {
metrics?: LatestMetrics;
@@ -10,7 +24,6 @@ interface AgentWithMetrics extends Agent {
interface ServerCardProps {
server: AgentWithMetrics;
onClick: (serverId: string) => void;
}
const calculateNetworkSpeed = (metrics?: LatestMetrics) => {
@@ -38,7 +51,7 @@ const getTemperatures = (metrics?: LatestMetrics) => {
return metrics.temperature.sort((a, b) => a.type.localeCompare(b.type));
};
const ServerCard: FC<ServerCardProps> = ({server, onClick}) => {
const ServerCard: FC<ServerCardProps> = ({server}) => {
const isOnline = server.status === 1;
const cpuUsage = server.metrics?.cpu?.usagePercent ?? 0;
const memoryUsage = server.metrics?.memory?.usagePercent ?? 0;
@@ -52,178 +65,162 @@ const ServerCard: FC<ServerCardProps> = ({server, onClick}) => {
const netConn = server.metrics?.networkConnection;
return (
<div
tabIndex={0}
onClick={() => onClick(server.id)}
onKeyDown={(event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
onClick(server.id);
}
}}
className="group bg-[#0f1016]/80 backdrop-blur-md border border-cyan-500/20 shadow-[0_0_15px_rgba(6,182,212,0.05)] hover:border-cyan-500/50 hover:shadow-[0_0_25px_rgba(6,182,212,0.15)] hover:bg-[#0f1016]/90 transition-all duration-300 cursor-pointer overflow-hidden relative"
>
{/* 装饰性边框 */}
<div
className="absolute top-0 left-0 w-2 h-2 border-t-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute top-0 right-0 w-2 h-2 border-t-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute bottom-0 left-0 w-2 h-2 border-b-2 border-l-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute bottom-0 right-0 w-2 h-2 border-b-2 border-r-2 border-cyan-500/30 group-hover:border-cyan-400 transition-colors"></div>
<div
className="absolute inset-0 bg-gradient-to-b from-transparent via-cyan-500/5 to-transparent -translate-y-full group-hover:translate-y-full transition-transform duration-1000 ease-in-out pointer-events-none"/>
<div className="relative z-10 p-5 space-y-2">
{/* 顶部:名称和状态 */}
<div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0">
<div className="font-bold text-cyan-100 font-mono text-base truncate">
{server.name || server.hostname}
<Link to={`/servers/${server.id}`}>
<CyberCard>
<div className="relative z-10 p-5 space-y-2">
{/* 顶部:名称和状态 */}
<div className="flex items-start justify-between gap-3">
<div className="flex-1 min-w-0">
<div className="font-bold text-slate-800 dark:text-cyan-100 font-mono text-base truncate">
{server.name || server.hostname}
</div>
<div
className="flex items-center gap-2 text-xs text-gray-600 dark:text-cyan-500 mt-1 font-mono uppercase">
<span>{server.os}</span>
<span className="w-px h-2 bg-gray-400 dark:bg-cyan-800"></span>
<span>{server.arch}</span>
</div>
</div>
<div className="flex items-center gap-2 text-xs text-cyan-500 mt-1 font-mono uppercase">
<span>{server.os}</span>
<span className="w-px h-2 bg-cyan-800"></span>
<span>{server.arch}</span>
</div>
</div>
{server.tags && server.tags.length > 0 && (
<div className="flex gap-1 flex-wrap justify-end">
{server.tags.slice(0, 2).map(tag => (
<span
key={tag}
className="px-1.5 py-0.5 bg-cyan-900/40 text-cyan-500 border border-cyan-700/50 text-xs font-mono rounded-sm whitespace-nowrap"
>
{server.tags && server.tags.length > 0 && (
<div className="flex gap-1 flex-wrap justify-end">
{server.tags.slice(0, 2).map(tag => (
<span
key={tag}
className="px-1.5 py-0.5 bg-gray-100 dark:bg-cyan-900/40 text-gray-700 dark:text-cyan-500 border border-gray-300 dark:border-cyan-700/50 text-xs font-mono rounded-sm whitespace-nowrap"
>
#{tag}
</span>
))}
{server.tags.length > 2 && (
<span
className="px-1.5 py-0.5 bg-cyan-900/40 text-cyan-500 border border-cyan-700/50 text-xs font-mono rounded-sm">
))}
{server.tags.length > 2 && (
<span
className="px-1.5 py-0.5 bg-gray-100 dark:bg-cyan-900/40 text-gray-700 dark:text-cyan-500 border border-gray-300 dark:border-cyan-700/50 text-xs font-mono rounded-sm">
+{server.tags.length - 2}
</span>
)}
</div>
)}
</div>
{isOnline && server.metrics?.host && (
<div className="flex items-center gap-2 text-xs font-mono mt-1.5">
<div className="flex items-center gap-1 text-cyan-500">
<Clock className="w-3 h-3"/>
<span>{formatUptime(server.metrics.host.uptime)}</span>
</div>
<span className="w-px h-2 bg-cyan-800"></span>
<div className="flex items-center gap-1 text-cyan-500">
<Activity className="w-3 h-3"/>
<span>{server.metrics.host.procs} 进程</span>
</div>
</div>
)}
{/* 资源使用情况 */}
{isOnline ? (
<div className="space-y-1">
<CompactResourceBar
value={cpuUsage}
label="CPU"
icon={Cpu}
subtext={server.metrics?.cpu ? `${server.metrics.cpu.physicalCores}核` : null}
color="bg-blue-500"
/>
<CompactResourceBar
value={memoryUsage}
label="RAM"
icon={MemoryStick}
subtext={`${formatBytes(memoryUsed, 0)}/${formatBytes(memoryTotal, 0)}`}
color="bg-purple-500"
/>
<CompactResourceBar
value={diskUsage}
label="DSK"
icon={HardDrive}
subtext={`${formatBytes(diskUsed, 0)}/${formatBytes(diskTotal, 0)}`}
color="bg-emerald-500"
/>
{temperatures.length > 0 && (
<div className="flex items-center gap-2 mt-1 text-xs font-mono pt-1 flex-wrap">
<Thermometer className="w-3 h-3 text-orange-400"/>
{temperatures.map((temp, index) => (
<span key={index} className="flex items-center gap-1">
<span className="text-orange-400">{temp.temperature?.toFixed(1)}°C</span>
<span className="text-cyan-500">{temp.type}</span>
{index < temperatures.length - 1 && <span className="text-cyan-900">|</span>}
</span>
))}
)}
</div>
)}
</div>
) : (
<div className="text-xs text-rose-500 font-mono flex items-center gap-2 py-2">
<AlertTriangle className="w-4 h-4"/>
<span>离线</span>
</div>
)}
{/* 网络和流量 */}
<div className="pt-2 border-t border-cyan-900/30 space-y-2">
<div className="flex items-center justify-between">
<div className="flex gap-3 text-xs font-mono">
<span className="flex items-center gap-1 text-emerald-400/80">
{isOnline && server.metrics?.host && (
<div className="flex items-center gap-2 text-xs font-mono mt-1.5">
<div className="flex items-center gap-1 text-gray-500 dark:text-cyan-500">
<Clock className="w-3 h-3"/>
<span>{formatUptime(server.metrics.host.uptime)}</span>
</div>
<span className="w-px h-2 bg-gray-400 dark:bg-cyan-800"></span>
<div className="flex items-center gap-1 text-gray-500 dark:text-cyan-500">
<Activity className="w-3 h-3"/>
<span>{server.metrics.host.procs} 进程</span>
</div>
</div>
)}
{/* 资源使用情况 */}
{isOnline ? (
<div className="space-y-1">
<CompactResourceBar
value={cpuUsage}
label="CPU"
icon={Cpu}
subtext={server.metrics?.cpu ? `${server.metrics.cpu.physicalCores}核` : null}
color="bg-blue-500"
/>
<CompactResourceBar
value={memoryUsage}
label="RAM"
icon={MemoryStick}
subtext={`${formatBytes(memoryUsed, 0)}/${formatBytes(memoryTotal, 0)}`}
color="bg-purple-500"
/>
<CompactResourceBar
value={diskUsage}
label="DSK"
icon={HardDrive}
subtext={`${formatBytes(diskUsed, 0)}/${formatBytes(diskTotal, 0)}`}
color="bg-emerald-500"
/>
{temperatures.length > 0 && (
<div className="flex items-center gap-2 mt-1 text-xs font-mono pt-1 flex-wrap">
<Thermometer className="w-3 h-3 text-orange-400"/>
{temperatures.map((temp, index) => (
<span key={index} className="flex items-center gap-1">
<span className="text-orange-400">{temp.temperature?.toFixed(1)}°C</span>
<span className="text-gray-500 dark:text-cyan-500">{temp.type}</span>
{index < temperatures.length - 1 &&
<span className="text-gray-400 dark:text-cyan-900">|</span>}
</span>
))}
</div>
)}
</div>
) : (
<div className="text-xs text-rose-500 font-mono flex items-center gap-2 py-2">
<AlertTriangle className="w-4 h-4"/>
<span>离线</span>
</div>
)}
{/* 网络和流量 */}
<div className="pt-2 border-t border-slate-200 dark:border-cyan-900/30 space-y-2">
<div className="flex items-center justify-between">
<div className="flex gap-3 text-xs font-mono">
<span className="flex items-center gap-1 text-emerald-600 dark:text-emerald-400/80">
<ArrowDown className="w-3 h-3"/>
{formatSpeed(download)}
</span>
<span className="flex items-center gap-1 text-blue-400/80">
<span className="flex items-center gap-1 text-blue-600 dark:text-blue-400/80">
<ArrowUp className="w-3 h-3"/>
{formatSpeed(upload)}
{formatSpeed(upload)}
</span>
</div>
{server.expireTime > 0 && (
<div
className="text-xs font-mono text-cyan-600 dark:text-cyan-500 flex items-center gap-1">
<Calendar className="w-3 h-3"/>
{new Date(server.expireTime).toLocaleDateString('zh-CN')}
</div>
)}
</div>
{server.expireTime > 0 && (
<div className="text-xs font-mono text-cyan-500 flex items-center gap-1">
<Calendar className="w-3 h-3"/>
{new Date(server.expireTime).toLocaleDateString('zh-CN')}
{isOnline && netConn && (
<div className="flex gap-3 text-xs font-mono">
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-emerald-600 dark:text-emerald-400"/>
<span
className="text-emerald-600 dark:text-emerald-400">{netConn.established || 0}</span>
<span className="text-gray-600 dark:text-cyan-500">已建立</span>
</span>
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-blue-600 dark:text-blue-400"/>
<span className="text-blue-600 dark:text-blue-400">{netConn.listen || 0}</span>
<span className="text-gray-600 dark:text-cyan-500">监听</span>
</span>
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-amber-600 dark:text-amber-400"/>
<span className="text-amber-600 dark:text-amber-400">{netConn.closeWait || 0}</span>
<span className="text-gray-600 dark:text-cyan-500">等待关闭</span>
</span>
</div>
)}
</div>
{isOnline && netConn && (
<div className="flex gap-3 text-xs font-mono">
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-emerald-400"/>
<span className="text-emerald-400">{netConn.established || 0}</span>
<span className="text-cyan-500">已建立</span>
</span>
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-blue-400"/>
<span className="text-blue-400">{netConn.listen || 0}</span>
<span className="text-cyan-500">监听</span>
</span>
<span className="flex items-center gap-1">
<Network className="w-3 h-3 text-amber-400"/>
<span className="text-amber-400">{netConn.closeWait || 0}</span>
<span className="text-cyan-500">等待关闭</span>
</span>
{/* 流量限制 */}
{server.trafficLimit > 0 && (
<div className="pt-2 border-t border-slate-200 dark:border-cyan-900/30">
<div className="flex justify-between text-xs text-gray-600 dark:text-cyan-500 mb-1">
<span>流量使用</span>
<span>{Math.round((server.trafficUsed || 0) / server.trafficLimit * 100)}%</span>
</div>
<div className="h-1.5 bg-slate-200 dark:bg-cyan-900/50 rounded-full overflow-hidden">
<div
className="h-full bg-gray-500 dark:bg-cyan-400 transition-all"
style={{width: `${((server.trafficUsed || 0) / server.trafficLimit) * 100}%`}}
/>
</div>
</div>
)}
</div>
{/* 流量限制 */}
{server.trafficLimit > 0 && (
<div className="pt-2 border-t border-cyan-900/30">
<div className="flex justify-between text-xs text-cyan-500 mb-1">
<span>流量使用</span>
<span>{Math.round((server.trafficUsed || 0) / server.trafficLimit * 100)}%</span>
</div>
<div className="h-1.5 bg-cyan-900/50 rounded-full overflow-hidden">
<div
className="h-full bg-cyan-400 transition-all"
style={{width: `${((server.trafficUsed || 0) / server.trafficLimit) * 100}%`}}
/>
</div>
</div>
)}
</div>
</div>
</CyberCard>
</Link>
);
};
+3 -3
View File
@@ -9,10 +9,10 @@ const LittleStatCard = ({
}) => (
<div
key={label}
className="rounded-xl bg-black/40 border border-cyan-900/50 p-4 text-left hover:border-cyan-700/50 transition"
className="rounded-xl bg-slate-50 dark:bg-black/40 border border-slate-200 dark:border-cyan-900/50 p-4 text-left hover:border-slate-300 dark:hover:border-cyan-700/50 transition"
>
<p className="text-sm uppercase tracking-[0.3em] text-cyan-500 font-mono font-bold">{label}</p>
<p className="mt-2 text-base font-semibold text-cyan-100">{value}</p>
<p className="text-sm uppercase tracking-[0.3em] text-gray-700 dark:text-cyan-500 font-mono font-bold">{label}</p>
<p className="mt-2 text-base font-semibold text-slate-800 dark:text-cyan-100">{value}</p>
</div>
);
+19 -19
View File
@@ -18,7 +18,7 @@ interface AgentStatsTableProps {
export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProps) => {
if (monitorStats.length === 0) {
return (
<div className="text-center py-12 text-cyan-500">
<div className="text-center py-12 text-gray-600 dark:text-cyan-500">
<p className="text-sm font-mono">暂无探针数据</p>
</div>
);
@@ -27,42 +27,42 @@ export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProp
return (
<CyberCard className="p-6">
<div className="mb-6">
<h3 className="text-lg font-bold tracking-wide text-cyan-100 uppercase">探针监控详情</h3>
<p className="text-xs text-cyan-500 mt-1 font-mono">各探针的当前状态和统计数据</p>
<h3 className="text-lg font-bold tracking-wide text-slate-800 dark:text-cyan-100 uppercase">探针监控详情</h3>
<p className="text-xs text-gray-600 dark:text-cyan-500 mt-1 font-mono">各探针的当前状态和统计数据</p>
</div>
<div className="overflow-x-auto -mx-6 px-6">
<table className="min-w-full">
<thead>
<tr className="border-b border-cyan-900/50">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono">
<tr className="border-b border-slate-200 dark:border-cyan-900/50">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono">
探针名称
</th>
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono">
状态
</th>
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono">
响应时间
</th>
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono hidden lg:table-cell">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono hidden lg:table-cell">
最后检测
</th>
{monitorType === 'https' && (
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono hidden xl:table-cell">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono hidden xl:table-cell">
证书信息
</th>
)}
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widesttext-cyan-500 font-mono hidden xl:table-cell">
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-widest text-gray-600 dark:text-cyan-500 font-mono hidden xl:table-cell">
错误信息
</th>
</tr>
</thead>
<tbody className="divide-y divide-cyan-900/30">
<tbody className="divide-y divide-slate-200 dark:divide-cyan-900/30">
{monitorStats.map((stat, index) => {
const color = AGENT_COLORS[index % AGENT_COLORS.length];
return (
<tr key={stat.agentId}
className="hover:bg-cyan-950/20 transition-colors">
className="hover:bg-slate-100 dark:hover:bg-cyan-950/20 transition-colors">
<td className="px-4 py-4">
<div className="flex items-center gap-3">
<span
@@ -70,8 +70,8 @@ export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProp
style={{backgroundColor: color}}
/>
<div className="flex items-center gap-2">
<MapPin className="h-3.5 w-3.5 text-cyan-500"/>
<span className="font-mono text-sm text-cyan-200">
<MapPin className="h-3.5 w-3.5 text-gray-600 dark:text-cyan-500"/>
<span className="font-mono text-sm text-slate-800 dark:text-cyan-200">
{stat.agentName || stat.agentId.substring(0, 8)}
</span>
</div>
@@ -82,13 +82,13 @@ export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProp
</td>
<td className="px-4 py-4">
<div className="flex items-center gap-2">
<Clock className="h-4 w-4 text-cyan-500"/>
<span className="text-sm font-semibold text-cyan-100 font-mono">
<Clock className="h-4 w-4 text-gray-600 dark:text-cyan-500"/>
<span className="text-sm font-semibold text-slate-800 dark:text-cyan-100 font-mono">
{formatTime(stat.responseTime)}
</span>
</div>
</td>
<td className="px-4 py-4 text-sm text-cyan-500 font-mono hidden lg:table-cell">
<td className="px-4 py-4 text-sm text-gray-600 dark:text-cyan-500 font-mono hidden lg:table-cell">
{formatDateTime(stat.checkedAt)}
</td>
{monitorType === 'https' && (
@@ -99,7 +99,7 @@ export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProp
daysLeft={stat.certDaysLeft}
/>
) : (
<span className="text-xs text-cyan-500">-</span>
<span className="text-xs text-gray-600 dark:text-cyan-500">-</span>
)}
</td>
)}
@@ -114,7 +114,7 @@ export const AgentStatsTable = ({monitorStats, monitorType}: AgentStatsTableProp
</span>
</div>
) : (
<span className="text-xs text-cyan-500">-</span>
<span className="text-xs text-gray-600 dark:text-cyan-500">-</span>
)}
</td>
</tr>
+10 -10
View File
@@ -78,14 +78,14 @@ const MonitorCard = ({monitor, displayMode}: {
<div className="flex justify-between items-start mb-4">
<div className="flex gap-3 flex-1 min-w-0">
<div
className="p-2.5 bg-cyan-950/30 border border-cyan-500/20 rounded-lg flex-shrink-0">
className="p-2.5 bg-gray-100 dark:bg-cyan-950/30 border border-slate-200 dark:border-cyan-500/20 rounded-lg flex-shrink-0">
<TypeIcon type={monitor.type}/>
</div>
<div className="flex-1 min-w-0">
<h3 className="font-bold text-sm text-cyan-100 tracking-wide truncate group-hover:text-cyan-500 transition-colors">
<h3 className="font-bold text-sm text-slate-800 dark:text-cyan-100 tracking-wide truncate group-hover:text-cyan-500 transition-colors">
{monitor.name}
</h3>
<div className="text-xs font-mono text-cyan-500/80 mb-0.5 tracking-wider truncate">
<div className="text-xs font-mono text-gray-600 dark:text-cyan-500/80 mb-0.5 tracking-wider truncate">
{monitor.target}
</div>
</div>
@@ -98,24 +98,24 @@ const MonitorCard = ({monitor, displayMode}: {
{/* 指标信息 */}
<div className="grid grid-cols-2 gap-4 mb-4">
<div>
<p className="text-xs text-cyan-500 mb-1 flex items-center gap-1">
<p className="text-xs text-gray-600 dark:text-cyan-500 mb-1 flex items-center gap-1">
{displayLabel}
{monitor.agentCount > 0 && (
<span
className="bg-slate-700 text-xs px-1.5 rounded-full text-cyan-300">
className="bg-slate-200 dark:bg-slate-700 text-xs px-1.5 rounded-full text-slate-700 dark:text-cyan-300">
{monitor.agentCount} 节点
</span>
)}
</p>
<div
className={`text-xl font-bold flex items-baseline gap-1 ${displayValue > 200 ? 'text-amber-400 drop-shadow-[0_0_8px_rgba(251,191,36,0.5)]' : 'text-white drop-shadow-[0_0_8px_rgba(34,211,238,0.5)]'}`}>
{displayValue}<span className="text-xs text-cyan-500 font-normal">ms</span>
className={`text-xl font-bold flex items-baseline gap-1 ${displayValue > 200 ? 'text-amber-600 dark:text-amber-400 drop-shadow-[0_0_8px_rgba(251,191,36,0.3)] dark:drop-shadow-[0_0_8px_rgba(251,191,36,0.5)]' : 'text-slate-800 dark:text-white drop-shadow-none dark:drop-shadow-[0_0_8px_rgba(34,211,238,0.5)]'}`}>
{displayValue}<span className="text-xs text-gray-600 dark:text-cyan-500 font-normal">ms</span>
</div>
</div>
<div>
{monitor.type === 'https' && monitor.certExpiryTime ? (
<>
<p className="text-xs text-cyan-500 mb-1">SSL 证书</p>
<p className="text-xs text-gray-600 dark:text-cyan-500 mb-1">SSL 证书</p>
<CertBadge
expiryTime={monitor.certExpiryTime}
daysLeft={monitor.certDaysLeft}
@@ -123,8 +123,8 @@ const MonitorCard = ({monitor, displayMode}: {
</>
) : (
<>
<p className="text-xs text-cyan-500 mb-1">上次检测</p>
<p className="text-sm font-medium text-cyan-300 font-mono">
<p className="text-xs text-gray-600 dark:text-cyan-500 mb-1">上次检测</p>
<p className="text-sm font-medium text-gray-700 dark:text-cyan-300 font-mono">
{formatDateTime(monitor.lastCheckTime)}
</p>
</>
+6 -6
View File
@@ -22,7 +22,7 @@ export const MonitorHero = ({monitor, onBack}: MonitorHeroProps) => {
<button
type="button"
onClick={onBack}
className="group inline-flex items-center gap-2 text-xs font-medium uppercase tracking-wider text-cyan-500 hover:text-cyan-500 transition font-mono"
className="group inline-flex items-center gap-2 text-xs font-medium uppercase tracking-wider text-gray-600 dark:text-cyan-500 hover:text-gray-800 dark:hover:text-cyan-400 transition font-mono"
>
<ArrowLeft className="h-4 w-4 transition-transform group-hover:-translate-x-1"/>
返回监控列表
@@ -31,15 +31,15 @@ export const MonitorHero = ({monitor, onBack}: MonitorHeroProps) => {
{/* 监控信息 */}
<div className="flex flex-col gap-6 lg:flex-row lg:items-start lg:justify-between">
<div className="flex items-start gap-4 flex-1 min-w-0">
<div className="p-3 bg-cyan-950/30 border border-cyan-500/20 rounded-lg flex-shrink-0">
<div className="p-3 bg-gray-100 dark:bg-cyan-950/30 border border-slate-200 dark:border-cyan-500/20 rounded-lg flex-shrink-0">
<TypeIcon type={monitor.type}/>
</div>
<div className="flex-1 min-w-0">
<div className="flex flex-wrap items-center gap-3 mb-2">
<h1 className="text-2xl sm:text-3xl font-bold truncate text-cyan-100 tracking-wide">{monitor.name}</h1>
<h1 className="text-2xl sm:text-3xl font-bold truncate text-slate-800 dark:text-cyan-100 tracking-wide">{monitor.name}</h1>
<StatusBadge status={monitor.status}/>
</div>
<p className="text-sm text-cyan-500/80 font-mono truncate">
<p className="text-sm text-gray-600 dark:text-cyan-500/80 font-mono truncate">
{monitor.showTargetPublic ? monitor.target : '******'}
</p>
</div>
@@ -68,8 +68,8 @@ export const MonitorHero = ({monitor, onBack}: MonitorHeroProps) => {
{/* 证书信息(如果是 HTTPS)*/}
{monitor.type === 'https' && monitor.certExpiryTime && (
<div className="flex items-center gap-2 pt-4 border-t border-cyan-900/50">
<span className="text-xstext-cyan-500 font-mono">SSL 证书:</span>
<div className="flex items-center gap-2 pt-4 border-t border-slate-200 dark:border-cyan-900/50">
<span className="text-xs text-gray-600 dark:text-cyan-500 font-mono">SSL 证书:</span>
<CertBadge
expiryTime={monitor.certExpiryTime}
daysLeft={monitor.certDaysLeft}
@@ -111,21 +111,20 @@ export const ResponseTimeChart = ({monitorId, monitorStats}: ResponseTimeChartPr
<CyberCard className={'p-6'}>
<div className="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-6">
<div>
<h3 className="text-lg font-bold tracking-wide text-cyan-100 uppercase">响应时间趋势</h3>
<p className="text-xs text-cyan-500 mt-1 font-mono">监控各探针的响应时间变化</p>
<h3 className="text-lg font-bold tracking-wide text-slate-800 dark:text-cyan-100 uppercase">响应时间趋势</h3>
<p className="text-xs text-gray-600 dark:text-cyan-500 mt-1 font-mono">监控各探针的响应时间变化</p>
</div>
<div className="flex flex-col sm:flex-row flex-wrap items-start sm:items-center gap-3">
<TimeRangeSelector
value={timeRange}
onChange={setTimeRange}
options={MONITOR_TIME_RANGE_OPTIONS}
variant={'dark'}
/>
{availableAgents.length > 0 && (
<select
value={selectedAgent}
onChange={(e) => setSelectedAgent(e.target.value)}
className="rounded-lg border border-cyan-900/50 bg-black/40 px-3 py-2 text-xs font-medium text-cyan-300 hover:border-cyan-500/50 focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20 transition-colors font-mono"
className="rounded-lg border border-slate-200 dark:border-cyan-900/50 bg-white dark:bg-black/40 px-3 py-2 text-xs font-medium text-gray-700 dark:text-cyan-300 hover:border-slate-300 dark:hover:border-cyan-500/50 focus:border-slate-400 dark:focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-slate-200 dark:focus:ring-cyan-500/20 transition-colors font-mono"
>
<option value="all">所有探针</option>
{availableAgents.map((agent) => (
@@ -158,7 +157,7 @@ export const ResponseTimeChart = ({monitorId, monitorStats}: ResponseTimeChartPr
</defs>
<CartesianGrid
strokeDasharray="3 3"
className="stroke-cyan-900/30"
className="stroke-slate-200 dark:stroke-cyan-900/30"
vertical={false}
/>
<XAxis
@@ -167,22 +166,22 @@ export const ResponseTimeChart = ({monitorId, monitorStats}: ResponseTimeChartPr
scale="time"
domain={['dataMin', 'dataMax']}
tickFormatter={(value) => formatChartTime(Number(value), timeRange)}
className="text-xs text-cyan-500 font-mono"
stroke="#164e63"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
stroke="currentColor"
tickLine={false}
axisLine={false}
angle={-15}
textAnchor="end"
/>
<YAxis
className="text-xs text-cyan-500 font-mono"
stroke="#164e63"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
stroke="currentColor"
tickLine={false}
axisLine={false}
tickFormatter={(value) => `${value}ms`}
/>
<Tooltip
content={<CustomTooltip variant={'dark'} unit={'ms'}/>}
content={<CustomTooltip unit={'ms'}/>}
wrapperStyle={{zIndex: 9999}}
/>
{!isMobile && (
@@ -217,7 +216,6 @@ export const ResponseTimeChart = ({monitorId, monitorStats}: ResponseTimeChartPr
</div>
) : (
<ChartPlaceholder
variant={'dark'}
subtitle="正在收集数据,请稍后查看历史趋势"
heightClass="h-80"
/>
+2 -2
View File
@@ -8,8 +8,8 @@ export const InfoGrid = ({items}: InfoGridProps) => (
<dl className="grid grid-cols-1 gap-4 text-sm sm:grid-cols-2">
{items.map((item) => (
<div key={item.label}>
<dt className="text-xs font-mono uppercase tracking-widest text-cyan-500">{item.label}</dt>
<dd className="mt-1 font-medium text-cyan-100">{item.value}</dd>
<dt className="text-xs font-mono uppercase tracking-widest text-gray-600 dark:text-cyan-500">{item.label}</dt>
<dd className="mt-1 font-medium text-slate-800 dark:text-cyan-100">{item.value}</dd>
</div>
))}
</dl>
@@ -17,35 +17,35 @@ export const NetworkConnectionSection = ({latestMetrics}: NetworkConnectionSecti
}
return (
<Card title="网络连接统计" description="TCP 连接各状态的实时统计数据" variant="dark">
<Card title="网络连接统计" description="TCP 连接各状态的实时统计数据">
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-6">
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">Total</div>
<div className="mt-1 text-lg font-semibold text-cyan-100">{latestMetrics.networkConnection.total}</div>
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">Total</div>
<div className="mt-1 text-lg font-semibold text-slate-800 dark:text-cyan-100">{latestMetrics.networkConnection.total}</div>
</div>
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">ESTABLISHED</div>
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">ESTABLISHED</div>
<div
className="mt-1 text-lg font-semibold text-emerald-400">{latestMetrics.networkConnection.established}</div>
className="mt-1 text-lg font-semibold text-emerald-600 dark:text-emerald-400">{latestMetrics.networkConnection.established}</div>
</div>
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">TIME_WAIT</div>
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">TIME_WAIT</div>
<div
className="mt-1 text-lg font-semibold text-amber-400">{latestMetrics.networkConnection.timeWait}</div>
className="mt-1 text-lg font-semibold text-amber-600 dark:text-amber-400">{latestMetrics.networkConnection.timeWait}</div>
</div>
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">LISTEN</div>
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">LISTEN</div>
<div
className="mt-1 text-lg font-semibold text-blue-400">{latestMetrics.networkConnection.listen}</div>
className="mt-1 text-lg font-semibold text-blue-600 dark:text-blue-400">{latestMetrics.networkConnection.listen}</div>
</div>
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">CLOSE_WAIT</div>
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">CLOSE_WAIT</div>
<div
className="mt-1 text-lg font-semibold text-rose-400">{latestMetrics.networkConnection.closeWait}</div>
className="mt-1 text-lg font-semibold text-rose-600 dark:text-rose-400">{latestMetrics.networkConnection.closeWait}</div>
</div>
<div className="text-center">
<div className="text-xs text-cyan-500 font-mono uppercase tracking-wider">OTHER</div>
<div className="mt-1 text-lg font-semibold text-cyan-500">
<div className="text-xs text-gray-600 dark:text-cyan-500 font-mono uppercase tracking-wider">OTHER</div>
<div className="mt-1 text-lg font-semibold text-gray-700 dark:text-cyan-500">
{latestMetrics.networkConnection.synSent +
latestMetrics.networkConnection.synRecv +
latestMetrics.networkConnection.finWait1 +
+4 -4
View File
@@ -49,7 +49,7 @@ export const ServerHero = ({agent, latestMetrics, onBack}: ServerHeroProps) => {
<button
type="button"
onClick={onBack}
className="group inline-flex items-center gap-2 text-xs font-bold font-mono uppercase tracking-[0.3em] text-cyan-500 transition hover:text-cyan-500"
className="group inline-flex items-center gap-2 text-xs font-bold font-mono uppercase tracking-[0.3em] dark:text-cyan-500 transition dark:hover:text-cyan-500"
>
<ArrowLeft className="h-4 w-4 transition group-hover:-translate-x-0.5"/>
返回概览
@@ -57,10 +57,10 @@ export const ServerHero = ({agent, latestMetrics, onBack}: ServerHeroProps) => {
<div className="flex items-start gap-4">
<div>
<div className="flex flex-wrap items-center gap-3">
<h1 className="text-3xl font-bold text-cyan-100">{displayName}</h1>
<h1 className="text-3xl font-bold dark:text-cyan-100">{displayName}</h1>
<StatusBadge status={agent.status === 1 ? 'up' : 'down'}/>
</div>
<p className="mt-2 text-sm text-cyan-500 font-mono">
<p className="mt-2 text-sm dark:text-cyan-500 font-mono">
{[agent.hostname, agent.ip].filter(Boolean).join(' · ') || '-'}
</p>
</div>
@@ -74,7 +74,7 @@ export const ServerHero = ({agent, latestMetrics, onBack}: ServerHeroProps) => {
</div>
</div>
<div
className="flex flex-wrap items-center gap-3 text-xs text-cyan-500 font-mono pt-4 border-t border-cyan-900/30">
className="flex flex-wrap items-center gap-3 text-xs dark:text-cyan-500 font-mono pt-4 border-t border-cyan-900/30">
<span>探针 ID:{agent.id}</span>
<span className="hidden h-1 w-1 rounded-full bg-cyan-900 sm:inline-block"/>
<span>版本:{agent.version || '-'}</span>
+5 -5
View File
@@ -47,23 +47,23 @@ export const SnapshotGrid = ({cards}: SnapshotGridProps) => (
return (
<div
key={card.key}
className="rounded-xl border border-cyan-900/50 bg-black/40 p-4 transition hover:-translate-y-0.5 hover:border-cyan-700/50"
className="rounded-xl border border-slate-200 dark:border-cyan-900/50 bg-slate-50 dark:bg-black/40 p-4 transition hover:-translate-y-0.5 hover:border-slate-300 dark:hover:border-cyan-700/50"
>
<div className="mb-3 flex items-start justify-between">
<div className="flex items-center gap-2">
<span className={cn("flex h-9 w-9 items-center justify-center rounded-lg bg-cyan-500/10", theme.icon)}>
<span className={cn("flex h-9 w-9 items-center justify-center rounded-lg bg-gray-200 dark:bg-cyan-500/10", theme.icon)}>
<card.icon className="h-4 w-4"/>
</span>
<p className="text-xs font-bold font-mono uppercase tracking-wider text-cyan-300">{card.title}</p>
<p className="text-xs font-bold font-mono uppercase tracking-wider text-gray-700 dark:text-cyan-300">{card.title}</p>
</div>
<span className={cn("text-xl font-bold", theme.highlight)}>{card.usagePercent}</span>
</div>
<div className="space-y-2">
{card.metrics.map((metric) => (
<div key={metric.label} className="flex items-center justify-between text-xs">
<span className="text-cyan-500 font-mono text-xs uppercase tracking-wider">{metric.label}</span>
<span className="text-gray-600 dark:text-cyan-500 font-mono text-xs uppercase tracking-wider">{metric.label}</span>
<span
className="ml-2 text-right font-medium text-cyan-200">{metric.value}</span>
className="ml-2 text-right font-medium text-slate-700 dark:text-cyan-200">{metric.value}</span>
</div>
))}
</div>
@@ -12,7 +12,7 @@ export const SnapshotSection = ({cards}: SnapshotSectionProps) => {
return (
<CyberCard className="p-6 space-y-4">
<div>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-cyan-500">资源快照</h3>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-gray-600 dark:text-cyan-500">资源快照</h3>
</div>
<SnapshotGrid cards={cards}/>
</CyberCard>
@@ -157,15 +157,15 @@ export const SystemInfoSection = ({agent, latestMetrics}: SystemInfoSectionProps
<div className="space-y-6">
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<CyberCard className={'p-6'}>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-cyan-500">运行环境</h3>
<p className="mt-1 text-xs text-cyan-500">来自最近一次探针上报的硬件与系统信息</p>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-gray-700 dark:text-cyan-500">运行环境</h3>
<p className="mt-1 text-xs text-gray-600 dark:text-cyan-500">来自最近一次探针上报的硬件与系统信息</p>
<div className="mt-4">
<InfoGrid items={environmentInfo}/>
</div>
</CyberCard>
<CyberCard className={'p-6'}>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-cyan-500">运行状态</h3>
<p className="mt-1 text-xs text-cyan-500">关键时间与网络指标,帮助快速判断主机健康状况</p>
<h3 className="text-sm font-bold font-mono uppercase tracking-widest text-gray-700 dark:text-cyan-500">运行状态</h3>
<p className="mt-1 text-xs text-gray-600 dark:text-cyan-500">关键时间与网络指标,帮助快速判断主机健康状况</p>
<div className="mt-4">
<InfoGrid items={statusInfo}/>
</div>
@@ -17,18 +17,18 @@ export const TemperatureMonitorSection = ({latestMetrics}: TemperatureMonitorSec
}
return (
<Card title="温度监控" description="系统各部件温度传感器数据" variant="dark">
<Card title="温度监控" description="系统各部件温度传感器数据">
<div className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
{latestMetrics.temperature.sort((a, b) => a.sensorKey.localeCompare(b.sensorKey)).map((temp) => (
<div
key={temp.sensorKey}
className="rounded-xl border border-cyan-900/50 bg-black/30 p-4 backdrop-blur-sm hover:border-cyan-700/50 transition"
className="rounded-xl border border-slate-200 dark:border-cyan-900/50 bg-slate-50 dark:bg-black/30 p-4 backdrop-blur-sm hover:border-slate-300 dark:hover:border-cyan-700/50 transition"
>
<div className="flex items-center gap-2 mb-2">
<Thermometer className="h-4 w-4 text-cyan-500"/>
<p className="text-xs font-bold font-mono uppercase tracking-wider text-cyan-500 truncate">{temp.type}</p>
<Thermometer className="h-4 w-4 text-gray-600 dark:text-cyan-500"/>
<p className="text-xs font-bold font-mono uppercase tracking-wider text-gray-700 dark:text-cyan-500 truncate">{temp.type}</p>
</div>
<p className="text-2xl font-bold text-orange-400">{temp.temperature.toFixed(1)}°C</p>
<p className="text-2xl font-bold text-orange-600 dark:text-orange-400">{temp.temperature.toFixed(1)}°C</p>
</div>
))}
</div>
@@ -16,8 +16,8 @@ export const ChartContainer = ({title, icon: Icon, children, action}: ChartConta
return (
<section>
<div className="mb-3 flex items-center justify-between">
<h3 className="flex items-center gap-2 text-xs font-bold font-mono uppercase tracking-widest text-cyan-500">
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-cyan-500/10 text-cyan-500">
<h3 className="flex items-center gap-2 text-xs font-bold font-mono uppercase tracking-widest text-gray-700 dark:text-cyan-500">
<span className="flex h-8 w-8 items-center justify-center rounded-lg bg-gray-200 dark:bg-cyan-500/10 text-gray-700 dark:text-cyan-500">
<Icon className="h-4 w-4"/>
</span>
{title}
@@ -37,7 +37,7 @@ export const CpuChart = ({agentId, timeRange}: CpuChartProps) => {
if (isLoading) {
return (
<ChartContainer title="CPU 使用率" icon={Cpu}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -53,7 +53,7 @@ export const CpuChart = ({agentId, timeRange}: CpuChartProps) => {
<stop offset="95%" stopColor="#2563eb" stopOpacity={0}/>
</linearGradient>
</defs>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -63,15 +63,15 @@ export const CpuChart = ({agentId, timeRange}: CpuChartProps) => {
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
/>
<YAxis
domain={[0, 100]}
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value}%`}
/>
<Tooltip content={<CustomTooltip unit="%" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit="%"/>}/>
<Area
type="monotone"
dataKey="usage"
@@ -84,7 +84,7 @@ export const CpuChart = ({agentId, timeRange}: CpuChartProps) => {
</AreaChart>
</ResponsiveContainer>
) : (
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
)}
</ChartContainer>
);
@@ -55,7 +55,7 @@ export const DiskIOChart = ({agentId, timeRange}: DiskIOChartProps) => {
if (isLoading) {
return (
<ChartContainer title="磁盘 I/O (MB/s)" icon={HardDrive}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -75,7 +75,7 @@ export const DiskIOChart = ({agentId, timeRange}: DiskIOChartProps) => {
<stop offset="95%" stopColor="#6FD598" stopOpacity={0}/>
</linearGradient>
</defs>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -85,15 +85,15 @@ export const DiskIOChart = ({agentId, timeRange}: DiskIOChartProps) => {
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
height={45}
/>
<YAxis
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value} MB`}
/>
<Tooltip content={<CustomTooltip unit=" MB" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit=" MB"/>}/>
<Legend/>
<Area
type="monotone"
@@ -116,7 +116,7 @@ export const DiskIOChart = ({agentId, timeRange}: DiskIOChartProps) => {
</AreaChart>
</ResponsiveContainer>
) : (
<ChartPlaceholder subtitle="暂无磁盘 I/O 采集数据" variant="dark"/>
<ChartPlaceholder subtitle="暂无磁盘 I/O 采集数据"/>
)}
</ChartContainer>
);
@@ -56,7 +56,7 @@ export const GpuChart = ({agentId, timeRange}: GpuChartProps) => {
if (isLoading) {
return (
<ChartContainer title="GPU 使用率与温度" icon={Zap}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -70,7 +70,7 @@ export const GpuChart = ({agentId, timeRange}: GpuChartProps) => {
<ChartContainer title="GPU 使用率与温度" icon={Zap}>
<ResponsiveContainer width="100%" height={220}>
<LineChart data={chartData}>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -78,13 +78,13 @@ export const GpuChart = ({agentId, timeRange}: GpuChartProps) => {
domain={['dataMin', 'dataMax']}
tickFormatter={(value) => formatChartTime(Number(value), timeRange)}
stroke="currentColor"
className="stroke-cyan-600"
className="stroke-gray-400 dark:stroke-cyan-600"
style={{fontSize: '12px'}}
/>
<YAxis
yAxisId="left"
stroke="currentColor"
className="stroke-cyan-600"
className="stroke-gray-400 dark:stroke-cyan-600"
style={{fontSize: '12px'}}
tickFormatter={(value) => `${value}%`}
/>
@@ -92,11 +92,11 @@ export const GpuChart = ({agentId, timeRange}: GpuChartProps) => {
yAxisId="right"
orientation="right"
stroke="currentColor"
className="stroke-cyan-600"
className="stroke-gray-400 dark:stroke-cyan-600"
style={{fontSize: '12px'}}
tickFormatter={(value) => `${value}°C`}
/>
<Tooltip content={<CustomTooltip unit="" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit=""/>}/>
<Legend/>
<Line
yAxisId="left"
@@ -37,7 +37,7 @@ export const MemoryChart = ({agentId, timeRange}: MemoryChartProps) => {
if (isLoading) {
return (
<ChartContainer title="内存使用率" icon={MemoryStick}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -53,7 +53,7 @@ export const MemoryChart = ({agentId, timeRange}: MemoryChartProps) => {
<stop offset="95%" stopColor="#10b981" stopOpacity={0}/>
</linearGradient>
</defs>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -63,15 +63,15 @@ export const MemoryChart = ({agentId, timeRange}: MemoryChartProps) => {
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
/>
<YAxis
domain={[0, 100]}
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value}%`}
/>
<Tooltip content={<CustomTooltip unit="%" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit="%"/>}/>
<Area
type="monotone"
dataKey="usage"
@@ -84,7 +84,7 @@ export const MemoryChart = ({agentId, timeRange}: MemoryChartProps) => {
</AreaChart>
</ResponsiveContainer>
) : (
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
)}
</ChartContainer>
);
@@ -79,7 +79,7 @@ export const MonitorChart = ({agentId, timeRange}: MonitorChartProps) => {
if (isLoading) {
return (
<ChartContainer title="监控响应时间" icon={Activity}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -99,7 +99,7 @@ export const MonitorChart = ({agentId, timeRange}: MonitorChartProps) => {
</linearGradient>
))}
</defs>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -109,16 +109,16 @@ export const MonitorChart = ({agentId, timeRange}: MonitorChartProps) => {
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
height={45}
/>
<YAxis
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value}ms`}
/>
<Tooltip
content={<CustomTooltip unit="ms" variant="dark"/>}
content={<CustomTooltip unit="ms"/>}
wrapperStyle={{zIndex: 9999,}}
/>
{!isMobile && monitorKeys.length > 1 && (
@@ -145,7 +145,7 @@ export const MonitorChart = ({agentId, timeRange}: MonitorChartProps) => {
<MobileLegend items={legendItems} show={isMobile}/>
</>
) : (
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
)}
</ChartContainer>
);
@@ -73,7 +73,7 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
<select
value={selectedInterface}
onChange={(e) => setSelectedInterface(e.target.value)}
className="rounded-lg border border-cyan-900/50 bg-black/40 px-3 py-1.5 text-xs font-mono text-cyan-300 hover:border-cyan-700 focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20"
className="rounded-lg border border-slate-200 dark:border-cyan-900/50 bg-white dark:bg-black/40 px-3 py-1.5 text-xs font-mono text-gray-700 dark:text-cyan-300 hover:border-slate-300 dark:hover:border-cyan-700 focus:border-slate-400 dark:focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-slate-200 dark:focus:ring-cyan-500/20"
>
{availableInterfaces.map((iface) => (
<option key={iface} value={iface}>
@@ -87,7 +87,7 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
if (isLoading) {
return (
<ChartContainer title="网络流量(MB/s)" icon={Network} action={interfaceSelector}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -107,7 +107,7 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
<stop offset="95%" stopColor={INTERFACE_COLORS[0].download} stopOpacity={0}/>
</linearGradient>
</defs>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -117,15 +117,15 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
height={45}
/>
<YAxis
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value} MB`}
/>
<Tooltip content={<CustomTooltip unit=" MB/s" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit=" MB/s"/>}/>
<Legend/>
<Area
type="monotone"
@@ -148,7 +148,7 @@ export const NetworkChart = ({agentId, timeRange}: NetworkChartProps) => {
</AreaChart>
</ResponsiveContainer>
) : (
<ChartPlaceholder subtitle="稍后再次尝试刷新网络流量" variant="dark"/>
<ChartPlaceholder subtitle="稍后再次尝试刷新网络流量"/>
)}
</ChartContainer>
);
@@ -55,7 +55,7 @@ export const NetworkConnectionChart = ({agentId, timeRange}: NetworkConnectionCh
if (isLoading) {
return (
<ChartContainer title="网络连接统计" icon={Network}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -65,7 +65,7 @@ export const NetworkConnectionChart = ({agentId, timeRange}: NetworkConnectionCh
{chartData.length > 0 ? (
<ResponsiveContainer width="100%" height={250}>
<LineChart data={chartData}>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -75,14 +75,14 @@ export const NetworkConnectionChart = ({agentId, timeRange}: NetworkConnectionCh
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
height={45}
/>
<YAxis
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
/>
<Tooltip content={<CustomTooltip unit="" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit=""/>}/>
<Legend/>
<Line
type="monotone"
@@ -123,7 +123,7 @@ export const NetworkConnectionChart = ({agentId, timeRange}: NetworkConnectionCh
</LineChart>
</ResponsiveContainer>
) : (
<ChartPlaceholder subtitle="暂无网络连接统计数据" variant="dark"/>
<ChartPlaceholder subtitle="暂无网络连接统计数据"/>
)}
</ChartContainer>
);
@@ -75,7 +75,7 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
<select
value={selectedTempType}
onChange={(e) => setSelectedTempType(e.target.value)}
className="rounded-lg border border-cyan-900/50 bg-black/40 px-3 py-1.5 text-xs font-mono text-cyan-300 hover:border-cyan-700 focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-cyan-500/20"
className="rounded-lg border border-slate-200 dark:border-cyan-900/50 bg-white dark:bg-black/40 px-3 py-1.5 text-xs font-mono text-gray-700 dark:text-cyan-300 hover:border-slate-300 dark:hover:border-cyan-700 focus:border-slate-400 dark:focus:border-cyan-500 focus:outline-none focus:ring-2 focus:ring-slate-200 dark:focus:ring-cyan-500/20"
>
<option value="all">所有类型</option>
{temperatureTypes.map((type) => (
@@ -90,7 +90,7 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
if (isLoading) {
return (
<ChartContainer title="系统温度" icon={Thermometer} action={tempTypeSelector}>
<ChartPlaceholder variant="dark"/>
<ChartPlaceholder/>
</ChartContainer>
);
}
@@ -104,7 +104,7 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
<ChartContainer title="系统温度" icon={Thermometer} action={tempTypeSelector}>
<ResponsiveContainer width="100%" height={250}>
<LineChart data={chartData}>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-cyan-900/30"/>
<CartesianGrid stroke="currentColor" strokeDasharray="4 4" className="stroke-slate-200 dark:stroke-cyan-900/30"/>
<XAxis
dataKey="timestamp"
type="number"
@@ -114,15 +114,15 @@ export const TemperatureChart = ({agentId, timeRange}: TemperatureChartProps) =>
stroke="currentColor"
angle={-15}
textAnchor="end"
className="text-xs text-cyan-500 font-mono"
className="text-xs text-gray-600 dark:text-cyan-500 font-mono"
height={45}
/>
<YAxis
stroke="currentColor"
className="stroke-cyan-600 text-xs"
className="stroke-gray-400 dark:stroke-cyan-600 text-xs"
tickFormatter={(value) => `${value}°C`}
/>
<Tooltip content={<CustomTooltip unit="°C" variant="dark"/>}/>
<Tooltip content={<CustomTooltip unit="°C"/>}/>
<Legend/>
{/* 为选中的温度类型渲染线条 */}
{filteredTemperatureTypes.map((type, index) => {
+3 -3
View File
@@ -38,15 +38,15 @@ const MonitorDetail = () => {
});
if (isLoading) {
return <LoadingSpinner variant="dark"/>;
return <LoadingSpinner/>;
}
if (!monitorDetail) {
return <EmptyState variant="dark"/>;
return <EmptyState/>;
}
return (
<div className="bg-[#05050a] min-h-screen">
<div className="bg-[#f0f2f5] dark:bg-[#05050a] min-h-screen">
<div className="mx-auto flex max-w-7xl flex-col px-4 pb-10 pt-4 sm:pt-6 sm:px-6 lg:px-8">
{/* 头部区域 */}
<MonitorHero
+17 -17
View File
@@ -11,18 +11,18 @@ import MonitorCard from "@/components/monitor/MonitorCard.tsx";
const LoadingSpinner = () => (
<div className="flex min-h-[400px] w-full items-center justify-center">
<div className="flex flex-col items-center gap-3 text-cyan-500">
<Loader2 className="h-8 w-8 animate-spin text-cyan-500"/>
<div className="flex flex-col items-center gap-3 text-gray-600 dark:text-cyan-500">
<Loader2 className="h-8 w-8 animate-spin text-gray-600 dark:text-cyan-500"/>
<span className="text-sm font-mono">加载监控数据中...</span>
</div>
</div>
);
const EmptyState = () => (
<div className="flex min-h-[400px] flex-col items-center justify-center text-cyan-500">
<div className="flex min-h-[400px] flex-col items-center justify-center text-gray-600 dark:text-cyan-500">
<Shield className="mb-4 h-16 w-16 opacity-20"/>
<p className="text-lg font-medium font-mono">暂无监控数据</p>
<p className="mt-2 text-sm text-cyan-500">请先在管理后台添加监控任务</p>
<p className="mt-2 text-sm text-gray-600 dark:text-cyan-500">请先在管理后台添加监控任务</p>
</div>
);
@@ -133,7 +133,7 @@ const MonitorList = () => {
<div className="flex flex-wrap gap-4 items-center w-full md:w-auto">
{/* 状态过滤 */}
<div
className="flex gap-2 bg-black/40 p-1 rounded-lg border border-cyan-900/50">
className="flex gap-2 bg-slate-100 dark:bg-black/40 p-1 rounded-lg border border-slate-200 dark:border-cyan-900/50">
{(['all', 'up', 'down', 'unknown'] as const).map(f => {
const labels = {all: '全部', up: '正常', down: '异常', unknown: '未知'};
return (
@@ -143,8 +143,8 @@ const MonitorList = () => {
className={cn(
"px-4 py-1.5 rounded-md text-xs font-medium transition-all font-mono cursor-pointer",
filter === f
? 'bg-cyan-500/20 text-cyan-300 border border-cyan-500/30'
: 'text-cyan-500 hover:text-cyan-500'
? 'bg-gray-200 dark:bg-cyan-500/20 text-gray-800 dark:text-cyan-300 border border-gray-300 dark:border-cyan-500/30'
: 'text-gray-600 dark:text-cyan-500 hover:text-gray-800 dark:hover:text-cyan-400'
)}
>
{labels[f]}
@@ -154,15 +154,15 @@ const MonitorList = () => {
</div>
{/* 显示模式切换 */}
<div className="flex gap-1 bg-black/40 p-1 rounded-lg border border-cyan-900/50 items-center">
<span className="text-xs text-cyan-500 px-2 font-mono">卡片指标:</span>
<div className="flex gap-1 bg-slate-100 dark:bg-black/40 p-1 rounded-lg border border-slate-200 dark:border-cyan-900/50 items-center">
<span className="text-xs text-gray-600 dark:text-cyan-500 px-2 font-mono">卡片指标:</span>
<button
onClick={() => setDisplayMode('avg')}
className={cn(
"px-3 py-1.5 text-xs font-medium rounded transition-all flex items-center gap-1 font-mono cursor-pointer",
displayMode === 'avg'
? 'bg-cyan-500/20 text-cyan-300 border border-cyan-500/30'
: 'text-cyan-500 hover:text-cyan-500'
? 'bg-gray-200 dark:bg-cyan-500/20 text-gray-800 dark:text-cyan-300 border border-gray-300 dark:border-cyan-500/30'
: 'text-gray-600 dark:text-cyan-500 hover:text-gray-800 dark:hover:text-cyan-400'
)}
>
<BarChart3 className="w-3 h-3"/> 平均
@@ -172,8 +172,8 @@ const MonitorList = () => {
className={cn(
"px-3 py-1.5 text-xs font-medium rounded transition-all flex items-center gap-1 font-mono cursor-pointer",
displayMode === 'max'
? 'bg-cyan-500/20 text-cyan-300 border border-cyan-500/30'
: 'text-cyan-500 hover:text-cyan-500'
? 'bg-gray-200 dark:bg-cyan-500/20 text-gray-800 dark:text-cyan-300 border border-gray-300 dark:border-cyan-500/30'
: 'text-gray-600 dark:text-cyan-500 hover:text-gray-800 dark:hover:text-cyan-400'
)}
>
<Maximize2 className="w-3 h-3"/> 最差(Max)
@@ -184,15 +184,15 @@ const MonitorList = () => {
{/* 搜索框 */}
<div className="relative w-full md:w-64 group">
<div
className="absolute -inset-0.5 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-lg blur opacity-20 group-hover:opacity-40 transition duration-500"></div>
<div className="relative flex items-center bg-[#0a0b10] rounded-lg border border-cyan-900">
<Search className="w-4 h-4 ml-3 text-cyan-500"/>
className="hidden dark:block absolute -inset-0.5 bg-gradient-to-r from-cyan-500 to-blue-600 rounded-lg blur opacity-20 group-hover:opacity-40 transition duration-500"></div>
<div className="relative flex items-center bg-white dark:bg-[#0a0b10] rounded-lg border border-slate-200 dark:border-cyan-900">
<Search className="w-4 h-4 ml-3 text-gray-500 dark:text-cyan-500"/>
<input
type="text"
placeholder="搜索服务名称或地址..."
value={searchKeyword}
onChange={(e) => setSearchKeyword(e.target.value)}
className="w-full bg-transparent border-none text-xs text-cyan-100 p-2.5 focus:ring-0 placeholder-cyan-600 font-mono focus:outline-none"
className="w-full bg-transparent border-none text-xs text-gray-800 dark:text-cyan-100 p-2.5 focus:ring-0 placeholder-gray-400 dark:placeholder-cyan-600 font-mono focus:outline-none"
/>
</div>
</div>
+3 -5
View File
@@ -38,15 +38,15 @@ const ServerDetail = () => {
const latestMetrics = latestMetricsResponse?.data || null;
if (isLoading) {
return <LoadingSpinner variant="dark"/>;
return <LoadingSpinner/>;
}
if (!agent) {
return <EmptyState variant="dark"/>;
return <EmptyState/>;
}
return (
<div className="bg-[#05050a] min-h-screen">
<div className="bg-[#f0f2f5] dark:bg-[#05050a] min-h-screen">
<div className="mx-auto flex max-w-7xl flex-col px-4 pb-10 pt-4 sm:pt-6 sm:px-6 lg:px-8">
{/* 头部区域 */}
<ServerHero
@@ -64,13 +64,11 @@ const ServerDetail = () => {
<Card
title="历史趋势"
description="针对选定时间范围展示 CPU、内存与网络的变化趋势"
variant="dark"
action={
<TimeRangeSelector
value={timeRange}
onChange={setTimeRange}
options={SERVER_TIME_RANGE_OPTIONS}
variant="dark"
/>
}
>
-1
View File
@@ -449,7 +449,6 @@ const ServerList = () => {
<ServerCard
key={server.id}
server={server}
onClick={handleNavigate}
/>
))}
</div>
+181 -411
View File
@@ -257,7 +257,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz"
integrity sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==
"@babel/core@^7.28.4":
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.28.4":
version "7.28.4"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz"
integrity sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==
@@ -426,7 +426,7 @@
dependencies:
tslib "^2.0.0"
"@dnd-kit/core@^6.0.8":
"@dnd-kit/core@^6.0.6", "@dnd-kit/core@^6.0.7", "@dnd-kit/core@^6.0.8":
version "6.3.1"
resolved "https://registry.npmjs.org/@dnd-kit/core/-/core-6.3.1.tgz"
integrity sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ==
@@ -458,28 +458,6 @@
dependencies:
tslib "^2.0.0"
"@emnapi/core@^1.5.0", "@emnapi/core@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4"
integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==
dependencies:
"@emnapi/wasi-threads" "1.1.0"
tslib "^2.4.0"
"@emnapi/runtime@^1.5.0", "@emnapi/runtime@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791"
integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==
dependencies:
tslib "^2.4.0"
"@emnapi/wasi-threads@1.1.0", "@emnapi/wasi-threads@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf"
integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==
dependencies:
tslib "^2.4.0"
"@emotion/hash@^0.8.0":
version "0.8.0"
resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz"
@@ -490,136 +468,11 @@
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@esbuild/aix-ppc64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz#ee6b7163a13528e099ecf562b972f2bcebe0aa97"
integrity sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==
"@esbuild/android-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz#115fc76631e82dd06811bfaf2db0d4979c16e2cb"
integrity sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==
"@esbuild/android-arm@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.10.tgz#8d5811912da77f615398611e5bbc1333fe321aa9"
integrity sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==
"@esbuild/android-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.10.tgz#e3e96516b2d50d74105bb92594c473e30ddc16b1"
integrity sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==
"@esbuild/darwin-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz"
integrity sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==
"@esbuild/darwin-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz#99ae82347fbd336fc2d28ffd4f05694e6e5b723d"
integrity sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==
"@esbuild/freebsd-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz#0c6d5558a6322b0bdb17f7025c19bd7d2359437d"
integrity sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==
"@esbuild/freebsd-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz#8c35873fab8c0857a75300a3dcce4324ca0b9844"
integrity sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==
"@esbuild/linux-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz#3edc2f87b889a15b4cedaf65f498c2bed7b16b90"
integrity sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==
"@esbuild/linux-arm@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz#86501cfdfb3d110176d80c41b27ed4611471cde7"
integrity sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==
"@esbuild/linux-ia32@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz#e6589877876142537c6864680cd5d26a622b9d97"
integrity sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==
"@esbuild/linux-loong64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz#11119e18781f136d8083ea10eb6be73db7532de8"
integrity sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==
"@esbuild/linux-mips64el@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz#3052f5436b0c0c67a25658d5fc87f045e7def9e6"
integrity sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==
"@esbuild/linux-ppc64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz#2f098920ee5be2ce799f35e367b28709925a8744"
integrity sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==
"@esbuild/linux-riscv64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz#fa51d7fd0a22a62b51b4b94b405a3198cf7405dd"
integrity sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==
"@esbuild/linux-s390x@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz#a27642e36fc282748fdb38954bd3ef4f85791e8a"
integrity sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==
"@esbuild/linux-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz#9d9b09c0033d17529570ced6d813f98315dfe4e9"
integrity sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==
"@esbuild/netbsd-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz#25c09a659c97e8af19e3f2afd1c9190435802151"
integrity sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==
"@esbuild/netbsd-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz#7fa5f6ffc19be3a0f6f5fd32c90df3dc2506937a"
integrity sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==
"@esbuild/openbsd-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz#8faa6aa1afca0c6d024398321d6cb1c18e72a1c3"
integrity sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==
"@esbuild/openbsd-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz#a42979b016f29559a8453d32440d3c8cd420af5e"
integrity sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==
"@esbuild/openharmony-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz#fd87bfeadd7eeb3aa384bbba907459ffa3197cb1"
integrity sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==
"@esbuild/sunos-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz#3a18f590e36cb78ae7397976b760b2b8c74407f4"
integrity sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==
"@esbuild/win32-arm64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz#e71741a251e3fd971408827a529d2325551f530c"
integrity sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==
"@esbuild/win32-ia32@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz#c6f010b5d3b943d8901a0c87ea55f93b8b54bf94"
integrity sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==
"@esbuild/win32-x64@0.25.10":
version "0.25.10"
resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz#e4b3e255a1b4aea84f6e1d2ae0b73f826c3785bd"
integrity sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==
"@eslint-community/eslint-utils@^4.7.0", "@eslint-community/eslint-utils@^4.8.0":
version "4.9.0"
resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz"
@@ -670,7 +523,7 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@eslint/js@9.37.0", "@eslint/js@^9.36.0":
"@eslint/js@^9.36.0", "@eslint/js@9.37.0":
version "9.37.0"
resolved "https://registry.npmjs.org/@eslint/js/-/js-9.37.0.tgz"
integrity sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==
@@ -779,15 +632,6 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@napi-rs/wasm-runtime@^1.0.5":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz#c0180393d7862cff0d412e3e1a7c3bd5ea6d9b2f"
integrity sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==
dependencies:
"@emnapi/core" "^1.7.1"
"@emnapi/runtime" "^1.7.1"
"@tybys/wasm-util" "^0.10.1"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
@@ -796,7 +640,7 @@
"@nodelib/fs.stat" "2.0.5"
run-parallel "^1.1.9"
"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
version "2.0.5"
resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
@@ -821,6 +665,16 @@
dependencies:
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-collection@1.1.7":
version "1.1.7"
resolved "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz"
integrity sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==
dependencies:
"@radix-ui/react-compose-refs" "1.1.2"
"@radix-ui/react-context" "1.1.2"
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-slot" "1.2.3"
"@radix-ui/react-compose-refs@1.1.2":
version "1.1.2"
resolved "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz"
@@ -831,6 +685,11 @@
resolved "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz"
integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==
"@radix-ui/react-direction@1.1.1":
version "1.1.1"
resolved "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz"
integrity sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==
"@radix-ui/react-dismissable-layer@1.1.11":
version "1.1.11"
resolved "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz"
@@ -842,6 +701,33 @@
"@radix-ui/react-use-callback-ref" "1.1.1"
"@radix-ui/react-use-escape-keydown" "1.1.1"
"@radix-ui/react-dropdown-menu@^2.1.16":
version "2.1.16"
resolved "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz"
integrity sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==
dependencies:
"@radix-ui/primitive" "1.1.3"
"@radix-ui/react-compose-refs" "1.1.2"
"@radix-ui/react-context" "1.1.2"
"@radix-ui/react-id" "1.1.1"
"@radix-ui/react-menu" "2.1.16"
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-use-controllable-state" "1.2.2"
"@radix-ui/react-focus-guards@1.1.3":
version "1.1.3"
resolved "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz"
integrity sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==
"@radix-ui/react-focus-scope@1.1.7":
version "1.1.7"
resolved "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz"
integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==
dependencies:
"@radix-ui/react-compose-refs" "1.1.2"
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-use-callback-ref" "1.1.1"
"@radix-ui/react-id@1.1.1":
version "1.1.1"
resolved "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz"
@@ -849,6 +735,30 @@
dependencies:
"@radix-ui/react-use-layout-effect" "1.1.1"
"@radix-ui/react-menu@2.1.16":
version "2.1.16"
resolved "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz"
integrity sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==
dependencies:
"@radix-ui/primitive" "1.1.3"
"@radix-ui/react-collection" "1.1.7"
"@radix-ui/react-compose-refs" "1.1.2"
"@radix-ui/react-context" "1.1.2"
"@radix-ui/react-direction" "1.1.1"
"@radix-ui/react-dismissable-layer" "1.1.11"
"@radix-ui/react-focus-guards" "1.1.3"
"@radix-ui/react-focus-scope" "1.1.7"
"@radix-ui/react-id" "1.1.1"
"@radix-ui/react-popper" "1.2.8"
"@radix-ui/react-portal" "1.1.9"
"@radix-ui/react-presence" "1.1.5"
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-roving-focus" "1.1.11"
"@radix-ui/react-slot" "1.2.3"
"@radix-ui/react-use-callback-ref" "1.1.1"
aria-hidden "^1.2.4"
react-remove-scroll "^2.6.3"
"@radix-ui/react-popper@1.2.8":
version "1.2.8"
resolved "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz"
@@ -888,6 +798,21 @@
dependencies:
"@radix-ui/react-slot" "1.2.3"
"@radix-ui/react-roving-focus@1.1.11":
version "1.1.11"
resolved "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz"
integrity sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==
dependencies:
"@radix-ui/primitive" "1.1.3"
"@radix-ui/react-collection" "1.1.7"
"@radix-ui/react-compose-refs" "1.1.2"
"@radix-ui/react-context" "1.1.2"
"@radix-ui/react-direction" "1.1.1"
"@radix-ui/react-id" "1.1.1"
"@radix-ui/react-primitive" "2.1.3"
"@radix-ui/react-use-callback-ref" "1.1.1"
"@radix-ui/react-use-controllable-state" "1.2.2"
"@radix-ui/react-slot@1.2.3":
version "1.2.3"
resolved "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz"
@@ -1069,116 +994,11 @@
resolved "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.38.tgz"
integrity sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==
"@rollup/rollup-android-arm-eabi@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.4.tgz#59e7478d310f7e6a7c72453978f562483828112f"
integrity sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==
"@rollup/rollup-android-arm64@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.4.tgz#a825192a0b1b2f27a5c950c439e7e37a33c5d056"
integrity sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==
"@rollup/rollup-darwin-arm64@4.52.4":
version "4.52.4"
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.4.tgz"
integrity sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==
"@rollup/rollup-darwin-x64@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.4.tgz#43cc08bd05bf9f388f125e7210a544e62d368d90"
integrity sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==
"@rollup/rollup-freebsd-arm64@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.4.tgz#bc8e640e28abe52450baf3fc80d9b26d9bb6587d"
integrity sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==
"@rollup/rollup-freebsd-x64@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.4.tgz#e981a22e057cc8c65bb523019d344d3a66b15bbc"
integrity sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==
"@rollup/rollup-linux-arm-gnueabihf@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.4.tgz#4036b68904f392a20f3499d63b33e055b67eb274"
integrity sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==
"@rollup/rollup-linux-arm-musleabihf@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.4.tgz#d3b1b9589606e0ff916801c855b1ace9e733427a"
integrity sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==
"@rollup/rollup-linux-arm64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.4.tgz#cbf0943c477e3b96340136dd3448eaf144378cf2"
integrity sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==
"@rollup/rollup-linux-arm64-musl@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.4.tgz#837f5a428020d5dce1c3b4cc049876075402cf78"
integrity sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==
"@rollup/rollup-linux-loong64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.4.tgz#532c214ababb32ab4bc21b4054278b9a8979e516"
integrity sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==
"@rollup/rollup-linux-ppc64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.4.tgz#93900163b61b49cee666d10ee38257a8b1dd161a"
integrity sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==
"@rollup/rollup-linux-riscv64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.4.tgz#f0ffdcc7066ca04bc972370c74289f35c7a7dc42"
integrity sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==
"@rollup/rollup-linux-riscv64-musl@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.4.tgz#361695c39dbe96773509745d77a870a32a9f8e48"
integrity sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==
"@rollup/rollup-linux-s390x-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.4.tgz#09fc6cc2e266a2324e366486ae5d1bca48c43a6a"
integrity sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==
"@rollup/rollup-linux-x64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.4.tgz#aa9d5b307c08f05d3454225bb0a2b4cc87eeb2e1"
integrity sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==
"@rollup/rollup-linux-x64-musl@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.4.tgz#26949e5b4645502a61daba2f7a8416bd17cb5382"
integrity sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==
"@rollup/rollup-openharmony-arm64@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.4.tgz#ef493c072f9dac7e0edb6c72d63366846b6ffcd9"
integrity sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==
"@rollup/rollup-win32-arm64-msvc@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.4.tgz#56e1aaa6a630d2202ee7ec0adddd05cf384ffd44"
integrity sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==
"@rollup/rollup-win32-ia32-msvc@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.4.tgz#0a44bbf933a9651c7da2b8569fa448dec0de7480"
integrity sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==
"@rollup/rollup-win32-x64-gnu@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.4.tgz#730e12f0b60b234a7c02d5d3179ca3ec7972033d"
integrity sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==
"@rollup/rollup-win32-x64-msvc@4.52.4":
version "4.52.4"
resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.4.tgz#5b2dd648a960b8fa00d76f2cc4eea2f03daa80f4"
integrity sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==
"@standard-schema/spec@^1.0.0":
version "1.0.0"
resolved "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz"
@@ -1202,73 +1022,11 @@
source-map-js "^1.2.1"
tailwindcss "4.1.14"
"@tailwindcss/oxide-android-arm64@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz#8903678d75715d913b8f7c5f6fa0517af83b5111"
integrity sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==
"@tailwindcss/oxide-darwin-arm64@4.1.14":
version "4.1.14"
resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz"
integrity sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==
"@tailwindcss/oxide-darwin-x64@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz#ac1af82da01299143129fdf615f6fcc046b4094e"
integrity sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==
"@tailwindcss/oxide-freebsd-x64@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz#a955cedf9b020147d222f92490e9d331db9b5c36"
integrity sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==
"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz#5474bee4d377144107f3f0198a3c0225a46c02e6"
integrity sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==
"@tailwindcss/oxide-linux-arm64-gnu@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz#b06ca140083b353735414e32f7a8786f55ce2dd6"
integrity sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==
"@tailwindcss/oxide-linux-arm64-musl@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz#85f4cabea2a07609274d1f747bd098c5da2a7cd2"
integrity sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==
"@tailwindcss/oxide-linux-x64-gnu@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz#0d7fbf91763a2f6886044a050298489107d120bd"
integrity sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==
"@tailwindcss/oxide-linux-x64-musl@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz#93578713064ba4c16df517df01b3c546ecc9878d"
integrity sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==
"@tailwindcss/oxide-wasm32-wasi@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz#9e55999129a952a3dcc2196cc9cc55248cc1b1fe"
integrity sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==
dependencies:
"@emnapi/core" "^1.5.0"
"@emnapi/runtime" "^1.5.0"
"@emnapi/wasi-threads" "^1.1.0"
"@napi-rs/wasm-runtime" "^1.0.5"
"@tybys/wasm-util" "^0.10.1"
tslib "^2.4.0"
"@tailwindcss/oxide-win32-arm64-msvc@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz#097c00bfc60cd84943a9cb5e853b25fa25525c77"
integrity sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==
"@tailwindcss/oxide-win32-x64-msvc@4.1.14":
version "4.1.14"
resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz#eaa49fa930ce16b23478d3b58c079a40ac0b6622"
integrity sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==
"@tailwindcss/oxide@4.1.14":
version "4.1.14"
resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz"
@@ -1311,13 +1069,6 @@
dependencies:
"@tanstack/query-core" "5.90.6"
"@tybys/wasm-util@^0.10.1":
version "0.10.1"
resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414"
integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==
dependencies:
tslib "^2.4.0"
"@types/babel__core@^7.20.5":
version "7.20.5"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz"
@@ -1402,7 +1153,7 @@
resolved "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz"
integrity sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==
"@types/estree@1.0.8", "@types/estree@^1.0.6":
"@types/estree@^1.0.6", "@types/estree@1.0.8":
version "1.0.8"
resolved "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz"
integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==
@@ -1412,7 +1163,7 @@
resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
"@types/node@^24.6.0":
"@types/node@^20.19.0 || >=22.12.0", "@types/node@^24.6.0":
version "24.7.1"
resolved "https://registry.npmjs.org/@types/node/-/node-24.7.1.tgz"
integrity sha512-CmyhGZanP88uuC5GpWU9q+fI61j2SkhO3UGMUdfYRE6Bcy0ccyzn1Rqj9YAB/ZY4kOXmNf0ocah5GtphmLMP6Q==
@@ -1424,12 +1175,12 @@
resolved "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz"
integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==
"@types/react-dom@^19.1.9":
"@types/react-dom@*", "@types/react-dom@^19.1.9":
version "19.2.1"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.1.tgz"
integrity sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==
"@types/react@^19.1.16":
"@types/react@*", "@types/react@^18.2.25 || ^19", "@types/react@^19.1.16", "@types/react@^19.2.0":
version "19.2.2"
resolved "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz"
integrity sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==
@@ -1461,7 +1212,7 @@
natural-compare "^1.4.0"
ts-api-utils "^2.1.0"
"@typescript-eslint/parser@8.46.0":
"@typescript-eslint/parser@^8.46.0", "@typescript-eslint/parser@8.46.0":
version "8.46.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.0.tgz"
integrity sha512-n1H6IcDhmmUEG7TNVSspGmiHHutt7iVKtZwRppD7e04wha5MrkV1h3pti9xQLcCMt6YWsncpoT0HMjkH1FNwWQ==
@@ -1489,7 +1240,7 @@
"@typescript-eslint/types" "8.46.0"
"@typescript-eslint/visitor-keys" "8.46.0"
"@typescript-eslint/tsconfig-utils@8.46.0", "@typescript-eslint/tsconfig-utils@^8.46.0":
"@typescript-eslint/tsconfig-utils@^8.46.0", "@typescript-eslint/tsconfig-utils@8.46.0":
version "8.46.0"
resolved "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.0.tgz"
integrity sha512-WrYXKGAHY836/N7zoK/kzi6p8tXFhasHh8ocFL9VZSAkvH956gfeRfcnhs3xzRy8qQ/dq3q44v1jvQieMFg2cw==
@@ -1505,7 +1256,7 @@
debug "^4.3.4"
ts-api-utils "^2.1.0"
"@typescript-eslint/types@8.46.0", "@typescript-eslint/types@^8.46.0":
"@typescript-eslint/types@^8.46.0", "@typescript-eslint/types@8.46.0":
version "8.46.0"
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.46.0.tgz"
integrity sha512-bHGGJyVjSE4dJJIO5yyEWt/cHyNwga/zXGJbJJ8TiO01aVREK6gCTu3L+5wrkb1FbDkQ+TKjMNe9R/QQQP9+rA==
@@ -1571,7 +1322,7 @@ acorn-jsx@^5.3.2:
resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^8.15.0:
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.15.0:
version "8.15.0"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz"
integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==
@@ -1600,7 +1351,7 @@ ansi-styles@^4.1.0:
dependencies:
color-convert "^2.0.1"
antd@^5.27.4:
"antd@^4.24.15 || ^5.11.2", antd@^5.27.4:
version "5.27.4"
resolved "https://registry.npmjs.org/antd/-/antd-5.27.4.tgz"
integrity sha512-rhArohoAUCxhkPjGI/BXthOrrjaElL4Fb7d4vEHnIR3DpxFXfegd4rN21IgGdiF+Iz4EFuUZu8MdS8NuJHLSVQ==
@@ -1660,6 +1411,13 @@ argparse@^2.0.1:
resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
aria-hidden@^1.2.4:
version "1.2.6"
resolved "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz"
integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==
dependencies:
tslib "^2.0.0"
balanced-match@^1.0.0:
version "1.0.2"
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
@@ -1692,7 +1450,7 @@ braces@^3.0.3:
dependencies:
fill-range "^7.1.1"
browserslist@^4.24.0:
browserslist@^4.24.0, "browserslist@>= 4.21.0":
version "4.26.3"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz"
integrity sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==
@@ -1742,7 +1500,7 @@ chownr@^3.0.0:
resolved "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz"
integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==
classnames@2.x, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1:
classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2, classnames@^2.5.1, classnames@2.x:
version "2.5.1"
resolved "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz"
integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==
@@ -1805,7 +1563,7 @@ csstype@^3.0.2, csstype@^3.1.3:
resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz"
integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
"d3-array@2 - 3", "d3-array@2.10.0 - 3", d3-array@^3.1.6:
d3-array@^3.1.6, "d3-array@2 - 3", "d3-array@2.10.0 - 3":
version "3.2.4"
resolved "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz"
integrity sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==
@@ -1827,7 +1585,7 @@ d3-ease@^3.0.1:
resolved "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz"
integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==
"d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1:
d3-interpolate@^3.0.1, "d3-interpolate@1.2.0 - 3":
version "3.0.1"
resolved "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz"
integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==
@@ -1864,7 +1622,7 @@ d3-shape@^3.1.0:
dependencies:
d3-time "1 - 3"
"d3-time@1 - 3", "d3-time@2.1.1 - 3", d3-time@^3.0.0:
d3-time@^3.0.0, "d3-time@1 - 3", "d3-time@2.1.1 - 3":
version "3.1.0"
resolved "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz"
integrity sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==
@@ -1876,7 +1634,7 @@ d3-timer@^3.0.1:
resolved "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz"
integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==
dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.18:
dayjs@^1.11.10, dayjs@^1.11.11, dayjs@^1.11.18, "dayjs@>= 1.x":
version "1.11.18"
resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz"
integrity sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==
@@ -1908,6 +1666,11 @@ detect-libc@^2.0.3, detect-libc@^2.0.4:
resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
detect-node-es@^1.1.0:
version "1.1.0"
resolved "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz"
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
dunder-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz"
@@ -2022,7 +1785,7 @@ eslint-visitor-keys@^4.2.1:
resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz"
integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==
eslint@^9.36.0:
"eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.36.0, eslint@>=8.40:
version "9.37.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-9.37.0.tgz"
integrity sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==
@@ -2205,6 +1968,11 @@ get-intrinsic@^1.2.5, get-intrinsic@^1.3.0:
hasown "^2.0.2"
math-intrinsics "^1.1.0"
get-nonce@^1.0.0:
version "1.0.1"
resolved "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz"
integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
get-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz"
@@ -2324,7 +2092,7 @@ isexe@^2.0.0:
resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
jiti@^2.6.0:
jiti@*, jiti@^2.6.0, jiti@>=1.21.0:
version "2.6.1"
resolved "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz"
integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==
@@ -2393,52 +2161,7 @@ lightningcss-darwin-arm64@1.30.1:
resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz"
integrity sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==
lightningcss-darwin-x64@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz#e81105d3fd6330860c15fe860f64d39cff5fbd22"
integrity sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==
lightningcss-freebsd-x64@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz#a0e732031083ff9d625c5db021d09eb085af8be4"
integrity sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==
lightningcss-linux-arm-gnueabihf@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz#1f5ecca6095528ddb649f9304ba2560c72474908"
integrity sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==
lightningcss-linux-arm64-gnu@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz#eee7799726103bffff1e88993df726f6911ec009"
integrity sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==
lightningcss-linux-arm64-musl@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz#f2e4b53f42892feeef8f620cbb889f7c064a7dfe"
integrity sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==
lightningcss-linux-x64-gnu@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz#2fc7096224bc000ebb97eea94aea248c5b0eb157"
integrity sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==
lightningcss-linux-x64-musl@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz#66dca2b159fd819ea832c44895d07e5b31d75f26"
integrity sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==
lightningcss-win32-arm64-msvc@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz#7d8110a19d7c2d22bfdf2f2bb8be68e7d1b69039"
integrity sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==
lightningcss-win32-x64-msvc@1.30.1:
version "1.30.1"
resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz#fd7dd008ea98494b85d24b4bea016793f2e0e352"
integrity sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==
lightningcss@1.30.1:
lightningcss@^1.21.0, lightningcss@1.30.1:
version "1.30.1"
resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz"
integrity sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==
@@ -2568,7 +2291,7 @@ node-releases@^2.0.21:
resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz"
integrity sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==
object-assign@4.x, object-assign@^4.1.1:
object-assign@^4.1.1, object-assign@4.x:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -2636,7 +2359,7 @@ picomatch@^2.3.1:
resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
picomatch@^4.0.3:
"picomatch@^3 || ^4", picomatch@^4.0.3:
version "4.0.3"
resolved "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz"
integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==
@@ -2743,7 +2466,7 @@ rc-dropdown@~4.2.0, rc-dropdown@~4.2.1:
classnames "^2.2.6"
rc-util "^5.44.1"
rc-field-form@~2.7.0:
rc-field-form@>=1.22.0, rc-field-form@~2.7.0:
version "2.7.0"
resolved "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.7.0.tgz"
integrity sha512-hgKsCay2taxzVnBPZl+1n4ZondsV78G++XVsMIJCAoioMjlMQR9YwAp7JZDIECzIu2Z66R+f4SFIRrO2DjDNAA==
@@ -3053,19 +2776,24 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
rc-resize-observer "^1.0.0"
rc-util "^5.36.0"
react-dom@^19.1.1:
react-dom@*, "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", react-dom@^19.1.1, react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.8.0, react-dom@>=16.9.0, react-dom@>=17.0.0, react-dom@>=18:
version "19.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz"
integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==
dependencies:
scheduler "^0.27.0"
react-is@^16.12.0, react-is@^16.13.1:
react-is@^16.12.0:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-is@^18.2.0:
react-is@^16.13.1:
version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
"react-is@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", react-is@^18.2.0:
version "18.3.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz"
integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
@@ -3075,7 +2803,7 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
"react-redux@8.x.x || 9.x.x":
"react-redux@^7.2.1 || ^8.1.3 || ^9.0.0", "react-redux@8.x.x || 9.x.x":
version "9.2.0"
resolved "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz"
integrity sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==
@@ -3088,6 +2816,25 @@ react-refresh@^0.17.0:
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
react-remove-scroll-bar@^2.3.7:
version "2.3.8"
resolved "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz"
integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==
dependencies:
react-style-singleton "^2.2.2"
tslib "^2.0.0"
react-remove-scroll@^2.6.3:
version "2.7.2"
resolved "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz"
integrity sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==
dependencies:
react-remove-scroll-bar "^2.3.7"
react-style-singleton "^2.2.3"
tslib "^2.1.0"
use-callback-ref "^1.3.3"
use-sidecar "^1.1.3"
react-router-dom@^7.9.4:
version "7.9.4"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.9.4.tgz"
@@ -3103,7 +2850,15 @@ react-router@7.9.4:
cookie "^1.0.1"
set-cookie-parser "^2.6.0"
react@^19.1.1:
react-style-singleton@^2.2.2, react-style-singleton@^2.2.3:
version "2.2.3"
resolved "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz"
integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==
dependencies:
get-nonce "^1.0.0"
tslib "^2.0.0"
react@*, "react@^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^18 || ^19", "react@^18.0 || ^19", react@^19.1.1, react@^19.2.0, react@>=16.0.0, react@>=16.11.0, react@>=16.12.0, react@>=16.8.0, react@>=16.9.0, react@>=17.0.0, react@>=18:
version "19.2.0"
resolved "https://registry.npmjs.org/react/-/react-19.2.0.tgz"
integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==
@@ -3137,12 +2892,12 @@ redux-thunk@^3.1.0:
resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz"
integrity sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==
redux@^5.0.1:
redux@^5.0.0, redux@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz"
integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==
reselect@5.1.1, reselect@^5.1.0:
reselect@^5.1.0, reselect@5.1.1:
version "5.1.1"
resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz"
integrity sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==
@@ -3329,7 +3084,7 @@ tailwind-merge@^3.3.1:
resolved "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz"
integrity sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==
tailwindcss@4.1.14, tailwindcss@^4.1.14:
tailwindcss@^4.1.14, tailwindcss@4.1.14:
version "4.1.14"
resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz"
integrity sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==
@@ -3390,7 +3145,7 @@ ts-api-utils@^2.1.0:
resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz"
integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==
tslib@^2.0.0, tslib@^2.4.0:
tslib@^2.0.0, tslib@^2.1.0:
version "2.8.1"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -3412,7 +3167,7 @@ typescript-eslint@^8.45.0:
"@typescript-eslint/typescript-estree" "8.46.0"
"@typescript-eslint/utils" "8.46.0"
typescript@~5.9.3:
typescript@>=4.8.4, "typescript@>=4.8.4 <6.0.0", typescript@~5.9.3:
version "5.9.3"
resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz"
integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==
@@ -3437,6 +3192,21 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
use-callback-ref@^1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz"
integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==
dependencies:
tslib "^2.0.0"
use-sidecar@^1.1.3:
version "1.1.3"
resolved "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz"
integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==
dependencies:
detect-node-es "^1.1.0"
tslib "^2.0.0"
use-sync-external-store@^1.2.2, use-sync-external-store@^1.4.0:
version "1.6.0"
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz"
@@ -3462,7 +3232,7 @@ victory-vendor@^37.0.2:
d3-time "^3.0.0"
d3-timer "^3.0.1"
vite@^7.1.7:
"vite@^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", "vite@^5.2.0 || ^6 || ^7", vite@^7.1.7:
version "7.1.9"
resolved "https://registry.npmjs.org/vite/-/vite-7.1.9.tgz"
integrity sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==