mirror of
https://github.com/GSManagerXZ/GameServerManager.git
synced 2026-06-09 09:24:42 +08:00
完善样式
This commit is contained in:
@@ -7,10 +7,7 @@
|
||||
<title>GSM3 游戏面板</title>
|
||||
<meta name="description" content="GSM3 游戏服务器管理面板 - 支持Steam等游戏一键部署" />
|
||||
|
||||
<!-- 游戏风格字体 -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;500;600;700;800;900&family=Exo+2:wght@300;400;500;600;700&family=Rajdhani:wght@300;400;500;600;700&family=JetBrains+Mono:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<!-- 使用系统默认字体 -->
|
||||
|
||||
<style>
|
||||
/* 防止页面闪烁 */
|
||||
@@ -21,7 +18,7 @@
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Exo 2', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
|
||||
@@ -61,7 +61,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setSidebarOpen(false)}
|
||||
className="lg:hidden text-gray-400 hover:text-white transition-colors"
|
||||
className="lg:hidden text-black dark:text-gray-400 hover:text-black dark:hover:text-white transition-colors"
|
||||
>
|
||||
<X className="w-6 h-6" />
|
||||
</button>
|
||||
@@ -79,8 +79,8 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
className={`
|
||||
flex items-center space-x-3 px-4 py-3 rounded-lg transition-all duration-200
|
||||
${isActive
|
||||
? 'bg-blue-600/20 text-blue-400 border border-blue-500/30 shadow-lg'
|
||||
: 'text-gray-300 hover:bg-white/10 hover:text-white'
|
||||
? 'bg-blue-600/20 text-blue-600 dark:text-blue-400 border border-blue-500/30 shadow-lg'
|
||||
: 'text-black dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10 hover:text-black dark:hover:text-white'
|
||||
}
|
||||
`}
|
||||
>
|
||||
@@ -96,7 +96,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
{/* 主题切换 */}
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="flex items-center space-x-3 w-full px-4 py-2 text-gray-300 hover:bg-white/10 hover:text-white rounded-lg transition-all duration-200"
|
||||
className="flex items-center space-x-3 w-full px-4 py-2 text-black dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-white/10 hover:text-black dark:hover:text-white rounded-lg transition-all duration-200"
|
||||
>
|
||||
{theme === 'dark' ? (
|
||||
<Sun className="w-5 h-5" />
|
||||
@@ -109,15 +109,15 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
</button>
|
||||
|
||||
{/* 用户信息 */}
|
||||
<div className="flex items-center space-x-3 px-4 py-2 bg-white/5 rounded-lg">
|
||||
<div className="flex items-center space-x-3 px-4 py-2 bg-gray-100 dark:bg-white/5 rounded-lg">
|
||||
<div className="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center">
|
||||
<User className="w-4 h-4 text-white" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm font-medium text-white truncate">
|
||||
<p className="text-sm font-medium text-black dark:text-white truncate">
|
||||
{user?.username}
|
||||
</p>
|
||||
<p className="text-xs text-gray-400">
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||
{user?.role === 'admin' ? '管理员' : '用户'}
|
||||
</p>
|
||||
</div>
|
||||
@@ -138,7 +138,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
{/* 主内容区域 */}
|
||||
<div className="lg:pl-64">
|
||||
{/* 顶部栏 */}
|
||||
<div className="sticky top-0 z-30 flex h-16 items-center justify-between px-6 glass border-b border-white/20 dark:border-gray-700/30">
|
||||
<div className="sticky top-0 z-30 flex h-16 items-center justify-between px-6 glass border-b border-gray-200 dark:border-gray-700/30">
|
||||
<button
|
||||
onClick={() => setSidebarOpen(true)}
|
||||
className="lg:hidden text-gray-400 hover:text-white transition-colors"
|
||||
@@ -147,7 +147,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
</button>
|
||||
|
||||
<div className="flex items-center space-x-4">
|
||||
<h1 className="text-xl font-semibold text-white font-display">
|
||||
<h1 className="text-xl font-semibold text-black dark:text-white font-display">
|
||||
{navigation.find(item => item.href === location.pathname)?.name || 'GSM3 游戏面板'}
|
||||
</h1>
|
||||
</div>
|
||||
@@ -156,7 +156,7 @@ const Layout: React.FC<LayoutProps> = ({ children }) => {
|
||||
{/* 连接状态指示器 */}
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
|
||||
<span className="text-sm text-gray-300">已连接</span>
|
||||
<span className="text-sm text-black dark:text-gray-300">已连接</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -22,14 +22,14 @@ const NotificationContainer: React.FC = () => {
|
||||
const getBackgroundColor = (type: string) => {
|
||||
switch (type) {
|
||||
case 'success':
|
||||
return 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800'
|
||||
return 'bg-green-50 dark:bg-green-900/20 border-green-200 dark:border-green-800 text-green-800 dark:text-green-200'
|
||||
case 'error':
|
||||
return 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800'
|
||||
return 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-800 dark:text-red-200'
|
||||
case 'warning':
|
||||
return 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800'
|
||||
return 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-800 dark:text-yellow-200'
|
||||
case 'info':
|
||||
default:
|
||||
return 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800'
|
||||
return 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-800 dark:text-blue-200'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,20 @@
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100;
|
||||
@apply bg-white dark:bg-gray-900 text-black dark:text-gray-100;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
font-feature-settings: "rlig" 1, "calt" 1;
|
||||
}
|
||||
|
||||
/* 确保浅色模式以白色为主 */
|
||||
html:not(.dark) {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
html:not(.dark) body {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
}
|
||||
}
|
||||
|
||||
@layer components {
|
||||
@@ -30,9 +41,9 @@
|
||||
|
||||
/* 游戏风格卡片 */
|
||||
.card-game {
|
||||
@apply bg-white/10 dark:bg-gray-800/50 backdrop-blur-sm border border-white/20 dark:border-gray-700/50;
|
||||
@apply bg-white/90 dark:bg-gray-800/50 backdrop-blur-sm border border-gray-200 dark:border-gray-700/50;
|
||||
@apply rounded-xl shadow-xl hover:shadow-2xl transition-all duration-300;
|
||||
@apply hover:bg-white/15 dark:hover:bg-gray-800/70;
|
||||
@apply hover:bg-white dark:hover:bg-gray-800/70;
|
||||
}
|
||||
|
||||
/* 霓虹效果 */
|
||||
@@ -47,13 +58,13 @@
|
||||
|
||||
/* 终端样式 */
|
||||
.terminal-container {
|
||||
@apply bg-gray-900 border border-gray-700 rounded-lg overflow-hidden;
|
||||
@apply shadow-2xl shadow-black/50;
|
||||
@apply bg-white dark:bg-gray-900 border border-gray-300 dark:border-gray-700 rounded-lg overflow-hidden;
|
||||
@apply shadow-2xl shadow-gray-500/20 dark:shadow-black/50;
|
||||
}
|
||||
|
||||
.terminal-header {
|
||||
@apply bg-gray-800 px-4 py-2 flex items-center justify-between;
|
||||
@apply border-b border-gray-700;
|
||||
@apply bg-gray-100 dark:bg-gray-800 px-4 py-2 flex items-center justify-between;
|
||||
@apply border-b border-gray-300 dark:border-gray-700;
|
||||
}
|
||||
|
||||
.terminal-dots {
|
||||
@@ -111,20 +122,20 @@
|
||||
}
|
||||
|
||||
.status-indicator.online {
|
||||
@apply bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400;
|
||||
@apply bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400 border border-green-200 dark:border-green-700;
|
||||
}
|
||||
|
||||
.status-indicator.offline {
|
||||
@apply bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400;
|
||||
@apply bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400 border border-red-200 dark:border-red-700;
|
||||
}
|
||||
|
||||
.status-indicator.warning {
|
||||
@apply bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400;
|
||||
@apply bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400 border border-yellow-200 dark:border-yellow-700;
|
||||
}
|
||||
|
||||
/* 渐变背景 */
|
||||
.bg-game-gradient {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
.dark .bg-game-gradient {
|
||||
@@ -133,7 +144,7 @@
|
||||
|
||||
/* 玻璃态效果 */
|
||||
.glass {
|
||||
@apply bg-white/10 dark:bg-gray-900/20 backdrop-blur-md border border-white/20 dark:border-gray-700/30;
|
||||
@apply bg-white/95 dark:bg-gray-900/20 backdrop-blur-md border border-gray-200 dark:border-gray-700/30;
|
||||
}
|
||||
|
||||
/* 悬浮效果 */
|
||||
@@ -158,14 +169,16 @@
|
||||
|
||||
/* 终端字体 */
|
||||
.font-mono {
|
||||
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', 'Monaco', monospace;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* 游戏字体 */
|
||||
/* 游戏字体 - 使用系统字体 */
|
||||
.font-game {
|
||||
font-family: 'Orbitron', 'Exo 2', sans-serif;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.font-display {
|
||||
font-family: 'Rajdhani', 'Exo 2', sans-serif;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
@@ -100,16 +100,16 @@ const HomePage: React.FC = () => {
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold text-white font-display mb-2">
|
||||
<h2 className="text-2xl font-bold text-black dark:text-white font-display mb-2">
|
||||
欢迎回来,{user?.username}!
|
||||
</h2>
|
||||
<p className="text-gray-300">
|
||||
<p className="text-gray-700 dark:text-gray-300">
|
||||
GSM3 游戏服务器管理面板 - 让游戏服务器管理变得简单
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className={`w-3 h-3 rounded-full ${connected ? 'bg-green-500 animate-pulse' : 'bg-red-500'}`}></div>
|
||||
<span className="text-sm text-gray-300">
|
||||
<span className="text-sm text-gray-700 dark:text-gray-300">
|
||||
{connected ? '已连接' : '连接中断'}
|
||||
</span>
|
||||
</div>
|
||||
@@ -123,8 +123,8 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center space-x-3">
|
||||
<Server className="w-8 h-8 text-blue-500" />
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">操作系统</p>
|
||||
<p className="text-lg font-semibold text-white">{systemInfo.platform}</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">操作系统</p>
|
||||
<p className="text-lg font-semibold text-black dark:text-white">{systemInfo.platform}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -133,8 +133,8 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center space-x-3">
|
||||
<Cpu className="w-8 h-8 text-green-500" />
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">架构</p>
|
||||
<p className="text-lg font-semibold text-white">{systemInfo.arch}</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">架构</p>
|
||||
<p className="text-lg font-semibold text-black dark:text-white">{systemInfo.arch}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -143,8 +143,8 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center space-x-3">
|
||||
<Network className="w-8 h-8 text-purple-500" />
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">主机名</p>
|
||||
<p className="text-lg font-semibold text-white">{systemInfo.hostname}</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">主机名</p>
|
||||
<p className="text-lg font-semibold text-black dark:text-white">{systemInfo.hostname}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,8 +153,8 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center space-x-3">
|
||||
<Zap className="w-8 h-8 text-yellow-500" />
|
||||
<div>
|
||||
<p className="text-sm text-gray-400">Node.js</p>
|
||||
<p className="text-lg font-semibold text-white">{systemInfo.nodeVersion}</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">Node.js</p>
|
||||
<p className="text-lg font-semibold text-black dark:text-white">{systemInfo.nodeVersion}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -169,14 +169,14 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Cpu className="w-6 h-6 text-blue-500" />
|
||||
<h3 className="text-lg font-semibold text-white">CPU使用率</h3>
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white">CPU使用率</h3>
|
||||
</div>
|
||||
<span className={`text-2xl font-bold ${getUsageColor(systemStats.cpu.usage)}`}>
|
||||
{systemStats.cpu.usage.toFixed(1)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between text-sm text-gray-400">
|
||||
<div className="flex justify-between text-sm text-gray-600 dark:text-gray-400">
|
||||
<span>核心数: {systemStats.cpu.cores}</span>
|
||||
<span>型号: {systemStats.cpu.model}</span>
|
||||
</div>
|
||||
@@ -194,14 +194,14 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<MemoryStick className="w-6 h-6 text-green-500" />
|
||||
<h3 className="text-lg font-semibold text-white">内存使用率</h3>
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white">内存使用率</h3>
|
||||
</div>
|
||||
<span className={`text-2xl font-bold ${getUsageColor(systemStats.memory.usage)}`}>
|
||||
{systemStats.memory.usage.toFixed(1)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between text-sm text-gray-400">
|
||||
<div className="flex justify-between text-sm text-gray-600 dark:text-gray-400">
|
||||
<span>已用: {formatBytes(systemStats.memory.used)}</span>
|
||||
<span>总计: {formatBytes(systemStats.memory.total)}</span>
|
||||
</div>
|
||||
@@ -219,14 +219,14 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<HardDrive className="w-6 h-6 text-purple-500" />
|
||||
<h3 className="text-lg font-semibold text-white">磁盘使用率</h3>
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white">磁盘使用率</h3>
|
||||
</div>
|
||||
<span className={`text-2xl font-bold ${getUsageColor(systemStats.disk.usage)}`}>
|
||||
{systemStats.disk.usage.toFixed(1)}%
|
||||
</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between text-sm text-gray-400">
|
||||
<div className="flex justify-between text-sm text-gray-600 dark:text-gray-400">
|
||||
<span>已用: {formatBytes(systemStats.disk.used)}</span>
|
||||
<span>总计: {formatBytes(systemStats.disk.total)}</span>
|
||||
</div>
|
||||
@@ -244,14 +244,14 @@ const HomePage: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Clock className="w-6 h-6 text-yellow-500" />
|
||||
<h3 className="text-lg font-semibold text-white">系统运行时间</h3>
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white">系统运行时间</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<p className="text-2xl font-bold text-white">
|
||||
<p className="text-2xl font-bold text-black dark:text-white">
|
||||
{formatUptime(systemStats.uptime)}
|
||||
</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
最后更新: {new Date(systemStats.timestamp).toLocaleString()}
|
||||
</p>
|
||||
</div>
|
||||
@@ -261,7 +261,7 @@ const HomePage: React.FC = () => {
|
||||
|
||||
{/* 快速操作 */}
|
||||
<div className="card-game p-6">
|
||||
<h3 className="text-lg font-semibold text-white mb-4 flex items-center space-x-2">
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white mb-4 flex items-center space-x-2">
|
||||
<Activity className="w-5 h-5" />
|
||||
<span>快速操作</span>
|
||||
</h3>
|
||||
|
||||
@@ -46,7 +46,7 @@ const LoginPage: React.FC = () => {
|
||||
{/* 主题切换按钮 */}
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="fixed top-4 right-4 p-3 glass rounded-full text-white hover:bg-white/20 transition-all duration-200"
|
||||
className="fixed top-4 right-4 p-3 glass rounded-full text-black dark:text-white hover:bg-white/20 transition-all duration-200"
|
||||
>
|
||||
{theme === 'dark' ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
|
||||
</button>
|
||||
@@ -62,7 +62,7 @@ const LoginPage: React.FC = () => {
|
||||
<h1 className="text-4xl font-bold font-game neon-text mb-2">
|
||||
GSM3
|
||||
</h1>
|
||||
<p className="text-gray-300 font-display">
|
||||
<p className="text-gray-700 dark:text-gray-300 font-display">
|
||||
游戏服务器管理面板
|
||||
</p>
|
||||
</div>
|
||||
@@ -72,7 +72,7 @@ const LoginPage: React.FC = () => {
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* 用户名输入 */}
|
||||
<div>
|
||||
<label htmlFor="username" className="block text-sm font-medium text-gray-200 mb-2">
|
||||
<label htmlFor="username" className="block text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
|
||||
用户名
|
||||
</label>
|
||||
<input
|
||||
@@ -82,7 +82,7 @@ const LoginPage: React.FC = () => {
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
className="
|
||||
w-full px-4 py-3 bg-white/10 border border-white/20 rounded-lg
|
||||
text-white placeholder-gray-400
|
||||
text-black dark:text-white placeholder-gray-400
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
|
||||
transition-all duration-200
|
||||
"
|
||||
@@ -93,7 +93,7 @@ const LoginPage: React.FC = () => {
|
||||
|
||||
{/* 密码输入 */}
|
||||
<div>
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-200 mb-2">
|
||||
<label htmlFor="password" className="block text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
|
||||
密码
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -104,7 +104,7 @@ const LoginPage: React.FC = () => {
|
||||
onChange={(e) => setPassword(e.target.value)}
|
||||
className="
|
||||
w-full px-4 py-3 pr-12 bg-white/10 border border-white/20 rounded-lg
|
||||
text-white placeholder-gray-400
|
||||
text-black dark:text-white placeholder-gray-400
|
||||
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
|
||||
transition-all duration-200
|
||||
"
|
||||
@@ -114,7 +114,7 @@ const LoginPage: React.FC = () => {
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPassword(!showPassword)}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white transition-colors"
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-black dark:hover:text-white transition-colors"
|
||||
disabled={loading}
|
||||
>
|
||||
{showPassword ? <EyeOff className="w-5 h-5" /> : <Eye className="w-5 h-5" />}
|
||||
@@ -152,7 +152,7 @@ const LoginPage: React.FC = () => {
|
||||
|
||||
{/* 底部信息 */}
|
||||
<div className="mt-6 text-center">
|
||||
<p className="text-sm text-gray-400">
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
GSM3 游戏服务器管理面板 v1.0.0
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -5,8 +5,6 @@ import { useNotificationStore } from '@/stores/notificationStore'
|
||||
import {
|
||||
Settings,
|
||||
Palette,
|
||||
Bell,
|
||||
Terminal,
|
||||
Shield,
|
||||
User,
|
||||
Save,
|
||||
@@ -32,22 +30,7 @@ const SettingsPage: React.FC = () => {
|
||||
})
|
||||
const [passwordLoading, setPasswordLoading] = useState(false)
|
||||
|
||||
// 终端设置
|
||||
const [terminalSettings, setTerminalSettings] = useState({
|
||||
fontSize: 14,
|
||||
fontFamily: 'JetBrains Mono',
|
||||
theme: 'dark',
|
||||
cursorBlink: true,
|
||||
scrollback: 1000
|
||||
})
|
||||
|
||||
// 通知设置
|
||||
const [notificationSettings, setNotificationSettings] = useState({
|
||||
desktop: true,
|
||||
sound: true,
|
||||
system: true,
|
||||
games: true
|
||||
})
|
||||
|
||||
|
||||
// 处理密码修改
|
||||
const handlePasswordChange = async (e: React.FormEvent) => {
|
||||
@@ -121,21 +104,6 @@ const SettingsPage: React.FC = () => {
|
||||
|
||||
// 重置设置
|
||||
const resetSettings = () => {
|
||||
setTerminalSettings({
|
||||
fontSize: 14,
|
||||
fontFamily: 'JetBrains Mono',
|
||||
theme: 'dark',
|
||||
cursorBlink: true,
|
||||
scrollback: 1000
|
||||
})
|
||||
|
||||
setNotificationSettings({
|
||||
desktop: true,
|
||||
sound: true,
|
||||
system: true,
|
||||
games: true
|
||||
})
|
||||
|
||||
addNotification({
|
||||
type: 'info',
|
||||
title: '设置已重置',
|
||||
@@ -149,28 +117,28 @@ const SettingsPage: React.FC = () => {
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Settings className="w-6 h-6 text-blue-500" />
|
||||
<h1 className="text-2xl font-bold text-white font-display">
|
||||
<h1 className="text-2xl font-bold text-black dark:text-white font-display">
|
||||
系统设置
|
||||
</h1>
|
||||
</div>
|
||||
<p className="text-gray-300 mt-2">
|
||||
<p className="text-gray-700 dark:text-gray-300 mt-2">
|
||||
自定义您的GSM3游戏面板体验
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-2 gap-6">
|
||||
{/* 外观设置 */}
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center space-x-3 mb-6">
|
||||
<Palette className="w-5 h-5 text-purple-500" />
|
||||
<h2 className="text-lg font-semibold text-white">外观设置</h2>
|
||||
<h2 className="text-lg font-semibold text-black dark:text-white">外观设置</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<label className="text-sm font-medium text-gray-200">主题模式</label>
|
||||
<p className="text-xs text-gray-400">选择浅色或深色主题</p>
|
||||
<label className="text-sm font-medium text-gray-800 dark:text-gray-200">主题模式</label>
|
||||
<p className="text-xs text-gray-600 dark:text-gray-400">选择浅色或深色主题</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
@@ -189,154 +157,20 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div className="pt-4 border-t border-gray-700">
|
||||
<p className="text-sm text-gray-300">
|
||||
<p className="text-sm text-gray-700 dark:text-gray-300">
|
||||
当前主题: <span className="font-semibold">{theme === 'dark' ? '深色模式' : '浅色模式'}</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 通知设置 */}
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center space-x-3 mb-6">
|
||||
<Bell className="w-5 h-5 text-yellow-500" />
|
||||
<h2 className="text-lg font-semibold text-white">通知设置</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{Object.entries(notificationSettings).map(([key, value]) => {
|
||||
const labels = {
|
||||
desktop: '桌面通知',
|
||||
sound: '声音提醒',
|
||||
system: '系统通知',
|
||||
games: '游戏通知'
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={key} className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-gray-200">
|
||||
{labels[key as keyof typeof labels]}
|
||||
</label>
|
||||
<button
|
||||
onClick={() => setNotificationSettings(prev => ({
|
||||
...prev,
|
||||
[key]: !value
|
||||
}))}
|
||||
className={`
|
||||
relative inline-flex h-6 w-11 items-center rounded-full transition-colors
|
||||
${value ? 'bg-green-600' : 'bg-gray-600'}
|
||||
`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
inline-block h-4 w-4 transform rounded-full bg-white transition-transform
|
||||
${value ? 'translate-x-6' : 'translate-x-1'}
|
||||
`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 终端设置 */}
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center space-x-3 mb-6">
|
||||
<Terminal className="w-5 h-5 text-green-500" />
|
||||
<h2 className="text-lg font-semibold text-white">终端设置</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
字体大小
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="10"
|
||||
max="20"
|
||||
value={terminalSettings.fontSize}
|
||||
onChange={(e) => setTerminalSettings(prev => ({
|
||||
...prev,
|
||||
fontSize: parseInt(e.target.value)
|
||||
}))}
|
||||
className="w-full h-2 bg-gray-700 rounded-lg appearance-none cursor-pointer"
|
||||
/>
|
||||
<div className="flex justify-between text-xs text-gray-400 mt-1">
|
||||
<span>10px</span>
|
||||
<span>{terminalSettings.fontSize}px</span>
|
||||
<span>20px</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
字体系列
|
||||
</label>
|
||||
<select
|
||||
value={terminalSettings.fontFamily}
|
||||
onChange={(e) => setTerminalSettings(prev => ({
|
||||
...prev,
|
||||
fontFamily: e.target.value
|
||||
}))}
|
||||
className="w-full px-3 py-2 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
>
|
||||
<option value="JetBrains Mono">JetBrains Mono</option>
|
||||
<option value="Fira Code">Fira Code</option>
|
||||
<option value="Consolas">Consolas</option>
|
||||
<option value="Monaco">Monaco</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
滚动缓冲区大小
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
min="100"
|
||||
max="10000"
|
||||
step="100"
|
||||
value={terminalSettings.scrollback}
|
||||
onChange={(e) => setTerminalSettings(prev => ({
|
||||
...prev,
|
||||
scrollback: parseInt(e.target.value)
|
||||
}))}
|
||||
className="w-full px-3 py-2 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="text-sm font-medium text-gray-200">
|
||||
光标闪烁
|
||||
</label>
|
||||
<button
|
||||
onClick={() => setTerminalSettings(prev => ({
|
||||
...prev,
|
||||
cursorBlink: !prev.cursorBlink
|
||||
}))}
|
||||
className={`
|
||||
relative inline-flex h-6 w-11 items-center rounded-full transition-colors
|
||||
${terminalSettings.cursorBlink ? 'bg-blue-600' : 'bg-gray-600'}
|
||||
`}
|
||||
>
|
||||
<span
|
||||
className={`
|
||||
inline-block h-4 w-4 transform rounded-full bg-white transition-transform
|
||||
${terminalSettings.cursorBlink ? 'translate-x-6' : 'translate-x-1'}
|
||||
`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{/* 账户安全 */}
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center space-x-3 mb-6">
|
||||
<Shield className="w-5 h-5 text-red-500" />
|
||||
<h2 className="text-lg font-semibold text-white">账户安全</h2>
|
||||
<h2 className="text-lg font-semibold text-black dark:text-white">账户安全</h2>
|
||||
</div>
|
||||
|
||||
{/* 用户信息 */}
|
||||
@@ -344,8 +178,8 @@ const SettingsPage: React.FC = () => {
|
||||
<div className="flex items-center space-x-3">
|
||||
<User className="w-8 h-8 text-blue-500" />
|
||||
<div>
|
||||
<p className="text-white font-medium">{user?.username}</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
<p className="text-black dark:text-white font-medium">{user?.username}</p>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">
|
||||
{user?.role === 'admin' ? '管理员' : '普通用户'}
|
||||
</p>
|
||||
</div>
|
||||
@@ -355,7 +189,7 @@ const SettingsPage: React.FC = () => {
|
||||
{/* 修改密码表单 */}
|
||||
<form onSubmit={handlePasswordChange} className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
<label className="block text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
|
||||
当前密码
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -366,7 +200,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
oldPassword: e.target.value
|
||||
}))}
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-black dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="请输入当前密码"
|
||||
disabled={passwordLoading}
|
||||
/>
|
||||
@@ -376,7 +210,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
showOldPassword: !prev.showOldPassword
|
||||
}))}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white"
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-black dark:hover:text-white"
|
||||
>
|
||||
{passwordForm.showOldPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
</button>
|
||||
@@ -384,7 +218,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
<label className="block text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
|
||||
新密码
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -395,7 +229,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
newPassword: e.target.value
|
||||
}))}
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-black dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="请输入新密码"
|
||||
disabled={passwordLoading}
|
||||
/>
|
||||
@@ -405,7 +239,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
showNewPassword: !prev.showNewPassword
|
||||
}))}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white"
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-black dark:hover:text-white"
|
||||
>
|
||||
{passwordForm.showNewPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
</button>
|
||||
@@ -413,7 +247,7 @@ const SettingsPage: React.FC = () => {
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-200 mb-2">
|
||||
<label className="block text-sm font-medium text-gray-800 dark:text-gray-200 mb-2">
|
||||
确认新密码
|
||||
</label>
|
||||
<div className="relative">
|
||||
@@ -424,7 +258,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
confirmPassword: e.target.value
|
||||
}))}
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
className="w-full px-3 py-2 pr-10 bg-white/10 border border-white/20 rounded-lg text-black dark:text-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="请再次输入新密码"
|
||||
disabled={passwordLoading}
|
||||
/>
|
||||
@@ -434,7 +268,7 @@ const SettingsPage: React.FC = () => {
|
||||
...prev,
|
||||
showConfirmPassword: !prev.showConfirmPassword
|
||||
}))}
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-white"
|
||||
className="absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-black dark:hover:text-white"
|
||||
>
|
||||
{passwordForm.showConfirmPassword ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
</button>
|
||||
@@ -456,8 +290,8 @@ const SettingsPage: React.FC = () => {
|
||||
<div className="card-game p-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-lg font-semibold text-white mb-1">设置操作</h3>
|
||||
<p className="text-sm text-gray-400">保存或重置您的设置</p>
|
||||
<h3 className="text-lg font-semibold text-black dark:text-white mb-1">设置操作</h3>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400">保存或重置您的设置</p>
|
||||
</div>
|
||||
|
||||
<div className="flex space-x-3">
|
||||
|
||||
@@ -408,7 +408,7 @@ const TerminalPage: React.FC = () => {
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-2">
|
||||
<TerminalIcon className="w-5 h-5 text-blue-500" />
|
||||
<h2 className="text-lg font-semibold text-white font-display">
|
||||
<h2 className="text-lg font-semibold text-black dark:text-white font-display">
|
||||
终端管理
|
||||
</h2>
|
||||
</div>
|
||||
@@ -426,7 +426,7 @@ const TerminalPage: React.FC = () => {
|
||||
<>
|
||||
<button
|
||||
onClick={resetTerminal}
|
||||
className="p-2 text-gray-400 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
className="p-2 text-gray-600 dark:text-gray-400 hover:text-black dark:hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
title="重置终端"
|
||||
>
|
||||
<RotateCcw className="w-4 h-4" />
|
||||
@@ -434,14 +434,14 @@ const TerminalPage: React.FC = () => {
|
||||
|
||||
<button
|
||||
onClick={toggleFullscreen}
|
||||
className="p-2 text-gray-400 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
className="p-2 text-gray-600 dark:text-gray-400 hover:text-black dark:hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
title={isFullscreen ? '退出全屏' : '全屏模式'}
|
||||
>
|
||||
{isFullscreen ? <Minimize2 className="w-4 h-4" /> : <Maximize2 className="w-4 h-4" />}
|
||||
</button>
|
||||
|
||||
<button
|
||||
className="p-2 text-gray-400 hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
className="p-2 text-gray-600 dark:text-gray-400 hover:text-black dark:hover:text-white hover:bg-white/10 rounded-lg transition-colors"
|
||||
title="终端设置"
|
||||
>
|
||||
<Settings className="w-4 h-4" />
|
||||
@@ -461,7 +461,7 @@ const TerminalPage: React.FC = () => {
|
||||
flex items-center space-x-2 px-3 py-2 rounded-lg cursor-pointer transition-all
|
||||
${session.active
|
||||
? 'bg-blue-600/20 text-blue-400 border border-blue-500/30'
|
||||
: 'bg-white/5 text-gray-400 hover:bg-white/10 hover:text-white'
|
||||
: 'bg-white/5 text-gray-600 dark:text-gray-400 hover:bg-white/10 hover:text-black dark:hover:text-white'
|
||||
}
|
||||
`}
|
||||
onClick={() => switchTerminalSession(session.id)}
|
||||
@@ -490,7 +490,7 @@ const TerminalPage: React.FC = () => {
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<TerminalIcon className="w-16 h-16 text-gray-500 mx-auto mb-4" />
|
||||
<p className="text-gray-400 mb-4">暂无终端会话</p>
|
||||
<p className="text-gray-600 dark:text-gray-400 mb-4">暂无终端会话</p>
|
||||
<button
|
||||
onClick={createTerminalSession}
|
||||
className="btn-game px-6 py-3"
|
||||
@@ -508,10 +508,10 @@ const TerminalPage: React.FC = () => {
|
||||
<div className="terminal-dot yellow"></div>
|
||||
<div className="terminal-dot green"></div>
|
||||
</div>
|
||||
<div className="text-sm text-gray-400">
|
||||
<div className="text-sm text-gray-600 dark:text-gray-400">
|
||||
{sessions.find(s => s.active)?.name || '终端'}
|
||||
</div>
|
||||
<div className="text-xs text-gray-500">
|
||||
<div className="text-xs text-gray-700 dark:text-gray-500">
|
||||
{activeSessionId}
|
||||
</div>
|
||||
</div>
|
||||
@@ -528,8 +528,8 @@ const TerminalPage: React.FC = () => {
|
||||
{/* 终端使用说明 */}
|
||||
{!isFullscreen && (
|
||||
<div className="card-game p-4">
|
||||
<h3 className="text-sm font-semibold text-white mb-2">使用说明</h3>
|
||||
<div className="text-xs text-gray-400 space-y-1">
|
||||
<h3 className="text-sm font-semibold text-black dark:text-white mb-2">使用说明</h3>
|
||||
<div className="text-xs text-gray-600 dark:text-gray-400 space-y-1">
|
||||
<p>• 支持多终端会话,可以同时运行多个终端</p>
|
||||
<p>• 终端会话在页面刷新后会自动恢复</p>
|
||||
<p>• 支持全屏模式,提供更好的操作体验</p>
|
||||
|
||||
@@ -95,8 +95,9 @@ export default {
|
||||
}
|
||||
},
|
||||
fontFamily: {
|
||||
'mono': ['JetBrains Mono', 'Fira Code', 'Consolas', 'monospace'],
|
||||
'game': ['Orbitron', 'Exo 2', 'Rajdhani', 'sans-serif'],
|
||||
'sans': ['system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'sans-serif'],
|
||||
'mono': ['Consolas', 'Monaco', 'Courier New', 'monospace'],
|
||||
'game': ['system-ui', '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'sans-serif'],
|
||||
},
|
||||
animation: {
|
||||
'pulse-slow': 'pulse 3s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
|
||||
Reference in New Issue
Block a user