diff --git a/web/static/css/style.css b/web/static/css/style.css index a43dcd92..c9156be6 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -53,12 +53,411 @@ body { min-height: 0; } -header { - background: var(--primary-color); - color: white; - padding: 16px 24px; - border-bottom: 1px solid rgba(255, 255, 255, 0.1); +/* 主侧边栏样式 - Ant Design Pro 风格 */ +.main-sidebar { + width: 256px; + background: linear-gradient(180deg, #fafbfc 0%, #f5f7fa 100%); + color: var(--text-primary); + display: flex; + flex-direction: column; flex-shrink: 0; + border-right: 1px solid var(--border-color); + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04); + position: relative; + transition: width 0.2s ease; +} + +.main-sidebar.collapsed { + width: 64px; +} + +.sidebar-collapse-btn { + position: absolute; + top: 16px; + right: 8px; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + border-radius: 6px; + background: var(--bg-primary); + border: 1px solid var(--border-color); + color: var(--text-secondary); + transition: all 0.2s ease; + z-index: 10; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08); +} + +.sidebar-collapse-btn:hover { + background: var(--bg-tertiary); + color: var(--text-primary); + border-color: var(--accent-color); +} + +.main-sidebar.collapsed .sidebar-collapse-btn { + right: 16px; + transform: rotate(180deg); +} + +.sidebar-collapse-btn svg { + width: 16px; + height: 16px; + stroke: currentColor; + transition: transform 0.2s ease; +} + +.main-sidebar-header { + padding: 16px 20px; + border-bottom: 1px solid var(--border-color); + flex-shrink: 0; + background: var(--bg-primary); +} + +.main-sidebar-header .logo { + display: flex; + align-items: center; + gap: 12px; + color: var(--text-primary); +} + +.main-sidebar-header .logo span { + font-size: 1.25rem; + font-weight: 600; + letter-spacing: -0.3px; + color: var(--text-primary); +} + +.main-sidebar-nav { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding: 16px 0; + background: transparent; + padding-top: 56px; +} + +/* 侧边栏滚动条样式 */ +.main-sidebar-nav::-webkit-scrollbar { + width: 6px; +} + +.main-sidebar-nav::-webkit-scrollbar-track { + background: transparent; +} + +.main-sidebar-nav::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.2); + border-radius: 3px; +} + +.main-sidebar-nav::-webkit-scrollbar-thumb:hover { + background: rgba(0, 0, 0, 0.3); +} + +.nav-item { + margin-bottom: 0; +} + +.nav-item-content { + display: flex; + align-items: center; + gap: 12px; + padding: 12px 20px; + cursor: pointer; + transition: all 0.2s ease; + color: var(--text-primary); + position: relative; + font-size: 0.9375rem; + border-left: 3px solid transparent; + justify-content: flex-start; +} + +.main-sidebar.collapsed .nav-item-content { + padding: 12px; + justify-content: center; + position: relative; +} + +.main-sidebar.collapsed .nav-item-content:hover::after { + content: attr(data-title); + position: absolute; + left: 100%; + top: 50%; + transform: translateY(-50%); + margin-left: 12px; + padding: 6px 12px; + background: rgba(0, 0, 0, 0.85); + color: white; + border-radius: 4px; + font-size: 0.8125rem; + white-space: nowrap; + z-index: 1000; + pointer-events: none; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); +} + +.main-sidebar.collapsed .nav-item-content:hover::before { + content: ''; + position: absolute; + left: 100%; + top: 50%; + transform: translateY(-50%); + margin-left: 6px; + border: 6px solid transparent; + border-right-color: rgba(0, 0, 0, 0.85); + z-index: 1001; + pointer-events: none; +} + +.nav-item-content:hover { + background: rgba(0, 102, 255, 0.06); + color: var(--text-primary); +} + +.nav-item.active > .nav-item-content { + background: linear-gradient(90deg, rgba(0, 102, 255, 0.12) 0%, rgba(0, 102, 255, 0.06) 100%); + color: var(--accent-color); + border-left-color: var(--accent-color); + font-weight: 500; +} + +.nav-item.active > .nav-item-content svg { + stroke: var(--accent-color); +} + +.nav-item-content svg { + flex-shrink: 0; + stroke: currentColor; + width: 18px; + height: 18px; +} + +.nav-item-content span { + flex: 1; + font-size: 0.9375rem; + font-weight: 400; + white-space: nowrap; + opacity: 1; + transition: opacity 0.2s ease; +} + +.main-sidebar.collapsed .nav-item-content span { + opacity: 0; + width: 0; + overflow: hidden; +} + +.nav-item-has-submenu .nav-item-content { + justify-content: space-between; +} + +.main-sidebar.collapsed .nav-item-has-submenu .nav-item-content { + justify-content: center; +} + +.main-sidebar.collapsed .submenu-arrow { + display: none; +} + +.submenu-arrow { + transition: transform 0.2s ease; + flex-shrink: 0; + width: 14px; + height: 14px; + stroke: var(--text-secondary); +} + +.nav-item.expanded .submenu-arrow { + transform: rotate(90deg); +} + +.nav-item.expanded > .nav-item-content { + color: var(--text-primary); + font-weight: 500; +} + +.nav-submenu { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease; + background: rgba(255, 255, 255, 0.5); +} + +.nav-item.expanded .nav-submenu { + max-height: 300px; +} + +.nav-submenu-item { + padding: 10px 20px 10px 56px; + cursor: pointer; + transition: all 0.2s ease; + color: var(--text-secondary); + font-size: 0.875rem; + position: relative; + border-left: 3px solid transparent; +} + +.main-sidebar.collapsed .nav-submenu { + display: none; +} + +.main-sidebar.collapsed .nav-item.expanded .nav-submenu { + display: none; +} + +/* 子菜单弹出框样式 */ +.submenu-popup { + background: var(--bg-primary); + border: 1px solid var(--border-color); + border-radius: 8px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + padding: 4px 0; + min-width: 160px; + margin-left: 8px; + animation: popupFadeIn 0.2s ease; +} + +@keyframes popupFadeIn { + from { + opacity: 0; + transform: translateX(-8px); + } + to { + opacity: 1; + transform: translateX(0); + } +} + +.submenu-popup-item { + padding: 10px 16px; + cursor: pointer; + transition: all 0.2s ease; + color: var(--text-primary); + font-size: 0.875rem; + white-space: nowrap; +} + +.submenu-popup-item:hover { + background: rgba(0, 102, 255, 0.08); + color: var(--accent-color); +} + +.submenu-popup-item:active { + background: rgba(0, 102, 255, 0.12); +} + +.submenu-popup-item.active { + background: rgba(0, 102, 255, 0.1); + color: var(--accent-color); + font-weight: 500; +} + +.nav-submenu-item:hover { + background: rgba(0, 102, 255, 0.06); + color: var(--text-primary); +} + +.nav-submenu-item.active { + background: linear-gradient(90deg, rgba(0, 102, 255, 0.12) 0%, rgba(0, 102, 255, 0.06) 100%); + color: var(--accent-color); + border-left-color: var(--accent-color); + font-weight: 500; +} + +/* 内容区域 */ +.content-area { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; + min-width: 0; + background: #f5f7fa; +} + +/* 对话页面不需要page-header */ +#page-chat .page-header { + display: none; +} + +#page-chat .page-content { + padding: 0; + overflow: hidden; +} + +.page { + display: none; + flex: 1; + flex-direction: column; + overflow: hidden; + min-height: 0; +} + +.page.active { + display: flex; +} + +.page-header { + padding: 20px 24px; + background: linear-gradient(135deg, #ffffff 0%, #fafbfc 100%); + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; + flex-shrink: 0; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); +} + +.page-header h2 { + margin: 0; + font-size: 1.5rem; + font-weight: 600; + color: var(--text-primary); +} + +.page-header-actions { + display: flex; + gap: 12px; + align-items: center; +} + +.page-content { + flex: 1; + overflow-y: auto; + overflow-x: hidden; + padding: 24px; + min-height: 0; +} + +/* 对话页面布局 */ +.chat-page-layout { + display: flex; + flex: 1; + overflow: hidden; + min-height: 0; + width: 100%; + height: 100%; +} + +.conversation-sidebar { + width: 280px; + background: linear-gradient(180deg, #ffffff 0%, #fafbfc 100%); + border-right: 1px solid var(--border-color); + display: flex; + flex-direction: column; + flex-shrink: 0; + height: 100%; + overflow: hidden; +} + +header { + background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); + color: var(--text-primary); + padding: 10px 24px; + border-bottom: 1px solid var(--border-color); + flex-shrink: 0; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06); } .header-content { @@ -78,10 +477,11 @@ header { } .logo h1 { - font-size: 1.75rem; + font-size: 1.5rem; font-weight: 600; letter-spacing: -0.5px; margin: 0; + color: var(--text-primary); } .header-right { @@ -92,7 +492,7 @@ header { .header-subtitle { font-size: 0.875rem; - color: rgba(255, 255, 255, 0.7); + color: var(--text-secondary); margin: 0; font-weight: 400; } @@ -108,13 +508,13 @@ header { align-items: center; justify-content: center; gap: 6px; - padding: 8px 14px; - border-radius: 999px; - border: 1px solid rgba(255, 255, 255, 0.2); - background: rgba(255, 255, 255, 0.05); - color: white; + padding: 6px 12px; + border-radius: 6px; + border: 1px solid var(--border-color); + background: var(--bg-primary); + color: var(--text-primary); cursor: pointer; - font-size: 0.85rem; + font-size: 0.8125rem; font-weight: 500; transition: all 0.2s ease; } @@ -124,41 +524,42 @@ header { } .header-actions button:hover { - background: rgba(255, 255, 255, 0.12); - border-color: rgba(255, 255, 255, 0.35); + background: var(--bg-tertiary); + border-color: var(--accent-color); + color: var(--accent-color); transform: translateY(-1px); } .monitor-btn { - color: #8cc4ff; - border-color: rgba(0, 102, 255, 0.35); - background: rgba(0, 102, 255, 0.15); + color: var(--accent-color); + border-color: var(--border-color); + background: var(--bg-primary); } .monitor-btn:hover { - background: rgba(0, 102, 255, 0.25); - border-color: rgba(0, 102, 255, 0.45); - color: #cfe4ff; + background: rgba(0, 102, 255, 0.08); + border-color: var(--accent-color); + color: var(--accent-color); } .attack-chain-btn { - color: #ffe08a; - border-color: rgba(255, 255, 255, 0.3); - background: rgba(255, 255, 255, 0.08); + color: var(--text-primary); + border-color: var(--border-color); + background: var(--bg-primary); } .attack-chain-btn:not(:disabled):hover { - background: rgba(255, 255, 255, 0.18); - border-color: rgba(255, 255, 255, 0.45); - color: #fff5cc; + background: var(--bg-tertiary); + border-color: var(--accent-color); + color: var(--accent-color); } .attack-chain-btn:disabled { - opacity: 0.55; + opacity: 0.5; cursor: not-allowed; - border-color: rgba(255, 255, 255, 0.15); - background: rgba(255, 255, 255, 0.04); - color: rgba(255, 255, 255, 0.6); + border-color: var(--border-color); + background: var(--bg-secondary); + color: var(--text-muted); } .settings-btn { @@ -166,7 +567,17 @@ header { min-width: 44px; } -/* 侧边栏样式 */ +/* 设置页面样式 */ +.settings-actions { + margin-top: 32px; + padding-top: 24px; + border-top: 1px solid var(--border-color); + display: flex; + justify-content: flex-end; + gap: 12px; +} + +/* 旧侧边栏样式(保留用于对话页面内的历史对话侧边栏) */ .sidebar { width: 280px; background: var(--bg-secondary); @@ -355,7 +766,7 @@ header { flex-direction: column; flex: 1; min-width: 0; - background: var(--bg-secondary); + background: #f5f7fa; overflow: hidden; height: 100%; } @@ -365,7 +776,7 @@ header { overflow-y: auto; overflow-x: hidden; padding: 24px; - background: var(--bg-secondary); + background: #f5f7fa; display: flex; flex-direction: column; min-height: 0; @@ -1365,12 +1776,12 @@ header { } header { - padding: 16px 20px; + padding: 10px 20px; flex-shrink: 0; } .logo h1 { - font-size: 1.5rem; + font-size: 1.25rem; } .header-subtitle { @@ -1382,7 +1793,36 @@ header { min-height: 0; } + /* 主侧边栏在移动设备上可以折叠或调整 */ + .main-sidebar { + width: 200px; + } + + .main-sidebar.collapsed { + width: 64px; + } + + .sidebar-collapse-btn { + width: 28px; + height: 28px; + } + + .main-sidebar-header .logo span { + font-size: 1rem; + } + + .nav-item-content { + padding: 10px 12px; + font-size: 0.875rem; + } + + .nav-item-content span { + font-size: 0.875rem; + } + + .conversation-sidebar, .sidebar { + width: 240px; height: 100%; overflow: hidden; } @@ -1410,6 +1850,19 @@ header { flex-shrink: 0; } + .page-header { + padding: 16px; + flex-wrap: wrap; + } + + .page-header h2 { + font-size: 1.25rem; + } + + .page-content { + padding: 16px; + } + .modal-content { width: 95%; margin: 10% auto; diff --git a/web/static/js/monitor.js b/web/static/js/monitor.js index 144dd7ee..a56f2e4e 100644 --- a/web/static/js/monitor.js +++ b/web/static/js/monitor.js @@ -911,42 +911,17 @@ const monitorState = { }; function openMonitorPanel() { - const modal = document.getElementById('monitor-modal'); - if (!modal) { - return; + // 切换到MCP监控页面 + if (typeof switchPage === 'function') { + switchPage('mcp-monitor'); } - modal.style.display = 'block'; - - // 重置显示状态 - const statsContainer = document.getElementById('monitor-stats'); - const execContainer = document.getElementById('monitor-executions'); - if (statsContainer) { - statsContainer.innerHTML = '
AI 驱动的自动化安全测试平台