style(ui): 统一组件样式,优化视觉设计和交互体验

- 更新颜色系统,使用新的主题变量
- 调整圆角、边框、阴影等视觉样式
- 优化字体大小、间距和排版细节
- 改进表单组件的交互状态
- 增强暗色模式下的显示效果
This commit is contained in:
lintsinghua 2025-12-18 19:57:43 +08:00
parent 51ee5a0da9
commit 8ee98a20eb
73 changed files with 2218 additions and 1966 deletions

View File

@ -1,5 +1,6 @@
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { ThemeProvider } from "next-themes";
import "@/assets/styles/globals.css";
import App from "./App.tsx";
import { AppWrapper } from "@/components/layout/PageMeta";
@ -9,9 +10,16 @@ import "@/shared/utils/fetchWrapper"; // 初始化fetch拦截器
createRoot(document.getElementById("root")!).render(
<StrictMode>
<ErrorBoundary>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange={false}
>
<AppWrapper>
<App />
</AppWrapper>
</ThemeProvider>
</ErrorBoundary>
</StrictMode>
);

File diff suppressed because it is too large Load Diff

View File

@ -23,7 +23,7 @@ export default function AgentModeSelector({
<div className="space-y-3">
<div className="flex items-center gap-2 mb-2">
<Shield className="w-4 h-4 text-violet-400" />
<span className="font-mono text-xs font-bold text-gray-400 uppercase tracking-wider">
<span className="font-mono text-xs font-bold text-muted-foreground uppercase tracking-wider">
</span>
</div>
@ -35,7 +35,7 @@ export default function AgentModeSelector({
"relative flex flex-col p-4 border cursor-pointer transition-all rounded",
value === "fast"
? "border-amber-500/50 bg-amber-950/30"
: "border-gray-700 hover:border-gray-600 bg-gray-900/30",
: "border-border hover:border-border bg-muted/50",
disabled && "opacity-50 cursor-not-allowed"
)}
>
@ -54,16 +54,16 @@ export default function AgentModeSelector({
"p-1.5 rounded border",
value === "fast"
? "bg-amber-500/20 border-amber-500/50"
: "bg-gray-800 border-gray-700"
: "bg-muted border-border"
)}>
<Zap className={cn(
"w-4 h-4",
value === "fast" ? "text-amber-400" : "text-gray-500"
value === "fast" ? "text-amber-400" : "text-muted-foreground"
)} />
</div>
<span className={cn(
"font-bold text-sm font-mono uppercase",
value === "fast" ? "text-amber-300" : "text-gray-400"
value === "fast" ? "text-amber-300" : "text-muted-foreground"
)}>
</span>
@ -72,7 +72,7 @@ export default function AgentModeSelector({
)}
</div>
<ul className="text-xs text-gray-500 space-y-1 mb-3 font-mono">
<ul className="text-xs text-muted-foreground space-y-1 mb-3 font-mono">
<li className="flex items-center gap-1">
<Clock className="w-3 h-3" />
@ -81,14 +81,14 @@ export default function AgentModeSelector({
<Code className="w-3 h-3" />
LLM
</li>
<li className="flex items-center gap-1 text-gray-600">
<li className="flex items-center gap-1 text-muted-foreground">
<Shield className="w-3 h-3" />
</li>
</ul>
<div className="mt-auto pt-2 border-t border-gray-800">
<span className="text-[10px] uppercase tracking-wider text-gray-600 font-bold font-mono">
<div className="mt-auto pt-2 border-t border-border">
<span className="text-xs uppercase tracking-wider text-muted-foreground font-bold font-mono">
适合: CI/CD
</span>
</div>
@ -100,7 +100,7 @@ export default function AgentModeSelector({
"relative flex flex-col p-4 border cursor-pointer transition-all rounded",
value === "agent"
? "border-violet-500/50 bg-violet-950/30"
: "border-gray-700 hover:border-gray-600 bg-gray-900/30",
: "border-border hover:border-border bg-muted/50",
disabled && "opacity-50 cursor-not-allowed"
)}
>
@ -115,7 +115,7 @@ export default function AgentModeSelector({
/>
{/* 推荐标签 */}
<div className="absolute -top-2 -right-2 px-2 py-0.5 bg-violet-600 text-white text-[10px] font-bold uppercase font-mono rounded shadow-[0_0_10px_rgba(139,92,246,0.5)]">
<div className="absolute -top-2 -right-2 px-2 py-0.5 bg-violet-600 text-foreground text-xs font-bold uppercase font-mono rounded shadow-[0_0_10px_rgba(139,92,246,0.5)]">
</div>
@ -124,16 +124,16 @@ export default function AgentModeSelector({
"p-1.5 rounded border",
value === "agent"
? "bg-violet-500/20 border-violet-500/50"
: "bg-gray-800 border-gray-700"
: "bg-muted border-border"
)}>
<Bot className={cn(
"w-4 h-4",
value === "agent" ? "text-violet-400" : "text-gray-500"
value === "agent" ? "text-violet-400" : "text-muted-foreground"
)} />
</div>
<span className={cn(
"font-bold text-sm font-mono uppercase",
value === "agent" ? "text-violet-300" : "text-gray-400"
value === "agent" ? "text-violet-300" : "text-muted-foreground"
)}>
Agent
</span>
@ -142,7 +142,7 @@ export default function AgentModeSelector({
)}
</div>
<ul className="text-xs text-gray-500 space-y-1 mb-3 font-mono">
<ul className="text-xs text-muted-foreground space-y-1 mb-3 font-mono">
<li className="flex items-center gap-1">
<Bot className="w-3 h-3" />
AI Agent
@ -153,15 +153,15 @@ export default function AgentModeSelector({
</li>
<li className={cn(
"flex items-center gap-1",
value === "agent" ? "text-violet-400 font-medium" : "text-gray-500"
value === "agent" ? "text-violet-400 font-medium" : "text-muted-foreground"
)}>
<Shield className="w-3 h-3" />
</li>
</ul>
<div className="mt-auto pt-2 border-t border-gray-800">
<span className="text-[10px] uppercase tracking-wider text-gray-600 font-bold font-mono">
<div className="mt-auto pt-2 border-t border-border">
<span className="text-xs uppercase tracking-wider text-muted-foreground font-bold font-mono">
适合: 发版前审计
</span>
</div>

View File

@ -232,16 +232,16 @@ export default function CreateAgentTaskDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="!w-[min(90vw,520px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogContent className="!w-[min(90vw,520px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
{/* Header */}
<DialogHeader className="px-5 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogHeader className="px-5 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Bot className="w-5 h-5 text-primary" />
</div>
<div>
<span className="text-base font-bold uppercase tracking-wider">New Agent Audit</span>
<p className="text-xs text-gray-500 font-normal mt-0.5">
<p className="text-xs text-muted-foreground font-normal mt-0.5">
AI-Powered Security Analysis
</p>
</div>
@ -252,17 +252,17 @@ export default function CreateAgentTaskDialog({
{/* 项目选择 */}
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-xs font-mono font-bold uppercase text-gray-400">
<span className="text-xs font-mono font-bold uppercase text-muted-foreground">
Select Project
</span>
<Badge className="cyber-badge-muted font-mono text-[10px]">
<Badge className="cyber-badge-muted font-mono text-xs">
{filteredProjects.length} available
</Badge>
</div>
{/* 搜索框 */}
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
<Input
placeholder="Search projects..."
value={searchTerm}
@ -272,13 +272,13 @@ export default function CreateAgentTaskDialog({
</div>
{/* 项目列表 */}
<ScrollArea className="h-[200px] border border-gray-800 rounded bg-gray-900/30">
<ScrollArea className="h-[200px] border border-border rounded bg-muted/50">
{loadingProjects ? (
<div className="flex items-center justify-center h-full">
<Loader2 className="w-5 h-5 animate-spin text-primary" />
</div>
) : filteredProjects.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-gray-600 font-mono">
<div className="flex flex-col items-center justify-center h-full text-muted-foreground font-mono">
<Package className="w-8 h-8 mb-2 opacity-50" />
<span className="text-sm">{searchTerm ? "No matches" : "No projects"}</span>
</div>
@ -302,9 +302,9 @@ export default function CreateAgentTaskDialog({
<div className="space-y-4">
{/* 仓库项目:分支选择 */}
{isRepositoryProject(selectedProject) && (
<div className="flex items-center gap-3 p-3 border border-gray-800 rounded bg-blue-950/20">
<div className="flex items-center gap-3 p-3 border border-border rounded bg-blue-950/20">
<GitBranch className="w-5 h-5 text-blue-400" />
<span className="font-mono text-sm text-gray-400 w-16">Branch</span>
<span className="font-mono text-sm text-muted-foreground w-16">Branch</span>
{loadingBranches ? (
<div className="flex items-center gap-2 flex-1">
<Loader2 className="w-4 h-4 animate-spin text-blue-400" />
@ -315,9 +315,9 @@ export default function CreateAgentTaskDialog({
<SelectTrigger className="flex-1 h-9 cyber-input">
<SelectValue placeholder="Select branch" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{branches.map((b) => (
<SelectItem key={b} value={b} className="font-mono text-white">
<SelectItem key={b} value={b} className="font-mono text-foreground">
{b}
</SelectItem>
))}
@ -329,27 +329,27 @@ export default function CreateAgentTaskDialog({
{/* ZIP 项目:文件选择 */}
{isZipProject(selectedProject) && (
<div className="p-3 border border-gray-800 rounded bg-amber-950/20 space-y-3">
<div className="p-3 border border-border rounded bg-amber-950/20 space-y-3">
<div className="flex items-center gap-3">
<Package className="w-5 h-5 text-amber-400" />
<span className="font-mono text-sm text-gray-400 uppercase font-bold">ZIP File</span>
<span className="font-mono text-sm text-muted-foreground uppercase font-bold">ZIP File</span>
</div>
{storedZipInfo?.has_file && (
<div
className={`p-2 rounded border cursor-pointer transition-colors ${useStoredZip
? 'border-emerald-500/50 bg-emerald-950/30'
: 'border-gray-700 hover:border-gray-600 bg-gray-900/30'
: 'border-border hover:border-border bg-muted/50'
}`}
onClick={() => setUseStoredZip(true)}
>
<div className="flex items-center gap-2">
<div className={`w-3 h-3 rounded-full border-2 ${useStoredZip ? 'border-emerald-500 bg-emerald-500' : 'border-gray-600'
<div className={`w-3 h-3 rounded-full border-2 ${useStoredZip ? 'border-emerald-500 bg-emerald-500' : 'border-border'
}`} />
<span className="text-sm text-white font-mono">
<span className="text-sm text-foreground font-mono">
{storedZipInfo.original_filename}
</span>
<Badge className="cyber-badge-success text-[10px]">
<Badge className="cyber-badge-success text-xs">
Stored
</Badge>
</div>
@ -359,14 +359,14 @@ export default function CreateAgentTaskDialog({
<div
className={`p-2 rounded border cursor-pointer transition-colors ${!useStoredZip && zipFile
? 'border-amber-500/50 bg-amber-950/30'
: 'border-gray-700 hover:border-gray-600 bg-gray-900/30'
: 'border-border hover:border-border bg-muted/50'
}`}
>
<label className="flex items-center gap-2 cursor-pointer">
<div className={`w-3 h-3 rounded-full border-2 ${!useStoredZip && zipFile ? 'border-amber-500 bg-amber-500' : 'border-gray-600'
<div className={`w-3 h-3 rounded-full border-2 ${!useStoredZip && zipFile ? 'border-amber-500 bg-amber-500' : 'border-border'
}`} />
<Upload className="w-4 h-4 text-gray-500" />
<span className="text-sm text-gray-400 font-mono">
<Upload className="w-4 h-4 text-muted-foreground" />
<span className="text-sm text-muted-foreground font-mono">
{zipFile ? zipFile.name : "Upload new file..."}
</span>
<input
@ -382,7 +382,7 @@ export default function CreateAgentTaskDialog({
{/* 高级选项 */}
<Collapsible open={showAdvanced} onOpenChange={setShowAdvanced}>
<CollapsibleTrigger className="flex items-center gap-2 text-xs font-mono text-gray-500 hover:text-gray-300 transition-colors">
<CollapsibleTrigger className="flex items-center gap-2 text-xs font-mono text-muted-foreground hover:text-foreground transition-colors">
<ChevronRight className={`w-4 h-4 transition-transform ${showAdvanced ? "rotate-90" : ""}`} />
<Settings2 className="w-4 h-4" />
<span className="uppercase font-bold">Advanced Options</span>
@ -396,12 +396,12 @@ export default function CreateAgentTaskDialog({
const canSelectFiles = isRepo || (isZip && useStoredZip && hasStoredZip);
return (
<div className="flex items-center justify-between p-3 border border-dashed border-gray-700 rounded bg-gray-900/30">
<div className="flex items-center justify-between p-3 border border-dashed border-border rounded bg-muted/50">
<div>
<p className="font-mono text-xs uppercase font-bold text-gray-500">
<p className="font-mono text-xs uppercase font-bold text-muted-foreground">
Scan Scope
</p>
<p className="text-sm text-white font-mono font-bold mt-1">
<p className="text-sm text-foreground font-mono font-bold mt-1">
{selectedFiles
? `${selectedFiles.length} files selected`
: "All files"}
@ -434,9 +434,9 @@ export default function CreateAgentTaskDialog({
})()}
{/* 排除模式 */}
<div className="p-3 border border-dashed border-gray-700 rounded bg-gray-900/30 space-y-3">
<div className="p-3 border border-dashed border-border rounded bg-muted/50 space-y-3">
<div className="flex items-center justify-between">
<span className="font-mono text-xs uppercase font-bold text-gray-500">
<span className="font-mono text-xs uppercase font-bold text-muted-foreground">
Exclude Patterns
</span>
<button
@ -452,7 +452,7 @@ export default function CreateAgentTaskDialog({
{excludePatterns.map((p) => (
<Badge
key={p}
className="bg-gray-800 text-gray-300 border-0 font-mono text-xs cursor-pointer hover:bg-rose-900/50 hover:text-rose-400"
className="bg-muted text-foreground border-0 font-mono text-xs cursor-pointer hover:bg-rose-900/50 hover:text-rose-400"
onClick={() => setExcludePatterns((prev) => prev.filter((x) => x !== p))}
>
{p} ×
@ -481,12 +481,12 @@ export default function CreateAgentTaskDialog({
</div>
{/* Footer */}
<div className="flex-shrink-0 flex justify-end gap-3 px-5 py-4 bg-gray-900/50 border-t border-gray-800">
<div className="flex-shrink-0 flex justify-end gap-3 px-5 py-4 bg-muted border-t border-border">
<Button
variant="ghost"
onClick={() => onOpenChange(false)}
disabled={creating}
className="px-4 h-10 font-mono text-gray-400 hover:text-white hover:bg-gray-800"
className="px-4 h-10 font-mono text-muted-foreground hover:text-foreground hover:bg-muted"
>
Cancel
</Button>
@ -539,7 +539,7 @@ function ProjectItem({
<div
className={`flex items-center gap-3 p-3 cursor-pointer rounded transition-all ${selected
? "bg-primary/10 border border-primary/50"
: "hover:bg-gray-800/50 border border-transparent"
: "hover:bg-muted border border-transparent"
}`}
onClick={onSelect}
>
@ -553,11 +553,11 @@ function ProjectItem({
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<span className={`font-mono text-sm truncate ${selected ? 'text-white font-bold' : 'text-gray-300'}`}>
<span className={`font-mono text-sm truncate ${selected ? 'text-foreground font-bold' : 'text-foreground'}`}>
{project.name}
</span>
<Badge
className={`text-[10px] px-1 py-0 font-mono ${isRepo
className={`text-xs px-1 py-0 font-mono ${isRepo
? "bg-blue-500/20 text-blue-400 border-blue-500/30"
: "bg-amber-500/20 text-amber-400 border-amber-500/30"
}`}
@ -566,7 +566,7 @@ function ProjectItem({
</Badge>
</div>
{project.description && (
<p className="text-xs text-gray-600 mt-0.5 font-mono truncate">
<p className="text-xs text-muted-foreground mt-0.5 font-mono truncate">
{project.description}
</p>
)}

View File

@ -189,7 +189,7 @@ export default function EmbeddingConfigPanel() {
<div className="flex items-center justify-center min-h-[300px]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
@ -202,26 +202,26 @@ export default function EmbeddingConfigPanel() {
<div className="cyber-card p-4 border-primary/30">
<div className="flex items-center gap-2 mb-3">
<Server className="w-4 h-4 text-primary" />
<span className="font-mono font-bold text-sm uppercase text-gray-300"></span>
<span className="font-mono font-bold text-sm uppercase text-foreground"></span>
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
<div className="bg-gray-900/50 p-3 rounded-lg border border-gray-800">
<p className="text-xs text-gray-500 uppercase mb-1"></p>
<div className="bg-muted p-3 rounded-lg border border-border">
<p className="text-xs text-muted-foreground uppercase mb-1"></p>
<Badge className="bg-primary/20 text-primary border-primary/50 font-mono">
{currentConfig.provider}
</Badge>
</div>
<div className="bg-gray-900/50 p-3 rounded-lg border border-gray-800">
<p className="text-xs text-gray-500 uppercase mb-1"></p>
<p className="font-mono text-sm text-gray-300 truncate">{currentConfig.model}</p>
<div className="bg-muted p-3 rounded-lg border border-border">
<p className="text-xs text-muted-foreground uppercase mb-1"></p>
<p className="font-mono text-sm text-foreground truncate">{currentConfig.model}</p>
</div>
<div className="bg-gray-900/50 p-3 rounded-lg border border-gray-800">
<p className="text-xs text-gray-500 uppercase mb-1"></p>
<p className="font-mono text-sm text-gray-300">{currentConfig.dimensions}</p>
<div className="bg-muted p-3 rounded-lg border border-border">
<p className="text-xs text-muted-foreground uppercase mb-1"></p>
<p className="font-mono text-sm text-foreground">{currentConfig.dimensions}</p>
</div>
<div className="bg-gray-900/50 p-3 rounded-lg border border-gray-800">
<p className="text-xs text-gray-500 uppercase mb-1"></p>
<p className="font-mono text-sm text-gray-300">{currentConfig.batch_size}</p>
<div className="bg-muted p-3 rounded-lg border border-border">
<p className="text-xs text-muted-foreground uppercase mb-1"></p>
<p className="font-mono text-sm text-foreground">{currentConfig.batch_size}</p>
</div>
</div>
</div>
@ -231,12 +231,12 @@ export default function EmbeddingConfigPanel() {
<div className="cyber-card p-6 space-y-6">
{/* 提供商选择 */}
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={selectedProvider} onValueChange={handleProviderChange}>
<SelectTrigger className="h-12 cyber-input">
<SelectValue placeholder="选择提供商" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{providers.map((provider) => (
<SelectItem key={provider.id} value={provider.id} className="font-mono">
<div className="flex items-center gap-2">
@ -253,7 +253,7 @@ export default function EmbeddingConfigPanel() {
</Select>
{selectedProviderInfo && (
<p className="text-xs text-gray-500 flex items-center gap-1">
<p className="text-xs text-muted-foreground flex items-center gap-1">
<Info className="w-3 h-3 text-sky-400" />
{selectedProviderInfo.description}
</p>
@ -263,7 +263,7 @@ export default function EmbeddingConfigPanel() {
{/* 模型选择/输入 */}
{selectedProviderInfo && (
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input
type="text"
value={selectedModel}
@ -273,7 +273,7 @@ export default function EmbeddingConfigPanel() {
/>
{selectedProviderInfo.models.length > 0 && (
<div className="flex flex-wrap gap-2 mt-2">
<span className="text-xs text-gray-500"></span>
<span className="text-xs text-muted-foreground"></span>
{selectedProviderInfo.models.map((model) => (
<button
key={model}
@ -282,7 +282,7 @@ export default function EmbeddingConfigPanel() {
className={`px-2 py-1 text-xs font-mono rounded border transition-colors ${
selectedModel === model
? "bg-primary/20 border-primary/50 text-primary"
: "bg-gray-800/50 border-gray-700 text-gray-400 hover:border-gray-600 hover:text-gray-300"
: "bg-muted border-border text-muted-foreground hover:border-border hover:text-foreground"
}`}
>
{model}
@ -296,7 +296,7 @@ export default function EmbeddingConfigPanel() {
{/* API Key */}
{selectedProviderInfo?.requires_api_key && (
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">
<Label className="text-xs font-bold text-muted-foreground uppercase">
API Key
<span className="text-rose-400 ml-1">*</span>
</Label>
@ -307,7 +307,7 @@ export default function EmbeddingConfigPanel() {
placeholder="输入 API Key"
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600">
<p className="text-xs text-muted-foreground">
API Key
</p>
</div>
@ -315,8 +315,8 @@ export default function EmbeddingConfigPanel() {
{/* 自定义端点 */}
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">
API <span className="text-gray-600">()</span>
<Label className="text-xs font-bold text-muted-foreground uppercase">
API <span className="text-muted-foreground">()</span>
</Label>
<Input
type="url"
@ -335,14 +335,14 @@ export default function EmbeddingConfigPanel() {
}
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600">
<p className="text-xs text-muted-foreground">
API
</p>
</div>
{/* 批处理大小 */}
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input
type="number"
value={batchSize}
@ -351,7 +351,7 @@ export default function EmbeddingConfigPanel() {
max={500}
className="h-10 cyber-input w-32"
/>
<p className="text-xs text-gray-600">
<p className="text-xs text-muted-foreground">
50-100
</p>
</div>
@ -379,14 +379,14 @@ export default function EmbeddingConfigPanel() {
{testResult.success ? "测试成功" : "测试失败"}
</span>
</div>
<p className="text-sm text-gray-400">{testResult.message}</p>
<p className="text-sm text-muted-foreground">{testResult.message}</p>
{testResult.success && (
<div className="mt-3 pt-3 border-t border-gray-800 text-xs text-gray-500 space-y-1 font-mono">
<div>: <span className="text-gray-300">{testResult.dimensions}</span></div>
<div>: <span className="text-gray-300">{testResult.latency_ms}ms</span></div>
<div className="mt-3 pt-3 border-t border-border text-xs text-muted-foreground space-y-1 font-mono">
<div>: <span className="text-foreground">{testResult.dimensions}</span></div>
<div>: <span className="text-foreground">{testResult.latency_ms}ms</span></div>
{testResult.sample_embedding && (
<div className="truncate">
: <span className="text-gray-400">[{testResult.sample_embedding.slice(0, 5).map((v) => v.toFixed(4)).join(", ")}...]</span>
: <span className="text-muted-foreground">[{testResult.sample_embedding.slice(0, 5).map((v) => v.toFixed(4)).join(", ")}...]</span>
</div>
)}
</div>
@ -395,7 +395,7 @@ export default function EmbeddingConfigPanel() {
)}
{/* 操作按钮 */}
<div className="flex items-center gap-3 pt-4 border-t border-gray-800 border-dashed">
<div className="flex items-center gap-3 pt-4 border-t border-border border-dashed">
<Button
onClick={handleTest}
disabled={testing || !selectedProvider || !selectedModel}
@ -434,15 +434,15 @@ export default function EmbeddingConfigPanel() {
</div>
{/* 说明 */}
<div className="bg-gray-900/50 border border-gray-800 p-4 rounded-lg text-xs space-y-2">
<p className="font-bold uppercase text-gray-400 flex items-center gap-2">
<div className="bg-muted border border-border p-4 rounded-lg text-xs space-y-2">
<p className="font-bold uppercase text-muted-foreground flex items-center gap-2">
<Info className="w-4 h-4 text-sky-400" />
</p>
<ul className="text-gray-500 space-y-1 ml-6">
<ul className="text-muted-foreground space-y-1 ml-6">
<li> Agent (RAG)</li>
<li> 使 LLM </li>
<li> 使 <span className="text-gray-300">OpenAI text-embedding-3-small</span> <span className="text-gray-300">Ollama</span></li>
<li> 使 <span className="text-foreground">OpenAI text-embedding-3-small</span> <span className="text-foreground">Ollama</span></li>
<li> </li>
</ul>
</div>

View File

@ -305,16 +305,16 @@ export default function CreateTaskDialog({
return (
<>
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="!w-[min(90vw,520px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogContent className="!w-[min(90vw,520px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
{/* Header */}
<DialogHeader className="px-5 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogHeader className="px-5 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Shield className="w-5 h-5 text-primary" />
</div>
<div>
<span className="text-base font-bold uppercase tracking-wider"></span>
<p className="text-xs text-gray-500 font-normal mt-0.5">
<p className="text-xs text-muted-foreground font-normal mt-0.5">
Code Security Analysis
</p>
</div>
@ -325,17 +325,17 @@ export default function CreateTaskDialog({
{/* 项目选择 */}
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-xs font-mono font-bold uppercase text-gray-400">
<span className="text-sm font-mono font-bold uppercase text-muted-foreground">
</span>
<Badge className="cyber-badge-muted font-mono text-[10px]">
<Badge className="cyber-badge-muted font-mono text-xs">
{filteredProjects.length}
</Badge>
</div>
{/* 搜索框 */}
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
<Input
placeholder="搜索项目..."
value={searchTerm}
@ -345,13 +345,13 @@ export default function CreateTaskDialog({
</div>
{/* 项目列表 */}
<ScrollArea className="h-[180px] border border-gray-800 rounded bg-gray-900/30">
<ScrollArea className="h-[180px] border border-border rounded bg-muted/50">
{loading ? (
<div className="flex items-center justify-center h-full">
<Loader2 className="w-5 h-5 animate-spin text-primary" />
</div>
) : filteredProjects.length === 0 ? (
<div className="flex flex-col items-center justify-center h-full text-gray-600 font-mono">
<div className="flex flex-col items-center justify-center h-full text-muted-foreground font-mono">
<Package className="w-8 h-8 mb-2 opacity-50" />
<span className="text-sm">
{searchTerm ? "未找到" : "暂无项目"}
@ -384,14 +384,14 @@ export default function CreateTaskDialog({
{/* 配置区域 */}
{selectedProject && (
<div className="space-y-4">
<span className="text-xs font-mono font-bold uppercase text-gray-400">
<span className="text-sm font-mono font-bold uppercase text-muted-foreground">
</span>
{isRepositoryProject(selectedProject) ? (
<div className="flex items-center gap-3 p-3 border border-gray-800 rounded bg-blue-950/20">
<div className="flex items-center gap-3 p-3 border border-border rounded bg-blue-950/20">
<GitBranch className="w-5 h-5 text-blue-400" />
<span className="font-mono text-sm text-gray-400 w-12">
<span className="font-mono text-base text-muted-foreground w-12">
</span>
{loadingBranches ? (
@ -404,7 +404,7 @@ export default function CreateTaskDialog({
<SelectTrigger className="h-9 flex-1 cyber-input">
<SelectValue placeholder="选择分支" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{branches.map((b) => (
<SelectItem key={b} value={b} className="font-mono">
{b}
@ -438,19 +438,19 @@ export default function CreateTaskDialog({
{/* 规则集和提示词选择 - 仅快速扫描模式显示 */}
{auditMode !== "agent" && (
<div className="p-3 border border-gray-800 rounded bg-violet-950/20 space-y-3">
<div className="p-3 border border-border rounded bg-violet-950/20 space-y-3">
<div className="flex items-center gap-2 mb-2">
<Zap className="w-4 h-4 text-violet-400" />
<span className="font-mono text-sm font-bold text-violet-300 uppercase"></span>
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<label className="block text-xs font-mono font-bold text-gray-500 mb-1 uppercase"></label>
<label className="block text-xs font-mono font-bold text-muted-foreground mb-1 uppercase"></label>
<Select value={selectedRuleSetId} onValueChange={setSelectedRuleSetId}>
<SelectTrigger className="h-9 cyber-input text-xs">
<SelectValue placeholder="选择规则集" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{ruleSets.map((rs) => (
<SelectItem key={rs.id} value={rs.id} className="font-mono text-xs">
{rs.name} {rs.is_default && '(默认)'} ({rs.enabled_rules_count})
@ -460,12 +460,12 @@ export default function CreateTaskDialog({
</Select>
</div>
<div>
<label className="block text-xs font-mono font-bold text-gray-500 mb-1 uppercase"></label>
<label className="block text-xs font-mono font-bold text-muted-foreground mb-1 uppercase"></label>
<Select value={selectedPromptTemplateId} onValueChange={setSelectedPromptTemplateId}>
<SelectTrigger className="h-9 cyber-input text-xs">
<SelectValue placeholder="选择提示词模板" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{promptTemplates.map((pt) => (
<SelectItem key={pt.id} value={pt.id} className="font-mono text-xs">
{pt.name} {pt.is_default && '(默认)'}
@ -480,7 +480,7 @@ export default function CreateTaskDialog({
{/* 高级选项 */}
<Collapsible open={showAdvanced} onOpenChange={setShowAdvanced}>
<CollapsibleTrigger className="flex items-center gap-2 text-xs font-mono text-gray-500 hover:text-gray-300 transition-colors">
<CollapsibleTrigger className="flex items-center gap-2 text-xs font-mono text-muted-foreground hover:text-foreground transition-colors">
<ChevronRight
className={`w-4 h-4 transition-transform ${showAdvanced ? "rotate-90" : ""}`}
/>
@ -489,9 +489,9 @@ export default function CreateTaskDialog({
</CollapsibleTrigger>
<CollapsibleContent className="mt-3 space-y-3">
{/* 排除模式 */}
<div className="p-3 border border-dashed border-gray-700 rounded bg-gray-900/30 space-y-3">
<div className="p-3 border border-dashed border-border rounded bg-muted/50 space-y-3">
<div className="flex items-center justify-between">
<span className="font-mono text-xs uppercase font-bold text-gray-500">
<span className="font-mono text-xs uppercase font-bold text-muted-foreground">
</span>
<button
@ -507,7 +507,7 @@ export default function CreateTaskDialog({
{excludePatterns.map((p) => (
<Badge
key={p}
className="bg-gray-800 text-gray-300 border-0 font-mono text-xs cursor-pointer hover:bg-rose-900/50 hover:text-rose-400"
className="bg-muted text-foreground border-0 font-mono text-xs cursor-pointer hover:bg-rose-900/50 hover:text-rose-400"
onClick={() =>
setExcludePatterns((prev) =>
prev.filter((x) => x !== p)
@ -518,12 +518,12 @@ export default function CreateTaskDialog({
</Badge>
))}
{excludePatterns.length === 0 && (
<span className="text-xs text-gray-600 font-mono"></span>
<span className="text-xs text-muted-foreground font-mono"></span>
)}
</div>
<div className="flex flex-wrap gap-1">
<span className="text-xs text-gray-600 font-mono mr-1">:</span>
<span className="text-xs text-muted-foreground font-mono mr-1">:</span>
{[".test.", ".spec.", ".min.", "coverage/", "docs/", ".md"].map((pattern) => (
<button
key={pattern}
@ -534,7 +534,7 @@ export default function CreateTaskDialog({
setExcludePatterns((prev) => [...prev, pattern]);
}
}}
className="text-xs font-mono px-1.5 py-0.5 border border-gray-700 bg-gray-800 hover:bg-gray-700 text-gray-400 hover:text-white disabled:opacity-40 disabled:cursor-not-allowed rounded"
className="text-xs font-mono px-1.5 py-0.5 border border-border bg-muted hover:bg-muted text-muted-foreground hover:text-foreground disabled:opacity-40 disabled:cursor-not-allowed rounded"
>
+{pattern}
</button>
@ -565,12 +565,12 @@ export default function CreateTaskDialog({
const canSelectFiles = isRepo || (isZip && useStored && hasStoredZip);
return (
<div className="flex items-center justify-between p-3 border border-dashed border-gray-700 rounded bg-gray-900/30">
<div className="flex items-center justify-between p-3 border border-dashed border-border rounded bg-muted/50">
<div>
<p className="font-mono text-xs uppercase font-bold text-gray-500">
<p className="font-mono text-xs uppercase font-bold text-muted-foreground">
</p>
<p className="text-sm font-bold text-white mt-1">
<p className="text-sm font-bold text-foreground mt-1">
{selectedFiles
? `已选 ${selectedFiles.length} 个文件`
: "全部文件"}
@ -608,12 +608,12 @@ export default function CreateTaskDialog({
</div>
{/* Footer */}
<div className="flex-shrink-0 flex justify-end gap-3 px-5 py-4 bg-gray-900/50 border-t border-gray-800">
<div className="flex-shrink-0 flex justify-end gap-3 px-5 py-4 bg-muted border-t border-border">
<Button
variant="ghost"
onClick={() => onOpenChange(false)}
disabled={creating}
className="px-4 h-10 font-mono text-gray-400 hover:text-white hover:bg-gray-800"
className="px-4 h-10 font-mono text-muted-foreground hover:text-foreground hover:bg-muted"
>
</Button>
@ -670,13 +670,13 @@ function ProjectCard({
<div
className={`flex items-center gap-3 p-3 cursor-pointer rounded transition-all ${selected
? "bg-primary/10 border border-primary/50"
: "hover:bg-gray-800/50 border border-transparent"
: "hover:bg-muted border border-transparent"
}`}
onClick={onSelect}
>
<Checkbox
checked={selected}
className="border-gray-600 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
className="border-border data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
<div className={`p-1.5 rounded ${isRepo ? "bg-blue-500/20" : "bg-amber-500/20"}`}>
@ -689,11 +689,11 @@ function ProjectCard({
<div className="flex-1 min-w-0 overflow-hidden">
<div className="flex items-center gap-2">
<span className={`font-mono text-sm truncate ${selected ? 'text-white font-bold' : 'text-gray-300'}`}>
<span className={`font-mono text-base truncate ${selected ? 'text-foreground font-bold' : 'text-foreground'}`}>
{project.name}
</span>
<Badge
className={`text-[10px] px-1 py-0 font-mono ${isRepo
className={`text-xs px-1 py-0 font-mono ${isRepo
? "bg-blue-500/20 text-blue-400 border-blue-500/30"
: "bg-amber-500/20 text-amber-400 border-amber-500/30"
}`}
@ -702,7 +702,7 @@ function ProjectCard({
</Badge>
</div>
{project.description && (
<p className="text-xs text-gray-600 mt-0.5 font-mono line-clamp-2" title={project.description}>
<p className="text-sm text-muted-foreground mt-0.5 font-mono line-clamp-2" title={project.description}>
{project.description}
</p>
)}
@ -722,7 +722,7 @@ function ZipUploadCard({
}) {
if (zipState.loading) {
return (
<div className="flex items-center gap-3 p-3 border border-gray-800 rounded bg-blue-950/20">
<div className="flex items-center gap-3 p-3 border border-border rounded bg-blue-950/20">
<Loader2 className="w-5 h-5 animate-spin text-blue-400" />
<span className="text-sm font-mono text-blue-400">
...
@ -733,7 +733,7 @@ function ZipUploadCard({
if (zipState.storedZipInfo?.has_file) {
return (
<div className="p-3 border border-gray-800 rounded bg-emerald-950/20 space-y-3">
<div className="p-3 border border-border rounded bg-emerald-950/20 space-y-3">
<div className="flex items-center gap-3">
<div className="p-1.5 bg-emerald-500/20 rounded">
<Package className="w-4 h-4 text-emerald-400" />

View File

@ -72,7 +72,7 @@ const getFileIcon = (path: string) => {
if (configExts.includes(ext)) {
return <FileJson className="w-4 h-4 text-amber-400" />;
}
return <File className="w-4 h-4 text-gray-500" />;
return <File className="w-4 h-4 text-muted-foreground" />;
};
// 获取文件扩展名
@ -326,7 +326,7 @@ export default function FileSelectionDialog({
items.push(
<div key={`folder-${folder.path}`}>
<div
className="flex items-center space-x-2 p-2 hover:bg-gray-800/50 border border-transparent hover:border-gray-700 cursor-pointer transition-colors rounded"
className="flex items-center space-x-2 p-2 hover:bg-muted border border-transparent hover:border-border cursor-pointer transition-colors rounded"
style={{ paddingLeft: `${depth * 16 + 8}px` }}
>
<button
@ -334,12 +334,12 @@ export default function FileSelectionDialog({
e.stopPropagation();
handleExpandFolder(folder.path);
}}
className="p-0.5 hover:bg-gray-700 rounded"
className="p-0.5 hover:bg-muted rounded"
>
{isExpanded ? (
<ChevronDown className="w-4 h-4 text-gray-500" />
<ChevronDown className="w-4 h-4 text-muted-foreground" />
) : (
<ChevronRight className="w-4 h-4 text-gray-500" />
<ChevronRight className="w-4 h-4 text-muted-foreground" />
)}
</button>
<div onClick={(e) => e.stopPropagation()}>
@ -352,7 +352,7 @@ export default function FileSelectionDialog({
}
}}
onCheckedChange={() => handleToggleFolder(folder.path)}
className="border-gray-600 data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=indeterminate]:bg-gray-500"
className="border-border data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=indeterminate]:bg-background0"
/>
</div>
{isExpanded ? (
@ -361,12 +361,12 @@ export default function FileSelectionDialog({
<Folder className="w-4 h-4 text-amber-400" />
)}
<span
className="text-sm font-mono font-medium flex-1 text-gray-300"
className="text-sm font-mono font-medium flex-1 text-foreground"
onClick={() => handleExpandFolder(folder.path)}
>
{folder.name}
</span>
<Badge className="cyber-badge-muted font-mono text-[10px]">
<Badge className="cyber-badge-muted font-mono text-xs">
{
filteredFiles.filter((f) =>
f.path.startsWith(folder.path + "/")
@ -387,7 +387,7 @@ export default function FileSelectionDialog({
items.push(
<div
key={`file-${file.path}`}
className="flex items-center space-x-3 p-2 hover:bg-gray-800/50 border border-transparent hover:border-gray-700 cursor-pointer transition-colors rounded"
className="flex items-center space-x-3 p-2 hover:bg-muted border border-transparent hover:border-border cursor-pointer transition-colors rounded"
style={{ paddingLeft: `${depth * 16 + 32}px` }}
onClick={() => handleToggleFile(file.path)}
>
@ -395,18 +395,18 @@ export default function FileSelectionDialog({
<Checkbox
checked={selectedFiles.has(file.path)}
onCheckedChange={() => handleToggleFile(file.path)}
className="border-gray-600 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
className="border-border data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
</div>
{getFileIcon(file.path)}
<span
className="text-sm font-mono flex-1 min-w-0 truncate text-gray-300"
className="text-sm font-mono flex-1 min-w-0 truncate text-foreground"
title={file.path}
>
{fileName}
</span>
{file.size > 0 && (
<Badge className="cyber-badge-muted font-mono text-[10px] flex-shrink-0">
<Badge className="cyber-badge-muted font-mono text-xs flex-shrink-0">
{formatSize(file.size)}
</Badge>
)}
@ -422,24 +422,24 @@ export default function FileSelectionDialog({
return filteredFiles.map((file) => (
<div
key={file.path}
className="flex items-center space-x-3 p-2 hover:bg-gray-800/50 border border-transparent hover:border-gray-700 cursor-pointer transition-colors rounded"
className="flex items-center space-x-3 p-2 hover:bg-muted border border-transparent hover:border-border cursor-pointer transition-colors rounded"
onClick={() => handleToggleFile(file.path)}
>
<div onClick={(e) => e.stopPropagation()}>
<Checkbox
checked={selectedFiles.has(file.path)}
onCheckedChange={() => handleToggleFile(file.path)}
className="border-gray-600 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
className="border-border data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
</div>
{getFileIcon(file.path)}
<div className="flex-1 min-w-0">
<p className="text-sm font-mono truncate text-gray-300" title={file.path}>
<p className="text-sm font-mono truncate text-foreground" title={file.path}>
{file.path}
</p>
</div>
{file.size > 0 && (
<Badge className="cyber-badge-muted font-mono text-[10px] flex-shrink-0">
<Badge className="cyber-badge-muted font-mono text-xs flex-shrink-0">
{formatSize(file.size)}
</Badge>
)}
@ -449,11 +449,11 @@ export default function FileSelectionDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="!max-w-[1000px] !w-[95vw] max-h-[85vh] flex flex-col cyber-card p-0 bg-[#0c0c12] !fixed">
<DialogContent className="!max-w-[1000px] !w-[95vw] max-h-[85vh] flex flex-col cyber-card p-0 cyber-dialog !fixed">
<DialogHeader className="cyber-card-header flex-shrink-0">
<div className="flex items-center gap-3">
<FolderOpen className="w-5 h-5 text-primary" />
<DialogTitle className="text-lg font-bold uppercase tracking-wider text-white">
<DialogTitle className="text-lg font-bold uppercase tracking-wider text-foreground">
</DialogTitle>
</div>
@ -469,7 +469,7 @@ export default function FileSelectionDialog({
<div className="flex items-center gap-2 flex-wrap">
{/* 搜索框 */}
<div className="relative flex-1 min-w-[200px]">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 w-4 h-4" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4" />
<Input
placeholder="搜索文件..."
value={searchTerm}
@ -481,11 +481,11 @@ export default function FileSelectionDialog({
{/* 文件类型筛选 */}
{fileTypes.length > 0 && (
<div className="flex items-center gap-1">
<Filter className="w-4 h-4 text-gray-500" />
<Filter className="w-4 h-4 text-muted-foreground" />
<select
value={filterType}
onChange={(e) => setFilterType(e.target.value)}
className="h-9 px-2 cyber-input font-mono text-sm bg-[#0a0a0f]"
className="h-9 px-2 cyber-input font-mono text-sm cyber-bg-elevated"
>
<option value=""></option>
{fileTypes.slice(0, 10).map(([ext, count]) => (
@ -498,16 +498,16 @@ export default function FileSelectionDialog({
)}
{/* 视图切换 */}
<div className="flex border border-gray-700 rounded overflow-hidden">
<div className="flex border border-border rounded overflow-hidden">
<button
onClick={() => setViewMode("tree")}
className={`px-3 py-1.5 text-xs font-mono uppercase ${viewMode === "tree" ? "bg-primary text-white" : "bg-gray-800 text-gray-400 hover:bg-gray-700"}`}
className={`px-3 py-1.5 text-xs font-mono uppercase ${viewMode === "tree" ? "bg-primary text-foreground" : "bg-muted text-muted-foreground hover:bg-muted"}`}
>
</button>
<button
onClick={() => setViewMode("flat")}
className={`px-3 py-1.5 text-xs font-mono uppercase border-l border-gray-700 ${viewMode === "flat" ? "bg-primary text-white" : "bg-gray-800 text-gray-400 hover:bg-gray-700"}`}
className={`px-3 py-1.5 text-xs font-mono uppercase border-l border-border ${viewMode === "flat" ? "bg-primary text-foreground" : "bg-muted text-muted-foreground hover:bg-muted"}`}
>
</button>
@ -552,14 +552,14 @@ export default function FileSelectionDialog({
setSearchTerm("");
setFilterType("");
}}
className="h-8 px-3 cyber-btn-outline font-mono text-xs text-gray-400"
className="h-8 px-3 cyber-btn-outline font-mono text-xs text-muted-foreground"
>
<RotateCcw className="w-3 h-3 mr-1" />
</Button>
)}
</div>
<div className="text-sm font-mono text-gray-500">
<div className="text-sm font-mono text-muted-foreground">
{searchTerm || filterType ? (
<span>
: {filteredFiles.length}/{files.length}
@ -574,7 +574,7 @@ export default function FileSelectionDialog({
</div>
{/* 文件列表 */}
<div className="border border-gray-800 bg-[#0a0a0f] relative h-[450px] overflow-hidden rounded">
<div className="border border-border cyber-bg-elevated relative h-[450px] overflow-hidden rounded">
{loading ? (
<div className="absolute inset-0 flex items-center justify-center">
<div className="loading-spinner" />
@ -588,7 +588,7 @@ export default function FileSelectionDialog({
</div>
</div>
) : (
<div className="absolute inset-0 flex flex-col items-center justify-center text-gray-500">
<div className="absolute inset-0 flex flex-col items-center justify-center text-muted-foreground">
<FileText className="w-12 h-12 mb-2 opacity-20" />
<p className="font-mono text-sm">
{searchTerm || filterType
@ -600,8 +600,8 @@ export default function FileSelectionDialog({
</div>
</div>
<DialogFooter className="p-5 border-t border-gray-800 bg-gray-900/50 flex-shrink-0 flex justify-between">
<div className="text-xs font-mono text-gray-600 flex items-center gap-2">
<DialogFooter className="p-5 border-t border-border bg-muted flex-shrink-0 flex justify-between">
<div className="text-xs font-mono text-muted-foreground flex items-center gap-2">
<Terminal className="w-3 h-3" />
/
</div>

View File

@ -425,7 +425,7 @@ export default function TerminalProgressDialog({
case "warning":
return "text-amber-400";
default:
return "text-gray-400";
return "text-muted-foreground";
}
};
@ -462,13 +462,13 @@ export default function TerminalProgressDialog({
/>
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 bg-[#0a0c10] border-b border-[#1a2535]"
<div className="flex items-center justify-between px-4 py-3 cyber-bg-elevated border-b border-[#1a2535]"
style={{ backgroundImage: "linear-gradient(90deg, rgba(255, 95, 31, 0.05) 0%, transparent 50%, rgba(14, 181, 196, 0.05) 100%)" }}>
<div className="flex items-center gap-3">
<Terminal className="w-5 h-5 text-primary" style={{ filter: "drop-shadow(0 0 8px rgba(255, 95, 31, 0.5))" }} />
<div>
<span className="text-lg font-bold uppercase tracking-[0.15em] text-[#f0e6d3]" style={{ textShadow: "0 0 20px rgba(255, 95, 31, 0.3)" }}>AUDIT_TERMINAL</span>
<span className="text-[10px] text-[#5a6577] ml-2 tracking-wider">v3.0</span>
<span className="text-xs text-[#5a6577] ml-2 tracking-wider">v3.0</span>
</div>
</div>
@ -501,16 +501,16 @@ export default function TerminalProgressDialog({
{/* Left Sidebar - Task Info */}
<div className="w-48 p-4 border-r border-[#1a2535] bg-[#060810] flex flex-col gap-4">
<div className="space-y-1.5">
<div className="text-[9px] font-bold text-[#5a6577] uppercase tracking-[0.15em]">Task ID</div>
<div className="text-xs font-mono text-primary truncate bg-[#0a0c10] p-2.5 rounded border border-[#1a2535]"
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Task ID</div>
<div className="text-xs font-mono text-primary truncate cyber-bg-elevated p-2.5 rounded border border-[#1a2535]"
style={{ textShadow: "0 0 10px rgba(255, 95, 31, 0.3)" }}>
{taskId?.slice(0, 8)}...
</div>
</div>
<div className="space-y-1.5">
<div className="text-[9px] font-bold text-[#5a6577] uppercase tracking-[0.15em]">Type</div>
<div className="flex items-center gap-2 bg-[#0a0c10] p-2.5 rounded border border-[#1a2535]">
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Type</div>
<div className="flex items-center gap-2 cyber-bg-elevated p-2.5 rounded border border-[#1a2535]">
{taskType === 'repository'
? <Cpu className="w-3.5 h-3.5 text-[#22d3ee]" style={{ filter: "drop-shadow(0 0 6px rgba(34, 211, 238, 0.5))" }} />
: <HardDrive className="w-3.5 h-3.5 text-[#fbbf24]" style={{ filter: "drop-shadow(0 0 6px rgba(251, 191, 36, 0.5))" }} />}
@ -522,7 +522,7 @@ export default function TerminalProgressDialog({
{/* Status Badge */}
<div className="space-y-2">
<div className="text-[9px] font-bold text-[#5a6577] uppercase tracking-[0.15em]">Status</div>
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Status</div>
{isCancelled ? (
<Badge className="w-full justify-center cyber-badge-warning">CANCELLED</Badge>
) : isCompleted ? (
@ -566,7 +566,7 @@ export default function TerminalProgressDialog({
</div>
{/* Bottom Controls */}
<div className="h-14 px-4 border-t border-[#1a2535] bg-[#0a0c10]/90 flex items-center justify-between">
<div className="h-14 px-4 border-t border-[#1a2535] cyber-bg-elevated/90 flex items-center justify-between">
<div className="flex items-center gap-2 text-xs text-[#6a7587] font-mono tracking-wide">
<Activity className="w-3.5 h-3.5" />
<span>
@ -580,7 +580,7 @@ export default function TerminalProgressDialog({
size="sm"
variant="outline"
onClick={handleCancel}
className="h-8 bg-transparent border-[#fbbf24]/40 text-[#fbbf24] hover:bg-[#fbbf24]/10 hover:border-[#fbbf24]/60 font-mono uppercase tracking-wider text-[10px]"
className="h-8 bg-transparent border-[#fbbf24]/40 text-[#fbbf24] hover:bg-[#fbbf24]/10 hover:border-[#fbbf24]/60 font-mono uppercase tracking-wider text-xs"
>
<AlertTriangle className="w-3 h-3 mr-1.5" />
@ -592,7 +592,7 @@ export default function TerminalProgressDialog({
size="sm"
variant="outline"
onClick={() => window.open('/logs', '_blank')}
className="h-8 bg-transparent border-[#6a7587]/40 text-[#a8b0c0] hover:bg-[#1a2030]/50 hover:border-[#6a7587]/60 font-mono uppercase tracking-wider text-[10px]"
className="h-8 bg-transparent border-[#6a7587]/40 text-[#a8b0c0] hover:bg-[#1a2030]/50 hover:border-[#6a7587]/60 font-mono uppercase tracking-wider text-xs"
>
<Activity className="w-3 h-3 mr-1.5" />
@ -603,7 +603,7 @@ export default function TerminalProgressDialog({
<Button
size="sm"
onClick={() => onOpenChange(false)}
className="h-8 cyber-btn-primary font-mono uppercase tracking-wider text-[10px]"
className="h-8 cyber-btn-primary font-mono uppercase tracking-wider text-xs"
>
<CheckCircle2 className="w-3 h-3 mr-1.5" />

View File

@ -30,7 +30,7 @@ export default function AdvancedOptions({
<div className="space-y-6">
<div>
<Label className="text-base font-bold uppercase"></Label>
<p className="text-sm text-gray-500 mt-1 font-bold">
<p className="text-sm text-muted-foreground mt-1 font-bold">
</p>
</div>
@ -83,11 +83,11 @@ export default function AdvancedOptions({
>
<SelectTrigger
id="analysis_depth"
className="retro-input h-10 rounded-none border-2 border-black shadow-none focus:ring-0"
className="retro-input h-10 rounded-none border-2 border-border shadow-none focus:ring-0"
>
<SelectValue />
</SelectTrigger>
<SelectContent className="rounded-none border-2 border-black shadow-[4px_4px_0px_0px_rgba(0,0,0,1)]">
<SelectContent className="rounded-none border-2 border-border shadow-[4px_4px_0px_0px_rgba(0,0,0,1)]">
<SelectItem value="basic" className="font-mono">
()
</SelectItem>
@ -104,16 +104,16 @@ export default function AdvancedOptions({
</div>
{/* 分析范围 */}
<div className="space-y-2 border-t-2 border-dashed border-gray-300 pt-4">
<div className="space-y-2 border-t-2 border-dashed border-border pt-4">
<Label className="font-bold uppercase"></Label>
<div className="flex items-center justify-between p-3 border-2 border-black bg-white">
<div className="flex items-center justify-between p-3 border-2 border-border bg-background">
<div>
<p className="text-sm font-bold uppercase">
{hasSelectedFiles
? `已选择 ${scanConfig.file_paths!.length} 个文件`
: "全量扫描 (所有文件)"}
</p>
<p className="text-xs text-gray-500 font-bold">
<p className="text-xs text-muted-foreground font-bold">
{hasSelectedFiles
? "仅分析选中的文件"
: "分析项目中的所有代码文件"}
@ -126,7 +126,7 @@ export default function AdvancedOptions({
variant="outline"
size="sm"
onClick={() => onUpdate({ file_paths: undefined })}
className="retro-btn bg-white text-red-600 hover:bg-red-50 h-8"
className="retro-btn bg-background text-red-600 hover:bg-red-50 h-8"
>
</Button>
@ -136,7 +136,7 @@ export default function AdvancedOptions({
variant="outline"
size="sm"
onClick={onOpenFileSelection}
className="retro-btn bg-white text-black hover:bg-gray-50 h-8"
className="retro-btn bg-background text-foreground hover:bg-background h-8"
>
{hasSelectedFiles ? "修改选择" : "选择文件"}
</Button>
@ -162,15 +162,15 @@ function CheckboxOption({
description: string;
}) {
return (
<div className="flex items-center space-x-3 p-3 border-2 border-black bg-white">
<div className="flex items-center space-x-3 p-3 border-2 border-border bg-background">
<Checkbox
checked={checked}
onCheckedChange={(c) => onChange(!!c)}
className="rounded-none border-2 border-black data-[state=checked]:bg-primary data-[state=checked]:text-white"
className="rounded-none border-2 border-border data-[state=checked]:bg-primary data-[state=checked]:text-foreground"
/>
<div>
<p className="text-sm font-bold uppercase">{label}</p>
<p className="text-xs text-gray-500 font-bold">{description}</p>
<p className="text-xs text-muted-foreground font-bold">{description}</p>
</div>
</div>
);
@ -178,7 +178,7 @@ function CheckboxOption({
function DepthExplanation() {
return (
<div className="bg-amber-50 border-2 border-black p-4 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)]">
<div className="bg-amber-50 border-2 border-border p-4 shadow-[4px_4px_0px_0px_rgba(0,0,0,1)]">
<div className="flex items-start space-x-3">
<AlertCircle className="w-5 h-5 text-amber-600 mt-0.5" />
<div className="text-sm font-mono">

View File

@ -36,7 +36,7 @@ export default function ExcludePatterns({
<div className="space-y-4">
<div>
<Label className="text-base font-bold uppercase"></Label>
<p className="text-sm text-gray-500 mt-1 font-bold">
<p className="text-sm text-muted-foreground mt-1 font-bold">
</p>
</div>
@ -46,16 +46,16 @@ export default function ExcludePatterns({
{COMMON_EXCLUDE_PATTERNS.map((pattern) => (
<div
key={pattern.value}
className="flex items-center space-x-3 p-3 border-2 border-black bg-white hover:bg-gray-50 transition-all"
className="flex items-center space-x-3 p-3 border-2 border-border bg-background hover:bg-background transition-all"
>
<Checkbox
checked={patterns.includes(pattern.value)}
onCheckedChange={() => onToggle(pattern.value)}
className="rounded-none border-2 border-black data-[state=checked]:bg-primary data-[state=checked]:text-white"
className="rounded-none border-2 border-border data-[state=checked]:bg-primary data-[state=checked]:text-foreground"
/>
<div className="flex-1">
<p className="text-sm font-bold uppercase">{pattern.label}</p>
<p className="text-xs text-gray-500 font-bold">
<p className="text-xs text-muted-foreground font-bold">
{pattern.description}
</p>
</div>
@ -103,7 +103,7 @@ function CustomPatternInput({ onAdd }: { onAdd: (pattern: string) => void }) {
.previousElementSibling as HTMLInputElement;
handleAdd(input);
}}
className="retro-btn bg-white text-black h-10"
className="retro-btn bg-background text-foreground h-10"
>
</Button>
@ -127,7 +127,7 @@ function SelectedPatterns({
<Badge
key={pattern}
variant="secondary"
className="cursor-pointer hover:bg-red-100 hover:text-red-800 rounded-none border-2 border-black bg-gray-100 text-black font-mono font-bold"
className="cursor-pointer hover:bg-red-100 hover:text-red-800 rounded-none border-2 border-border bg-muted text-foreground font-mono font-bold"
onClick={() => onRemove(pattern)}
>
{pattern} ×

View File

@ -39,14 +39,14 @@ export default function ProjectSelector({
</Label>
<Badge
variant="outline"
className="text-xs rounded-none border-black font-mono"
className="text-xs rounded-none border-border font-mono"
>
{filteredProjects.length}
</Badge>
</div>
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-black w-4 h-4" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-foreground w-4 h-4" />
<Input
placeholder="搜索项目名称..."
value={searchTerm}
@ -91,7 +91,7 @@ function ProjectCard({
className={`cursor-pointer transition-all border-2 p-4 relative ${
isSelected
? "border-primary bg-blue-50 shadow-[4px_4px_0px_0px_rgba(37,99,235,1)] translate-x-[-2px] translate-y-[-2px]"
: "border-black bg-white hover:bg-gray-50 hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[-2px] hover:translate-y-[-2px]"
: "border-border bg-background hover:bg-background hover:shadow-[4px_4px_0px_0px_rgba(0,0,0,1)] hover:translate-x-[-2px] hover:translate-y-[-2px]"
}`}
onClick={onSelect}
>
@ -101,11 +101,11 @@ function ProjectCard({
{project.name}
</h4>
{project.description && (
<p className="text-xs text-gray-600 mt-1 line-clamp-2 font-mono">
<p className="text-xs text-muted-foreground mt-1 line-clamp-2 font-mono">
{project.description}
</p>
)}
<div className="flex items-center space-x-4 mt-2 text-xs text-gray-500 font-mono font-bold">
<div className="flex items-center space-x-4 mt-2 text-xs text-muted-foreground font-mono font-bold">
<span
className={`px-1.5 py-0.5 ${isRepo ? "bg-blue-100 text-blue-700" : "bg-amber-100 text-amber-700"}`}
>
@ -122,8 +122,8 @@ function ProjectCard({
</div>
</div>
{isSelected && (
<div className="w-5 h-5 bg-primary border-2 border-black flex items-center justify-center">
<div className="w-2 h-2 bg-white" />
<div className="w-5 h-5 bg-primary border-2 border-border flex items-center justify-center">
<div className="w-2 h-2 bg-background" />
</div>
)}
</div>
@ -141,7 +141,7 @@ function LoadingSpinner() {
function EmptyState({ hasSearch }: { hasSearch: boolean }) {
return (
<div className="col-span-2 text-center py-8 text-gray-500 font-mono">
<div className="col-span-2 text-center py-8 text-muted-foreground font-mono">
<FileText className="w-8 h-8 mx-auto mb-2 opacity-50" />
<p className="text-sm">
{hasSearch ? "未找到匹配的项目" : "暂无可用项目"}

View File

@ -208,7 +208,7 @@ export function DatabaseManager() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Activity className="w-5 h-5 text-emerald-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto">
<Button
variant="outline"
@ -238,16 +238,16 @@ export function DatabaseManager() {
<AlertCircle className="h-5 w-5 text-rose-400" />
)}
<div className="flex items-center gap-2">
<span className="font-bold uppercase text-sm text-gray-400"></span>
<span className="font-bold uppercase text-sm text-muted-foreground"></span>
{getHealthStatusBadge(health.status)}
</div>
<span className="text-sm text-gray-400">
<span className="text-sm text-muted-foreground">
<span className={health.database_connected ? 'text-emerald-400' : 'text-rose-400'}>
{health.database_connected ? '正常' : '异常'}
</span>
<span className="mx-2">|</span>
<span className="text-white">{health.total_records.toLocaleString()}</span>
<span className="text-foreground">{health.total_records.toLocaleString()}</span>
</span>
</div>
@ -292,7 +292,7 @@ export function DatabaseManager() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Database className="w-5 h-5 text-violet-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto">
<Button
variant="outline"
@ -321,17 +321,17 @@ export function DatabaseManager() {
<div className="cyber-card p-4">
<p className="stat-label"></p>
<p className="stat-value text-emerald-400">{stats.total_tasks}</p>
<p className="text-xs text-gray-500 mt-1">: {stats.completed_tasks} | : {stats.running_tasks}</p>
<p className="text-xs text-muted-foreground mt-1">: {stats.completed_tasks} | : {stats.running_tasks}</p>
</div>
<div className="cyber-card p-4">
<p className="stat-label"></p>
<p className="stat-value text-amber-400">{stats.total_issues}</p>
<p className="text-xs text-gray-500 mt-1">: {stats.open_issues} | : {stats.resolved_issues}</p>
<p className="text-xs text-muted-foreground mt-1">: {stats.open_issues} | : {stats.resolved_issues}</p>
</div>
<div className="cyber-card p-4">
<p className="stat-label"></p>
<p className="stat-value text-violet-400">{stats.total_analyses}</p>
<p className="text-xs text-gray-500 mt-1"></p>
<p className="text-xs text-muted-foreground mt-1"></p>
</div>
</div>
) : (
@ -347,7 +347,7 @@ export function DatabaseManager() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Database className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6 space-y-6">
{message && (
@ -369,11 +369,11 @@ export function DatabaseManager() {
<div className="grid gap-6 md:grid-cols-3">
<div className="space-y-3">
<h4 className="text-sm font-bold uppercase text-gray-300 flex items-center gap-2">
<h4 className="text-sm font-bold uppercase text-foreground flex items-center gap-2">
<Download className="h-4 w-4 text-sky-400" />
</h4>
<p className="text-xs text-gray-500"> JSON </p>
<p className="text-xs text-muted-foreground"> JSON </p>
<Button
onClick={handleExport}
disabled={loading}
@ -385,11 +385,11 @@ export function DatabaseManager() {
</div>
<div className="space-y-3">
<h4 className="text-sm font-bold uppercase text-gray-300 flex items-center gap-2">
<h4 className="text-sm font-bold uppercase text-foreground flex items-center gap-2">
<Upload className="h-4 w-4 text-emerald-400" />
</h4>
<p className="text-xs text-gray-500"> JSON 50MB</p>
<p className="text-xs text-muted-foreground"> JSON 50MB</p>
<Button
onClick={() => document.getElementById('import-file')?.click()}
disabled={loading}
@ -412,7 +412,7 @@ export function DatabaseManager() {
<Trash2 className="h-4 w-4" />
</h4>
<p className="text-xs text-gray-500"></p>
<p className="text-xs text-muted-foreground"></p>
<Button
onClick={handleClear}
disabled={loading}
@ -424,7 +424,7 @@ export function DatabaseManager() {
</div>
</div>
<div className="pt-6 border-t border-gray-800 border-dashed">
<div className="pt-6 border-t border-border border-dashed">
<div className="bg-sky-500/10 border border-sky-500/30 p-4 flex items-start gap-3 rounded-lg">
<Info className="h-5 w-5 text-sky-400 mt-0.5 flex-shrink-0" />
<p className="text-sm text-sky-300/80">

View File

@ -155,7 +155,7 @@ export default function DatabaseTest() {
</CardHeader>
<CardContent className="space-y-4">
<div className="flex items-center justify-between">
<p className="text-sm text-gray-600">
<p className="text-sm text-muted-foreground">
</p>
<Button
@ -188,7 +188,7 @@ export default function DatabaseTest() {
{getStatusIcon(result.status)}
<div>
<p className="font-medium text-sm">{result.name}</p>
<p className="text-xs text-gray-500">{result.message}</p>
<p className="text-xs text-muted-foreground">{result.message}</p>
</div>
</div>
{getStatusBadge(result.status)}

View File

@ -6,6 +6,7 @@
import { useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { Button } from "@/components/ui/button";
import { ThemeToggle } from "@/components/ui/theme-toggle";
import {
Menu,
X,
@ -22,22 +23,21 @@ import {
Shield,
MessageSquare,
Bot,
Terminal
} from "lucide-react";
import routes from "@/app/routes";
import { version } from "../../../package.json";
// Icon mapping for routes
const routeIcons: Record<string, React.ReactNode> = {
"/": <Bot className="w-5 h-5" />,
"/dashboard": <LayoutDashboard className="w-5 h-5" />,
"/projects": <FolderGit2 className="w-5 h-5" />,
"/instant-analysis": <Zap className="w-5 h-5" />,
"/audit-tasks": <ListTodo className="w-5 h-5" />,
"/audit-rules": <Shield className="w-5 h-5" />,
"/prompts": <MessageSquare className="w-5 h-5" />,
"/admin": <Settings className="w-5 h-5" />,
"/recycle-bin": <Trash2 className="w-5 h-5" />,
"/": <Bot className="w-6 h-6" />,
"/dashboard": <LayoutDashboard className="w-6 h-6" />,
"/projects": <FolderGit2 className="w-6 h-6" />,
"/instant-analysis": <Zap className="w-6 h-6" />,
"/audit-tasks": <ListTodo className="w-6 h-6" />,
"/audit-rules": <Shield className="w-6 h-6" />,
"/prompts": <MessageSquare className="w-6 h-6" />,
"/admin": <Settings className="w-6 h-6" />,
"/recycle-bin": <Trash2 className="w-6 h-6" />,
};
interface SidebarProps {
@ -57,7 +57,12 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
<Button
variant="ghost"
size="sm"
className="fixed top-4 left-4 z-50 md:hidden bg-[#0c0c12] border border-gray-800 text-gray-300 hover:bg-gray-800 hover:text-white"
className="fixed top-4 left-4 z-50 md:hidden"
style={{
background: 'var(--cyber-bg)',
border: '1px solid var(--cyber-border)',
color: 'var(--cyber-text-muted)'
}}
onClick={() => setMobileOpen(!mobileOpen)}
>
{mobileOpen ? <X className="w-5 h-5" /> : <Menu className="w-5 h-5" />}
@ -74,12 +79,14 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
{/* Sidebar */}
<aside
className={`
fixed top-0 left-0 h-screen
bg-[#0a0a0f] border-r border-gray-800/60
z-40 transition-all duration-300 ease-in-out
fixed top-0 left-0 h-screen z-40 transition-all duration-300 ease-in-out
${collapsed ? "w-20" : "w-64"}
${mobileOpen ? "translate-x-0" : "-translate-x-full md:translate-x-0"}
`}
style={{
background: 'var(--cyber-bg)',
borderRight: '1px solid var(--cyber-border)'
}}
>
<div className="flex flex-col h-full relative">
{/* Subtle grid background */}
@ -87,30 +94,35 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
className="absolute inset-0 opacity-30 pointer-events-none"
style={{
backgroundImage: `
linear-gradient(rgba(255,107,44,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,107,44,0.03) 1px, transparent 1px)
linear-gradient(var(--cyber-border-accent) 1px, transparent 1px),
linear-gradient(90deg, var(--cyber-border-accent) 1px, transparent 1px)
`,
backgroundSize: '24px 24px',
}}
/>
{/* Logo Section */}
<div className={`
relative flex items-center h-[72px]
border-b border-gray-800/60 bg-[#0c0c12]
${collapsed ? 'px-3 justify-center' : 'px-4 pr-6'}
`}>
<div
className={`relative flex items-center h-[72px] ${collapsed ? 'px-3 justify-center' : 'px-4 pr-6'}`}
style={{
background: 'var(--cyber-bg-elevated)',
borderBottom: '1px solid var(--cyber-border)'
}}
>
<Link
to="/"
className={`
flex items-center gap-3 group transition-all duration-300
${collapsed ? 'justify-center' : 'flex-1 min-w-0'}
`}
className={`flex items-center gap-3 group transition-all duration-300 ${collapsed ? 'justify-center' : 'flex-1 min-w-0'}`}
onClick={() => setMobileOpen(false)}
>
{/* Logo Icon */}
<div className="relative flex-shrink-0">
<div className="w-10 h-10 bg-[#0a0a0f] border border-primary/30 rounded-lg flex items-center justify-center overflow-hidden group-hover:border-primary/60 transition-colors">
<div
className="w-10 h-10 rounded-lg flex items-center justify-center overflow-hidden group-hover:border-primary/60 transition-colors"
style={{
background: 'var(--cyber-bg)',
border: '1px solid hsl(var(--primary) / 0.3)'
}}
>
<img
src="/logo_deepaudit.png"
alt="DeepAudit"
@ -122,31 +134,27 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
</div>
{/* Logo Text */}
<div className={`
transition-all duration-300
${collapsed ? 'w-0 opacity-0 overflow-hidden' : 'flex-1 min-w-0 opacity-100'}
`}>
<div className={`transition-all duration-300 ${collapsed ? 'w-0 opacity-0 overflow-hidden' : 'flex-1 min-w-0 opacity-100'}`}>
<div
className="text-xl font-bold tracking-wider font-mono"
style={{ textShadow: '0 0 20px rgba(255,107,44,0.3)' }}
>
<span className="text-primary">DEEP</span>
<span className="text-white">AUDIT</span>
<span style={{ color: 'var(--cyber-text)' }}>AUDIT</span>
</div>
</div>
</Link>
{/* Collapse button */}
<button
className={`
hidden md:flex absolute -right-3 top-1/2 -translate-y-1/2
w-6 h-6 bg-[#0c0c12] border border-gray-700 rounded
items-center justify-center text-gray-500
hover:bg-primary hover:border-primary hover:text-white
transition-all duration-200
`}
className="hidden md:flex absolute -right-3 top-1/2 -translate-y-1/2 w-6 h-6 rounded items-center justify-center hover:bg-primary hover:border-primary hover:text-foreground transition-all duration-200"
style={{
background: 'var(--cyber-bg)',
border: '1px solid var(--cyber-border)',
color: 'var(--cyber-text-muted)',
zIndex: 100
}}
onClick={() => setCollapsed(!collapsed)}
style={{ zIndex: 100 }}
>
{collapsed ? (
<ChevronRight className="w-3 h-3" />
@ -165,16 +173,26 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
<Link
key={route.path}
to={route.path}
className={`
flex items-center gap-3 px-3 py-2.5
transition-all duration-200 group relative rounded-lg
${isActive
? "bg-primary/15 text-primary border border-primary/30"
: "text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 border border-transparent"
}
`}
className="flex items-center gap-3 px-3 py-2.5 transition-all duration-200 group relative rounded-lg"
style={{
background: isActive ? 'hsl(var(--primary) / 0.15)' : 'transparent',
border: isActive ? '1px solid hsl(var(--primary) / 0.3)' : '1px solid transparent',
color: isActive ? 'hsl(var(--primary))' : 'var(--cyber-text-muted)'
}}
onClick={() => setMobileOpen(false)}
title={collapsed ? route.name : undefined}
onMouseEnter={(e) => {
if (!isActive) {
e.currentTarget.style.background = 'var(--cyber-hover-bg)';
e.currentTarget.style.color = 'var(--cyber-text)';
}
}}
onMouseLeave={(e) => {
if (!isActive) {
e.currentTarget.style.background = 'transparent';
e.currentTarget.style.color = 'var(--cyber-text-muted)';
}
}}
>
{/* Active indicator */}
{isActive && (
@ -182,19 +200,13 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
)}
{/* Icon */}
<span className={`
flex-shrink-0 transition-colors duration-200
${isActive ? "text-primary" : "text-gray-500 group-hover:text-gray-300"}
`}>
{routeIcons[route.path] || <LayoutDashboard className="w-5 h-5" />}
<span className="flex-shrink-0 transition-colors duration-200">
{routeIcons[route.path] || <LayoutDashboard className="w-6 h-6" />}
</span>
{/* Label */}
{!collapsed && (
<span className={`
font-mono text-sm tracking-wide
${isActive ? 'font-semibold' : 'font-medium'}
`}>
<span className={`font-mono text-base tracking-wide ${isActive ? 'font-semibold' : 'font-medium'}`}>
{route.name}
</span>
)}
@ -212,26 +224,31 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
</nav>
{/* Footer */}
<div className="p-3 border-t border-gray-800/60 bg-[#0c0c12] space-y-1">
<div
className="p-3 space-y-1"
style={{
background: 'var(--cyber-bg-elevated)',
borderTop: '1px solid var(--cyber-border)'
}}
>
{/* Theme Toggle */}
<ThemeToggle collapsed={collapsed} />
{/* Account Link */}
<Link
to="/account"
className={`
flex items-center gap-3 px-3 py-2.5 rounded-lg
transition-all duration-200 group
${location.pathname === '/account'
? "bg-primary/15 text-primary border border-primary/30"
: "text-gray-400 hover:text-gray-200 hover:bg-gray-800/50 border border-transparent"
}
`}
className="flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 group"
style={{
background: location.pathname === '/account' ? 'hsl(var(--primary) / 0.15)' : 'transparent',
border: location.pathname === '/account' ? '1px solid hsl(var(--primary) / 0.3)' : '1px solid transparent',
color: location.pathname === '/account' ? 'hsl(var(--primary))' : 'var(--cyber-text-muted)'
}}
onClick={() => setMobileOpen(false)}
title={collapsed ? "账号管理" : undefined}
>
<UserCircle className={`w-5 h-5 flex-shrink-0 ${
location.pathname === '/account' ? 'text-primary' : 'text-gray-500 group-hover:text-gray-300'
}`} />
<UserCircle className="w-6 h-6 flex-shrink-0" />
{!collapsed && (
<span className="font-mono text-sm"></span>
<span className="font-mono text-base"></span>
)}
</Link>
@ -240,29 +257,31 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
href="https://github.com/lintsinghua/DeepAudit"
target="_blank"
rel="noopener noreferrer"
className={`
flex items-center gap-3 px-3 py-2.5 rounded-lg
text-gray-400 hover:text-gray-200 hover:bg-gray-800/50
transition-all duration-200 group border border-transparent
`}
className="flex items-center gap-3 px-3 py-2.5 rounded-lg transition-all duration-200 group"
style={{ color: 'var(--cyber-text-muted)' }}
title={collapsed ? "GitHub" : undefined}
>
<Github className="w-5 h-5 flex-shrink-0 text-gray-500 group-hover:text-gray-300" />
<Github className="w-6 h-6 flex-shrink-0" />
{!collapsed && (
<div className="flex flex-col">
<span className="font-mono text-sm">GitHub</span>
<span className="text-[10px] text-gray-600 font-mono">v{version}</span>
<span className="font-mono text-base">GitHub</span>
<span className="text-sm font-mono" style={{ color: 'var(--cyber-text-muted)' }}>v{version}</span>
</div>
)}
</a>
{/* System Status */}
{!collapsed && (
<div className="mt-3 pt-3 border-t border-gray-800/50">
<div className="mt-3 pt-3" style={{ borderTop: '1px solid var(--cyber-border)' }}>
<div className="flex items-center gap-2 px-3 py-2">
<div className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"
style={{ boxShadow: '0 0 8px rgba(52, 211, 153, 0.5)' }} />
<span className="text-[10px] text-gray-600 font-mono uppercase tracking-wider">
<div
className="w-2 h-2 rounded-full bg-emerald-400 animate-pulse"
style={{ boxShadow: '0 0 8px rgba(52, 211, 153, 0.5)' }}
/>
<span
className="text-sm font-mono uppercase tracking-wider"
style={{ color: 'var(--cyber-text-muted)' }}
>
System Online
</span>
</div>

View File

@ -62,13 +62,13 @@ export default function ExportReportDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[600px] bg-[#0c0c12] border-gray-700">
<DialogContent className="sm:max-w-[600px] cyber-dialog border-border">
<DialogHeader>
<DialogTitle className="flex items-center gap-3 text-lg font-bold uppercase tracking-wider text-white">
<DialogTitle className="flex items-center gap-3 text-lg font-bold uppercase tracking-wider text-foreground">
<Download className="w-5 h-5 text-primary" />
</DialogTitle>
<DialogDescription className="text-gray-400 font-mono text-xs">
<DialogDescription className="text-muted-foreground font-mono text-xs">
</DialogDescription>
</DialogHeader>
@ -79,57 +79,57 @@ export default function ExportReportDialog({
onValueChange={(value) => setSelectedFormat(value as ExportFormat)}
className="space-y-4"
>
<div className="flex items-center space-x-3 p-4 border border-gray-700 rounded bg-gray-900/30 cursor-pointer hover:bg-gray-800/50">
<div className="flex items-center space-x-3 p-4 border border-border rounded bg-muted/50 cursor-pointer hover:bg-muted">
<RadioGroupItem value="json" id="json" />
<Label htmlFor="json" className="flex items-center gap-3 cursor-pointer flex-1">
<FileJson className="w-5 h-5 text-amber-400" />
<div>
<div className="font-bold text-gray-200">JSON </div>
<div className="text-xs text-gray-500"></div>
<div className="font-bold text-foreground">JSON </div>
<div className="text-xs text-muted-foreground"></div>
</div>
</Label>
</div>
<div className="flex items-center space-x-3 p-4 border border-gray-700 rounded bg-gray-900/30 cursor-pointer hover:bg-gray-800/50">
<div className="flex items-center space-x-3 p-4 border border-border rounded bg-muted/50 cursor-pointer hover:bg-muted">
<RadioGroupItem value="pdf" id="pdf" />
<Label htmlFor="pdf" className="flex items-center gap-3 cursor-pointer flex-1">
<FileText className="w-5 h-5 text-rose-400" />
<div>
<div className="font-bold text-gray-200">PDF </div>
<div className="text-xs text-gray-500"></div>
<div className="font-bold text-foreground">PDF </div>
<div className="text-xs text-muted-foreground"></div>
</div>
</Label>
</div>
</RadioGroup>
{/* 报告预览信息 */}
<div className="mt-6 border border-gray-700 rounded bg-gray-900/30">
<div className="px-4 py-2 border-b border-gray-800 bg-gray-900/50 flex items-center gap-2">
<div className="mt-6 border border-border rounded bg-muted/50">
<div className="px-4 py-2 border-b border-border bg-muted flex items-center gap-2">
<Terminal className="w-3 h-3 text-primary" />
<h4 className="font-bold text-gray-300 uppercase text-xs"></h4>
<h4 className="font-bold text-foreground uppercase text-xs"></h4>
</div>
<div className="p-4 grid grid-cols-2 gap-3 text-xs font-mono">
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<span className="font-bold text-white">{task.project?.name || "未知"}</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-foreground">{task.project?.name || "未知"}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-emerald-400">{task.quality_score.toFixed(1)}/100</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<span className="font-bold text-white">{task.scanned_files}/{task.total_files}</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-foreground">{task.scanned_files}/{task.total_files}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-amber-400">{issues.length}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<span className="font-bold text-white">{task.total_lines.toLocaleString()}</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-foreground">{task.total_lines.toLocaleString()}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-rose-400">
{issues.filter(i => i.severity === "critical").length}
</span>
@ -138,7 +138,7 @@ export default function ExportReportDialog({
</div>
</div>
<DialogFooter className="border-t border-gray-800 pt-4">
<DialogFooter className="border-t border-border pt-4">
<Button
variant="outline"
onClick={() => onOpenChange(false)}

View File

@ -72,13 +72,13 @@ export default function InstantExportDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="sm:max-w-[600px] bg-[#0c0c12] border-gray-700">
<DialogContent className="sm:max-w-[600px] cyber-dialog border-border">
<DialogHeader>
<DialogTitle className="flex items-center gap-3 text-lg font-bold uppercase tracking-wider text-white">
<DialogTitle className="flex items-center gap-3 text-lg font-bold uppercase tracking-wider text-foreground">
<Download className="w-5 h-5 text-primary" />
</DialogTitle>
<DialogDescription className="text-gray-400 font-mono text-xs">
<DialogDescription className="text-muted-foreground font-mono text-xs">
</DialogDescription>
</DialogHeader>
@ -89,23 +89,23 @@ export default function InstantExportDialog({
onValueChange={(value) => setSelectedFormat(value as ExportFormat)}
className="space-y-4"
>
<div className="flex items-center space-x-3 p-4 border border-gray-700 rounded bg-gray-900/30 cursor-pointer hover:bg-gray-800/50">
<div className="flex items-center space-x-3 p-4 border border-border rounded bg-muted/50 cursor-pointer hover:bg-muted">
<RadioGroupItem value="json" id="json" />
<Label htmlFor="json" className="flex items-center gap-3 cursor-pointer flex-1">
<FileJson className="w-5 h-5 text-amber-400" />
<div>
<div className="font-bold text-gray-200">JSON </div>
<div className="text-xs text-gray-500"></div>
<div className="font-bold text-foreground">JSON </div>
<div className="text-xs text-muted-foreground"></div>
</div>
</Label>
</div>
<div className={`flex items-center space-x-3 p-4 border border-gray-700 rounded bg-gray-900/30 ${isPdfDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-gray-800/50'}`}>
<div className={`flex items-center space-x-3 p-4 border border-border rounded bg-muted/50 ${isPdfDisabled ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer hover:bg-muted'}`}>
<RadioGroupItem value="pdf" id="pdf" disabled={isPdfDisabled} />
<Label htmlFor="pdf" className={`flex items-center gap-3 flex-1 ${isPdfDisabled ? 'cursor-not-allowed' : 'cursor-pointer'}`}>
<FileText className="w-5 h-5 text-rose-400" />
<div>
<div className="font-bold text-gray-200">PDF </div>
<div className="text-xs text-gray-500">
<div className="font-bold text-foreground">PDF </div>
<div className="text-xs text-muted-foreground">
{isPdfDisabled && <AlertTriangle className="w-3 h-3 inline mr-1 text-amber-500" />}
{isPdfDisabled ? "需要先保存到历史记录" : "专业报告,适合打印和分享"}
</div>
@ -115,33 +115,33 @@ export default function InstantExportDialog({
</RadioGroup>
{/* 报告预览信息 */}
<div className="mt-6 border border-gray-700 rounded bg-gray-900/30">
<div className="px-4 py-2 border-b border-gray-800 bg-gray-900/50 flex items-center gap-2">
<div className="mt-6 border border-border rounded bg-muted/50">
<div className="px-4 py-2 border-b border-border bg-muted flex items-center gap-2">
<Terminal className="w-3 h-3 text-primary" />
<h4 className="font-bold text-gray-300 uppercase text-xs"></h4>
<h4 className="font-bold text-foreground uppercase text-xs"></h4>
</div>
<div className="p-4 grid grid-cols-2 gap-3 text-xs font-mono">
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-sky-400">{language.toUpperCase()}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-emerald-400">{(analysisResult.quality_score ?? 0).toFixed(1)}/100</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-amber-400">{analysisResult.issues?.length ?? 0}</span>
</div>
<div className="flex items-center justify-between border-b border-gray-800 pb-2">
<span className="text-gray-600">:</span>
<span className="font-bold text-white">{(analysisTime ?? 0).toFixed(2)}s</span>
<div className="flex items-center justify-between border-b border-border pb-2">
<span className="text-muted-foreground">:</span>
<span className="font-bold text-foreground">{(analysisTime ?? 0).toFixed(2)}s</span>
</div>
</div>
</div>
</div>
<DialogFooter className="border-t border-gray-800 pt-4">
<DialogFooter className="border-t border-border pt-4">
<Button
variant="outline"
onClick={() => onOpenChange(false)}

View File

@ -208,7 +208,7 @@ export function SystemConfig() {
<div className="flex items-center justify-center min-h-[400px]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
@ -250,17 +250,17 @@ export function SystemConfig() {
</div>
<Tabs defaultValue="llm" className="w-full">
<TabsList className="grid w-full grid-cols-4 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded-lg mb-6">
<TabsTrigger value="llm" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2.5 text-gray-400 transition-all rounded text-xs flex items-center gap-2">
<TabsList className="grid w-full grid-cols-4 bg-muted border border-border p-1 h-auto gap-1 rounded-lg mb-6">
<TabsTrigger value="llm" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2.5 text-muted-foreground transition-all rounded text-xs flex items-center gap-2">
<Zap className="w-3 h-3" /> LLM
</TabsTrigger>
<TabsTrigger value="embedding" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2.5 text-gray-400 transition-all rounded text-xs flex items-center gap-2">
<TabsTrigger value="embedding" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2.5 text-muted-foreground transition-all rounded text-xs flex items-center gap-2">
<Brain className="w-3 h-3" />
</TabsTrigger>
<TabsTrigger value="analysis" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2.5 text-gray-400 transition-all rounded text-xs flex items-center gap-2">
<TabsTrigger value="analysis" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2.5 text-muted-foreground transition-all rounded text-xs flex items-center gap-2">
<Settings className="w-3 h-3" />
</TabsTrigger>
<TabsTrigger value="git" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2.5 text-gray-400 transition-all rounded text-xs flex items-center gap-2">
<TabsTrigger value="git" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2.5 text-muted-foreground transition-all rounded text-xs flex items-center gap-2">
<Globe className="w-3 h-3" /> Git
</TabsTrigger>
</TabsList>
@ -270,29 +270,29 @@ export function SystemConfig() {
<div className="cyber-card p-6 space-y-6">
{/* Provider Selection */}
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> LLM </Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> LLM </Label>
<Select value={config.llmProvider} onValueChange={(v) => updateConfig('llmProvider', v)}>
<SelectTrigger className="h-12 cyber-input">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<div className="px-2 py-1.5 text-xs font-bold text-gray-500 uppercase">LiteLLM ()</div>
<SelectContent className="cyber-dialog border-border">
<div className="px-2 py-1.5 text-xs font-bold text-muted-foreground uppercase">LiteLLM ()</div>
{LLM_PROVIDERS.filter(p => p.category === 'litellm').map(p => (
<SelectItem key={p.value} value={p.value} className="font-mono">
<span className="flex items-center gap-2">
<span>{p.icon}</span>
<span>{p.label}</span>
<span className="text-xs text-gray-500">- {p.hint}</span>
<span className="text-xs text-muted-foreground">- {p.hint}</span>
</span>
</SelectItem>
))}
<div className="px-2 py-1.5 text-xs font-bold text-gray-500 uppercase mt-2"></div>
<div className="px-2 py-1.5 text-xs font-bold text-muted-foreground uppercase mt-2"></div>
{LLM_PROVIDERS.filter(p => p.category === 'native').map(p => (
<SelectItem key={p.value} value={p.value} className="font-mono">
<span className="flex items-center gap-2">
<span>{p.icon}</span>
<span>{p.label}</span>
<span className="text-xs text-gray-500">- {p.hint}</span>
<span className="text-xs text-muted-foreground">- {p.hint}</span>
</span>
</SelectItem>
))}
@ -303,7 +303,7 @@ export function SystemConfig() {
{/* API Key */}
{config.llmProvider !== 'ollama' && (
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">API Key</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase">API Key</Label>
<div className="flex gap-2">
<Input
type={showApiKey ? 'text' : 'password'}
@ -327,7 +327,7 @@ export function SystemConfig() {
{/* Model and Base URL */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> ()</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> ()</Label>
<Input
value={config.llmModel}
onChange={(e) => updateConfig('llmModel', e.target.value)}
@ -336,7 +336,7 @@ export function SystemConfig() {
/>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">API Base URL ()</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase">API Base URL ()</Label>
<Input
value={config.llmBaseUrl}
onChange={(e) => updateConfig('llmBaseUrl', e.target.value)}
@ -347,10 +347,10 @@ export function SystemConfig() {
</div>
{/* Test Connection */}
<div className="pt-4 border-t border-gray-800 border-dashed flex items-center justify-between flex-wrap gap-4">
<div className="pt-4 border-t border-border border-dashed flex items-center justify-between flex-wrap gap-4">
<div className="text-sm">
<span className="font-bold text-gray-300"></span>
<span className="text-gray-500 ml-2"></span>
<span className="font-bold text-foreground"></span>
<span className="text-muted-foreground ml-2"></span>
</div>
<Button
onClick={testLLMConnection}
@ -386,11 +386,11 @@ export function SystemConfig() {
)}
{/* Advanced Parameters */}
<details className="pt-4 border-t border-gray-800 border-dashed">
<summary className="font-bold uppercase cursor-pointer hover:text-primary text-gray-400 text-sm"></summary>
<details className="pt-4 border-t border-border border-dashed">
<summary className="font-bold uppercase cursor-pointer hover:text-primary text-muted-foreground text-sm"></summary>
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mt-4">
<div className="space-y-2">
<Label className="text-xs text-gray-500 uppercase"> ()</Label>
<Label className="text-xs text-muted-foreground uppercase"> ()</Label>
<Input
type="number"
value={config.llmTimeout}
@ -399,7 +399,7 @@ export function SystemConfig() {
/>
</div>
<div className="space-y-2">
<Label className="text-xs text-gray-500 uppercase"> (0-2)</Label>
<Label className="text-xs text-muted-foreground uppercase"> (0-2)</Label>
<Input
type="number"
step="0.1"
@ -411,7 +411,7 @@ export function SystemConfig() {
/>
</div>
<div className="space-y-2">
<Label className="text-xs text-gray-500 uppercase"> Tokens</Label>
<Label className="text-xs text-muted-foreground uppercase"> Tokens</Label>
<Input
type="number"
value={config.llmMaxTokens}
@ -424,14 +424,14 @@ export function SystemConfig() {
</div>
{/* Usage Notes */}
<div className="bg-gray-900/50 border border-gray-800 p-4 rounded-lg text-xs space-y-2">
<p className="font-bold uppercase text-gray-400 flex items-center gap-2">
<div className="bg-muted border border-border p-4 rounded-lg text-xs space-y-2">
<p className="font-bold uppercase text-muted-foreground flex items-center gap-2">
<Info className="w-4 h-4 text-sky-400" />
</p>
<p className="text-gray-500"> <strong className="text-gray-400">LiteLLM </strong>: LiteLLM </p>
<p className="text-gray-500"> <strong className="text-gray-400"></strong>: MiniMax API 使</p>
<p className="text-gray-500"> <strong className="text-gray-400">API </strong>: Base URL API Key Key</p>
<p className="text-muted-foreground"> <strong className="text-muted-foreground">LiteLLM </strong>: LiteLLM </p>
<p className="text-muted-foreground"> <strong className="text-muted-foreground"></strong>: MiniMax API 使</p>
<p className="text-muted-foreground"> <strong className="text-muted-foreground">API </strong>: Base URL API Key Key</p>
</div>
</TabsContent>
@ -445,47 +445,47 @@ export function SystemConfig() {
<div className="cyber-card p-6 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input
type="number"
value={config.maxAnalyzeFiles}
onChange={(e) => updateConfig('maxAnalyzeFiles', Number(e.target.value))}
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600"></p>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">LLM </Label>
<Label className="text-xs font-bold text-muted-foreground uppercase">LLM </Label>
<Input
type="number"
value={config.llmConcurrency}
onChange={(e) => updateConfig('llmConcurrency', Number(e.target.value))}
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600"> LLM </p>
<p className="text-xs text-muted-foreground"> LLM </p>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> ()</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> ()</Label>
<Input
type="number"
value={config.llmGapMs}
onChange={(e) => updateConfig('llmGapMs', Number(e.target.value))}
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600"></p>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={config.outputLanguage} onValueChange={(v) => updateConfig('outputLanguage', v)}>
<SelectTrigger className="h-10 cyber-input">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="zh-CN" className="font-mono">🇨🇳 </SelectItem>
<SelectItem value="en-US" className="font-mono">🇺🇸 English</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-gray-600"></p>
<p className="text-xs text-muted-foreground"></p>
</div>
</div>
</div>
@ -495,7 +495,7 @@ export function SystemConfig() {
<TabsContent value="git" className="space-y-6">
<div className="cyber-card p-6 space-y-6">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">GitHub Token ()</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase">GitHub Token ()</Label>
<Input
type="password"
value={config.githubToken}
@ -503,7 +503,7 @@ export function SystemConfig() {
placeholder="ghp_xxxxxxxxxxxx"
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600">
<p className="text-xs text-muted-foreground">
访:{' '}
<a href="https://github.com/settings/tokens" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
github.com/settings/tokens
@ -511,7 +511,7 @@ export function SystemConfig() {
</p>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase">GitLab Token ()</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase">GitLab Token ()</Label>
<Input
type="password"
value={config.gitlabToken}
@ -519,20 +519,20 @@ export function SystemConfig() {
placeholder="glpat-xxxxxxxxxxxx"
className="h-10 cyber-input"
/>
<p className="text-xs text-gray-600">
<p className="text-xs text-muted-foreground">
访:{' '}
<a href="https://gitlab.com/-/profile/personal_access_tokens" target="_blank" rel="noopener noreferrer" className="text-primary hover:underline">
gitlab.com/-/profile/personal_access_tokens
</a>
</p>
</div>
<div className="bg-gray-900/50 border border-gray-800 p-4 rounded-lg text-xs">
<p className="font-bold text-gray-400 flex items-center gap-2 mb-2">
<div className="bg-muted border border-border p-4 rounded-lg text-xs">
<p className="font-bold text-muted-foreground flex items-center gap-2 mb-2">
<Info className="w-4 h-4 text-sky-400" />
</p>
<p className="text-gray-500"> Token</p>
<p className="text-gray-500"> Token</p>
<p className="text-muted-foreground"> Token</p>
<p className="text-muted-foreground"> Token</p>
</div>
</div>
</TabsContent>

View File

@ -33,13 +33,13 @@ function AccordionTrigger({
<AccordionPrimitive.Trigger
data-slot="accordion-trigger"
className={cn(
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-md py-4 text-left text-sm font-medium transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
"focus-visible:border-ring focus-visible:ring-ring/50 flex flex-1 items-start justify-between gap-4 rounded-sm py-4 text-left text-base font-semibold transition-all outline-none hover:underline focus-visible:ring-[3px] disabled:pointer-events-none disabled:opacity-50 [&[data-state=open]>svg]:rotate-180",
className
)}
{...props}
>
{children}
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-4 shrink-0 translate-y-0.5 transition-transform duration-200" />
<ChevronDownIcon className="text-muted-foreground pointer-events-none size-5 shrink-0 translate-y-0.5 transition-transform duration-200" />
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
);
@ -53,7 +53,7 @@ function AccordionContent({
return (
<AccordionPrimitive.Content
data-slot="accordion-content"
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm"
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-base"
{...props}
>
<div className={cn("pt-0 pb-4", className)}>{children}</div>

View File

@ -52,7 +52,7 @@ function AlertDialogContent({
<AlertDialogPrimitive.Content
data-slot="alert-dialog-content"
className={cn(
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-6 rounded-sm border border-border p-0 shadow-lg duration-200 sm:max-w-lg overflow-hidden",
className
)}
{...props}
@ -68,7 +68,7 @@ function AlertDialogHeader({
return (
<div
data-slot="alert-dialog-header"
className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
className={cn("flex flex-col gap-2 px-6 pt-6 text-center sm:text-left", className)}
{...props}
/>
);
@ -82,7 +82,7 @@ function AlertDialogFooter({
<div
data-slot="alert-dialog-footer"
className={cn(
"flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
"flex flex-col-reverse gap-3 sm:flex-row sm:justify-end px-6 pb-6 pt-4 border-t border-border bg-muted/30",
className
)}
{...props}
@ -97,7 +97,7 @@ function AlertDialogTitle({
return (
<AlertDialogPrimitive.Title
data-slot="alert-dialog-title"
className={cn("text-lg font-semibold", className)}
className={cn("text-xl font-mono font-bold uppercase tracking-wider text-foreground", className)}
{...props}
/>
);
@ -110,7 +110,7 @@ function AlertDialogDescription({
return (
<AlertDialogPrimitive.Description
data-slot="alert-dialog-description"
className={cn("text-muted-foreground text-sm", className)}
className={cn("text-foreground/70 text-base font-mono", className)}
{...props}
/>
);

View File

@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/shared/utils/utils"
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm grid has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-3 gap-y-0.5 items-start [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
"relative w-full rounded-sm border px-5 py-4 text-base grid has-[>svg]:grid-cols-[calc(var(--spacing)*5)_1fr] grid-cols-[0_1fr] has-[>svg]:gap-x-4 gap-y-1 items-start [&>svg]:size-5 [&>svg]:translate-y-0.5 [&>svg]:text-current",
{
variants: {
variant: {
@ -39,7 +39,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="alert-title"
className={cn(
"col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight",
"col-start-2 line-clamp-1 min-h-5 font-semibold tracking-tight text-lg",
className
)}
{...props}
@ -55,7 +55,7 @@ function AlertDescription({
<div
data-slot="alert-description"
className={cn(
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
"text-foreground/70 col-start-2 grid justify-items-start gap-1 text-base [&_p]:leading-relaxed",
className
)}
{...props}

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/utils/utils";
const badgeVariants = cva(
"inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
"inline-flex items-center justify-center rounded-sm border px-3 py-1.5 text-sm font-mono font-semibold uppercase tracking-wider w-fit whitespace-nowrap shrink-0 [&>svg]:size-4 gap-1.5 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
{
variants: {
variant: {
@ -14,7 +14,7 @@ const badgeVariants = cva(
secondary:
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive:
"border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
"border-transparent bg-destructive text-foreground [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
},

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/utils/utils";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-sm text-sm font-mono font-semibold transition-all duration-150 focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-sm text-base font-mono font-semibold transition-all duration-150 focus-visible:outline-none focus-visible:shadow-focus disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-5 [&_svg]:shrink-0",
{
variants: {
variant: {
@ -21,10 +21,10 @@ const buttonVariants = cva(
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-9 px-4 py-2",
sm: "h-8 rounded-sm px-3 text-xs",
lg: "h-10 rounded-sm px-8",
icon: "h-9 w-9",
default: "h-11 px-5 py-2.5",
sm: "h-9 rounded-sm px-4 text-sm",
lg: "h-13 rounded-sm px-8 text-lg",
icon: "h-11 w-11",
},
},
defaultVariants: {

View File

@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6",
"bg-card text-card-foreground flex flex-col gap-4 rounded-sm border border-border p-5 shadow-sm transition-all duration-200 hover:shadow-md relative overflow-hidden",
className
)}
{...props}
@ -20,7 +20,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="card-header"
className={cn(
"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
"flex flex-col gap-2 pb-4 border-b border-border",
className
)}
{...props}
@ -32,7 +32,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-title"
className={cn("leading-none font-semibold", className)}
className={cn("text-lg font-mono font-bold uppercase tracking-wider text-foreground", className)}
{...props}
/>
);
@ -42,7 +42,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)}
className={cn("text-base text-foreground/70 font-mono", className)}
{...props}
/>
);
@ -65,7 +65,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-content"
className={cn("px-6", className)}
className={cn("py-2", className)}
{...props}
/>
);
@ -75,7 +75,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="card-footer"
className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
className={cn("flex items-center gap-3 pt-4 border-t border-border", className)}
{...props}
/>
);

View File

@ -12,7 +12,7 @@ function Checkbox({
<CheckboxPrimitive.Root
data-slot="checkbox"
className={cn(
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
"peer border-border bg-background data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-primary focus-visible:shadow-focus aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-6 shrink-0 rounded-sm border shadow-none transition-all outline-none disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
@ -21,7 +21,7 @@ function Checkbox({
data-slot="checkbox-indicator"
className="flex items-center justify-center text-current transition-none"
>
<CheckIcon className="size-3.5" />
<CheckIcon className="size-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
);

View File

@ -19,7 +19,7 @@ function Command({
<CommandPrimitive
data-slot="command"
className={cn(
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md",
"bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-sm",
className
)}
{...props}
@ -64,7 +64,7 @@ function CommandInput({
<CommandPrimitive.Input
data-slot="command-input"
className={cn(
"placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
"placeholder:text-muted-foreground flex h-10 w-full rounded-sm bg-transparent py-3 text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}

View File

@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-6 border border-border bg-background p-0 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg overflow-hidden",
className
)}
{...props}
@ -59,7 +59,7 @@ const DialogHeader = ({
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
"flex flex-col space-y-2 px-6 pt-6 text-center sm:text-left",
className
)}
{...props}
@ -73,7 +73,7 @@ const DialogFooter = ({
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
"flex flex-col-reverse sm:flex-row sm:justify-end gap-3 px-6 pb-6 pt-4 border-t border-border bg-muted/30",
className
)}
{...props}
@ -88,7 +88,7 @@ const DialogTitle = React.forwardRef<
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
"text-xl font-mono font-bold uppercase tracking-wider text-foreground",
className
)}
{...props}
@ -102,7 +102,7 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
className={cn("text-base text-foreground/70 font-mono", className)}
{...props}
/>
))

View File

@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger
ref={ref}
className={cn(
"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
"flex cursor-default select-none items-center gap-2 rounded-sm px-3 py-2 text-base outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-5 [&_svg]:shrink-0",
inset && "pl-8",
className
)}
@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-sm border border-border bg-popover p-1 text-popover-foreground shadow-lg font-mono",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
className
)}
@ -84,7 +84,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-4 [&>svg]:shrink-0",
"relative flex cursor-default select-none items-center gap-2 rounded-sm px-4 py-2.5 text-base outline-none transition-colors focus:bg-muted focus:text-foreground hover:bg-muted data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&>svg]:size-5 [&>svg]:shrink-0",
inset && "pl-8",
className
)}
@ -148,7 +148,7 @@ const DropdownMenuLabel = React.forwardRef<
<DropdownMenuPrimitive.Label
ref={ref}
className={cn(
"px-2 py-1.5 text-sm font-semibold",
"px-3 py-2 text-base font-semibold",
inset && "pl-8",
className
)}

View File

@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground font-mono flex h-9 w-full min-w-0 rounded-sm border border-input bg-background px-3 py-2 text-sm shadow-none transition-[border-color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground font-mono font-medium flex h-11 w-full min-w-0 rounded-sm border border-input bg-background px-4 py-2.5 text-base shadow-none transition-[border-color,box-shadow] outline-none file:inline-flex file:h-9 file:border-0 file:bg-transparent file:text-base file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"focus:border-primary focus:shadow-focus",
"aria-invalid:border-secondary",
className

View File

@ -13,7 +13,7 @@ function Label({
<LabelPrimitive.Root
data-slot="label"
className={cn(
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
"flex items-center gap-2 text-base leading-none font-mono font-semibold text-foreground/80 uppercase tracking-wider select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
className
)}
{...props}

View File

@ -12,7 +12,7 @@ function Menubar({
<MenubarPrimitive.Root
data-slot="menubar"
className={cn(
"bg-background flex h-9 items-center gap-1 rounded-md border p-1 shadow-xs",
"bg-background flex h-9 items-center gap-1 rounded-sm border p-1 shadow-xs",
className
)}
{...props}
@ -77,7 +77,7 @@ function MenubarContent({
alignOffset={alignOffset}
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-md",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[12rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-sm border p-1 shadow-md",
className
)}
{...props}
@ -246,7 +246,7 @@ function MenubarSubContent({
<MenubarPrimitive.SubContent
data-slot="menubar-sub-content"
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[8rem] origin-(--radix-menubar-content-transform-origin) overflow-hidden rounded-sm border p-1 shadow-lg",
className
)}
{...props}

View File

@ -89,13 +89,13 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
<div className="relative z-20 inline-block w-full" ref={containerRef}>
<div className="relative flex flex-col items-center">
<div onClick={toggleDropdown} className="w-full">
<div className="mb-2 flex h-11 rounded-lg border border-gray-300 py-1.5 pl-3 pr-3 shadow-theme-xs outline-hidden transition focus:border-brand-300 focus:shadow-focus-ring dark:border-gray-700 dark:bg-gray-900 dark:focus:border-brand-300">
<div className="mb-2 flex h-11 rounded-sm border border-border py-1.5 pl-3 pr-3 shadow-theme-xs outline-hidden transition focus:border-brand-300 focus:shadow-focus-ring dark:border-border dark:bg-card dark:focus:border-brand-300">
<div className="flex flex-wrap flex-auto gap-2">
{selectedValuesText.length > 0 ? (
selectedValuesText.map((text, index) => (
<div
key={index}
className="group flex items-center justify-center rounded-full border-[0.7px] border-transparent bg-gray-100 py-1 pl-2.5 pr-2 text-sm text-gray-800 hover:border-gray-200 dark:bg-gray-800 dark:text-white/90 dark:hover:border-gray-800"
className="group flex items-center justify-center rounded-full border-[0.7px] border-transparent bg-muted py-1 pl-2.5 pr-2 text-sm text-foreground hover:border-border dark:bg-muted dark:text-foreground/90 dark:hover:border-border"
>
<span className="flex-initial max-w-full">{text}</span>
<div className="flex flex-row-reverse flex-auto">
@ -104,7 +104,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
e.stopPropagation();
removeOption(selectedOptions[index]);
}}
className="pl-2 text-gray-500 cursor-pointer group-hover:text-gray-400 dark:text-gray-400"
className="pl-2 text-muted-foreground cursor-pointer group-hover:text-muted-foreground dark:text-muted-foreground"
>
<svg
className="fill-current"
@ -127,7 +127,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
) : (
<input
placeholder="请选择选项..."
className="w-full h-full p-1 pr-2 text-sm bg-transparent border-0 outline-hidden appearance-none placeholder:text-gray-800 focus:border-0 focus:outline-hidden focus:ring-0 dark:placeholder:text-white/90"
className="w-full h-full p-1 pr-2 text-sm bg-transparent border-0 outline-hidden appearance-none placeholder:text-foreground focus:border-0 focus:outline-hidden focus:ring-0 dark:placeholder:text-foreground/90"
readOnly
value="请选择选项..."
/>
@ -137,7 +137,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
<button
type="button"
onClick={toggleDropdown}
className="w-5 h-5 text-gray-700 outline-hidden cursor-pointer focus:outline-hidden dark:text-gray-400"
className="w-5 h-5 text-muted-foreground outline-hidden cursor-pointer focus:outline-hidden dark:text-muted-foreground"
>
<svg
className={`stroke-current ${isOpen ? "rotate-180" : ""}`}
@ -162,14 +162,14 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
{isOpen && (
<div
className="absolute left-0 z-40 w-full overflow-y-auto bg-white rounded-lg shadow-sm top-full max-h-select dark:bg-gray-900"
className="absolute left-0 z-40 w-full overflow-y-auto bg-background rounded-sm shadow-sm top-full max-h-select dark:bg-card"
onClick={(e) => e.stopPropagation()}
>
<div className="flex flex-col">
{options.map((option, index) => (
<div
key={index}
className={`hover:bg-primary/5 w-full cursor-pointer rounded-t border-b border-gray-200 dark:border-gray-800`}
className={`hover:bg-primary/5 w-full cursor-pointer rounded-t border-b border-border dark:border-border`}
onClick={() => handleSelect(option.value)}
>
<div
@ -179,7 +179,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
: ""
}`}
>
<div className="mx-2 leading-6 text-gray-800 dark:text-white/90">
<div className="mx-2 leading-6 text-foreground dark:text-foreground/90">
{option.label}
</div>
</div>

View File

@ -59,7 +59,7 @@ function NavigationMenuItem({
}
const navigationMenuTriggerStyle = cva(
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
"group inline-flex h-9 w-max items-center justify-center rounded-sm bg-background px-4 py-2 text-sm font-medium hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=open]:hover:bg-accent data-[state=open]:text-accent-foreground data-[state=open]:focus:bg-accent data-[state=open]:bg-accent/50 focus-visible:ring-ring/50 outline-none transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1"
);
function NavigationMenuTrigger({
@ -91,7 +91,7 @@ function NavigationMenuContent({
data-slot="navigation-menu-content"
className={cn(
"data-[motion^=from-]:animate-in data-[motion^=to-]:animate-out data-[motion^=from-]:fade-in data-[motion^=to-]:fade-out data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52 data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52 top-0 left-0 w-full p-2 pr-2.5 md:absolute md:w-auto",
"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-md group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
"group-data-[viewport=false]/navigation-menu:bg-popover group-data-[viewport=false]/navigation-menu:text-popover-foreground group-data-[viewport=false]/navigation-menu:data-[state=open]:animate-in group-data-[viewport=false]/navigation-menu:data-[state=closed]:animate-out group-data-[viewport=false]/navigation-menu:data-[state=closed]:zoom-out-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:zoom-in-95 group-data-[viewport=false]/navigation-menu:data-[state=open]:fade-in-0 group-data-[viewport=false]/navigation-menu:data-[state=closed]:fade-out-0 group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden group-data-[viewport=false]/navigation-menu:rounded-sm group-data-[viewport=false]/navigation-menu:border group-data-[viewport=false]/navigation-menu:shadow group-data-[viewport=false]/navigation-menu:duration-200 **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none",
className
)}
{...props}
@ -112,7 +112,7 @@ function NavigationMenuViewport({
<NavigationMenuPrimitive.Viewport
data-slot="navigation-menu-viewport"
className={cn(
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-md border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
"origin-top-center bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-90 relative mt-1.5 h-[var(--radix-navigation-menu-viewport-height)] w-full overflow-hidden rounded-sm border shadow md:w-[var(--radix-navigation-menu-viewport-width)]",
className
)}
{...props}

View File

@ -28,7 +28,7 @@ function PopoverContent({
align={align}
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-sm border border-border p-5 shadow-lg outline-hidden font-mono text-base",
className
)}
{...props}

View File

@ -12,7 +12,7 @@ function Progress({
<ProgressPrimitive.Root
data-slot="progress"
className={cn(
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
"bg-muted relative h-3 w-full overflow-hidden rounded-full border border-border",
className
)}
{...props}

View File

@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
"flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
"flex h-11 w-full items-center justify-between whitespace-nowrap rounded-sm border border-input bg-background px-4 py-2.5 text-base font-mono font-medium shadow-none ring-offset-background data-[placeholder]:text-muted-foreground focus:outline-none focus:border-primary focus:shadow-focus disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
className
)}
{...props}
@ -75,7 +75,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content
ref={ref}
className={cn(
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
"relative z-50 max-h-[--radix-select-content-available-height] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-sm border border-border bg-popover text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-select-content-transform-origin]",
position === "popper" &&
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
className
@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item
ref={ref}
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
"relative flex w-full cursor-default select-none items-center rounded-sm py-2.5 pl-4 pr-9 text-base font-mono outline-none focus:bg-muted focus:text-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 hover:bg-muted transition-colors",
className
)}
{...props}

View File

@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef<
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
"fixed z-50 gap-4 bg-background p-0 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out border-border",
{
variants: {
side: {
@ -108,7 +108,7 @@ const SheetTitle = React.forwardRef<
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
className={cn("text-xl font-mono font-bold uppercase tracking-wider text-foreground", className)}
{...props}
/>
));
@ -120,7 +120,7 @@ const SheetDescription = React.forwardRef<
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
className={cn("text-base text-foreground/70 font-mono", className)}
{...props}
/>
));

View File

@ -4,7 +4,7 @@ function Skeleton({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="skeleton"
className={cn("bg-accent animate-pulse rounded-md", className)}
className={cn("bg-muted animate-pulse rounded-sm", className)}
{...props}
/>
);

View File

@ -11,7 +11,7 @@ function Switch({
<SwitchPrimitive.Root
data-slot="switch"
className={cn(
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 dark:data-[state=unchecked]:bg-input/80 inline-flex h-[1.15rem] w-8 shrink-0 items-center rounded-full border border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-muted focus-visible:border-primary focus-visible:shadow-focus inline-flex h-7 w-12 shrink-0 items-center rounded-full border border-border shadow-none transition-all outline-none disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}
@ -19,7 +19,7 @@ function Switch({
<SwitchPrimitive.Thumb
data-slot="switch-thumb"
className={cn(
"bg-background dark:data-[state=unchecked]:bg-foreground dark:data-[state=checked]:bg-primary-foreground pointer-events-none block size-4 rounded-full ring-0 transition-transform data-[state=checked]:translate-x-[calc(100%-2px)] data-[state=unchecked]:translate-x-0"
"bg-background pointer-events-none block size-5.5 rounded-full ring-0 shadow-sm transition-transform data-[state=checked]:translate-x-5.5 data-[state=unchecked]:translate-x-0.5"
)}
/>
</SwitchPrimitive.Root>

View File

@ -6,11 +6,11 @@ function Table({ className, ...props }: React.ComponentProps<"table">) {
return (
<div
data-slot="table-container"
className="relative w-full overflow-x-auto"
className="relative w-full overflow-x-auto rounded-sm border border-border"
>
<table
data-slot="table"
className={cn("w-full caption-bottom text-sm", className)}
className={cn("w-full caption-bottom text-base font-mono", className)}
{...props}
/>
</div>
@ -21,7 +21,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
return (
<thead
data-slot="table-header"
className={cn("[&_tr]:border-b", className)}
className={cn("bg-muted/50 [&_tr]:border-b border-border", className)}
{...props}
/>
);
@ -55,7 +55,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
<tr
data-slot="table-row"
className={cn(
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
"hover:bg-muted/30 data-[state=selected]:bg-muted border-b border-border transition-colors",
className
)}
{...props}
@ -68,7 +68,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
<th
data-slot="table-head"
className={cn(
"text-foreground h-10 px-2 text-left align-middle font-medium whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
"text-foreground/70 h-12 px-4 text-left align-middle font-mono font-bold text-sm uppercase tracking-wider whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
)}
{...props}
@ -81,7 +81,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
<td
data-slot="table-cell"
className={cn(
"p-2 align-middle whitespace-nowrap [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
"px-4 py-3.5 align-middle text-foreground text-base [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
className
)}
{...props}

View File

@ -24,7 +24,7 @@ function TabsList({
<TabsPrimitive.List
data-slot="tabs-list"
className={cn(
"bg-muted text-muted-foreground inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]",
"bg-muted text-muted-foreground inline-flex h-12 w-fit items-center justify-center rounded-sm p-1.5 border border-border",
className
)}
{...props}
@ -40,7 +40,7 @@ function TabsTrigger({
<TabsPrimitive.Trigger
data-slot="tabs-trigger"
className={cn(
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 text-foreground dark:text-muted-foreground inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-[color,box-shadow] focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
"data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:border-primary/30 focus-visible:border-primary focus-visible:shadow-focus text-muted-foreground inline-flex h-10 flex-1 items-center justify-center gap-2 rounded-sm border border-transparent px-4 py-2 text-base font-mono font-semibold uppercase tracking-wider whitespace-nowrap transition-all disabled:pointer-events-none disabled:opacity-50 data-[state=active]:shadow-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-5",
className
)}
{...props}

View File

@ -7,7 +7,7 @@ export function Textarea({ className, ...props }: React.ComponentProps<"textarea
<textarea
data-slot="textarea"
className={cn(
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"border-input placeholder:text-muted-foreground focus-visible:border-primary focus-visible:shadow-focus aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-28 w-full rounded-sm border bg-background px-4 py-3 text-base font-mono font-medium leading-relaxed shadow-none transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50",
className
)}
{...props}

View File

@ -0,0 +1,194 @@
/**
* Theme Toggle Component
* Cyberpunk-styled theme switcher with smooth animations
*/
import { useTheme } from "next-themes";
import { useEffect, useState, useCallback } from "react";
import { Sun, Moon, Monitor } from "lucide-react";
import { cn } from "@/shared/utils/utils";
interface ThemeToggleProps {
collapsed?: boolean;
className?: string;
}
// Enable smooth theme transition
const enableTransition = () => {
const html = document.documentElement;
html.classList.add('theme-transition');
// Remove transition class after animation completes
setTimeout(() => {
html.classList.remove('theme-transition');
}, 280);
};
export function ThemeToggle({ collapsed = false, className }: ThemeToggleProps) {
const { theme, setTheme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
// Prevent hydration mismatch
useEffect(() => {
setMounted(true);
}, []);
// Smooth theme change handler
const handleThemeChange = useCallback((newTheme: string) => {
enableTransition();
setTheme(newTheme);
}, [setTheme]);
if (!mounted) {
return (
<div className={cn("h-10 w-full animate-pulse rounded-lg bg-muted", className)} />
);
}
const themes = [
{ value: "light", icon: Sun, label: "浅色" },
{ value: "dark", icon: Moon, label: "深色" },
{ value: "system", icon: Monitor, label: "系统" },
];
const currentTheme = themes.find((t) => t.value === theme) || themes[2];
const CurrentIcon = currentTheme.icon;
// Cycle through themes
const cycleTheme = () => {
const currentIndex = themes.findIndex((t) => t.value === theme);
const nextIndex = (currentIndex + 1) % themes.length;
handleThemeChange(themes[nextIndex].value);
};
// Collapsed mode - single button
if (collapsed) {
return (
<button
onClick={cycleTheme}
className={cn(
"flex items-center justify-center w-full h-10 rounded-lg",
"border border-transparent transition-colors duration-200",
"dark:text-muted-foreground dark:hover:text-primary dark:hover:bg-primary/10 dark:hover:border-primary/30",
"text-muted-foreground hover:text-primary hover:bg-primary/5 hover:border-primary/20",
className
)}
title={`当前: ${currentTheme.label}模式`}
>
<CurrentIcon
className={cn(
"w-6 h-6 transition-transform duration-200",
resolvedTheme === "dark" && "text-amber-400",
resolvedTheme === "light" && "text-orange-500"
)}
/>
</button>
);
}
// Expanded mode - segmented control
return (
<div className={cn("w-full", className)}>
<div className="flex items-center gap-2 px-3 py-2">
<span className="text-xs text-muted-foreground dark:text-muted-foreground font-mono uppercase tracking-wider">
</span>
</div>
<div
className={cn(
"flex items-center gap-1 p-1 mx-3 mb-2 rounded-lg",
"dark:cyber-bg-elevated dark:border dark:border-[#1a2535]",
"bg-muted border border-border"
)}
>
{themes.map(({ value, icon: Icon, label }) => {
const isActive = theme === value;
return (
<button
key={value}
onClick={() => handleThemeChange(value)}
className={cn(
"flex-1 flex items-center justify-center gap-1.5 py-1.5 px-2 rounded-md transition-all duration-200",
"text-xs font-mono uppercase tracking-wider",
isActive
? cn(
"dark:bg-primary/20 dark:text-primary dark:border dark:border-primary/40",
"bg-white text-primary border border-primary/30 shadow-sm"
)
: cn(
"dark:text-muted-foreground dark:hover:text-foreground dark:hover:bg-[#151a22]",
"text-muted-foreground hover:text-muted-foreground hover:bg-background"
)
)}
title={`${label}模式`}
>
<Icon
className={cn(
"w-3.5 h-3.5 transition-all duration-200",
isActive && value === "dark" && "text-amber-400",
isActive && value === "light" && "text-orange-500",
isActive && value === "system" && "text-cyan-400"
)}
/>
<span className="hidden sm:inline">{label}</span>
</button>
);
})}
</div>
</div>
);
}
// Compact version for dropdown menus
export function ThemeToggleCompact({ className }: { className?: string }) {
const { setTheme, resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
const handleToggle = useCallback(() => {
enableTransition();
setTheme(resolvedTheme === "dark" ? "light" : "dark");
}, [setTheme, resolvedTheme]);
if (!mounted) return null;
const isDark = resolvedTheme === "dark";
return (
<button
onClick={handleToggle}
className={cn(
"relative flex items-center justify-center w-10 h-10 rounded-lg",
"dark:cyber-bg-elevated dark:border dark:border-[#1a2535] dark:hover:border-primary/50",
"bg-muted border border-border hover:border-primary/50",
"group transition-colors duration-200",
className
)}
title={isDark ? "切换到浅色模式" : "切换到深色模式"}
>
{/* Sun icon */}
<Sun
className={cn(
"absolute w-5 h-5 transition-all duration-250",
isDark
? "opacity-0 rotate-90 scale-0"
: "opacity-100 rotate-0 scale-100 text-orange-500"
)}
/>
{/* Moon icon */}
<Moon
className={cn(
"absolute w-5 h-5 transition-all duration-250",
isDark
? "opacity-100 rotate-0 scale-100 text-amber-400"
: "opacity-0 -rotate-90 scale-0"
)}
/>
</button>
);
}
export default ThemeToggle;

View File

@ -26,7 +26,7 @@ function ToggleGroup({
data-variant={variant}
data-size={size}
className={cn(
"group/toggle-group flex w-fit items-center rounded-md data-[variant=outline]:shadow-xs",
"group/toggle-group flex w-fit items-center rounded-sm data-[variant=outline]:shadow-xs",
className
)}
{...props}

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/utils/utils";
const toggleVariants = cva(
"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
"inline-flex items-center justify-center gap-2 rounded-sm text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
{
variants: {
variant: {

View File

@ -46,13 +46,13 @@ function TooltipContent({
data-slot="tooltip-content"
sideOffset={sideOffset}
className={cn(
"bg-primary text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
"bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-sm px-4 py-2 text-sm font-mono text-balance shadow-lg",
className
)}
{...props}
>
{children}
<TooltipPrimitive.Arrow className="bg-primary fill-primary z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
<TooltipPrimitive.Arrow className="bg-foreground fill-foreground z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px]" />
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
);

View File

@ -138,17 +138,17 @@ export default function Account() {
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen bg-[#0a0a0f]">
<div className="flex items-center justify-center min-h-screen cyber-bg-elevated">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -157,7 +157,7 @@ export default function Account() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<User className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6 text-center">
<div className="relative inline-block mb-4">
@ -167,31 +167,31 @@ export default function Account() {
{getInitials(profile?.full_name, profile?.email)}
</AvatarFallback>
</Avatar>
<div className="absolute -bottom-1 -right-1 w-6 h-6 bg-emerald-500 rounded-full border-2 border-[#0a0a0f] flex items-center justify-center">
<div className="w-2 h-2 bg-white rounded-full animate-pulse" />
<div className="absolute -bottom-1 -right-1 w-6 h-6 bg-emerald-500 rounded-full border-2 border-background flex items-center justify-center">
<div className="w-2 h-2 bg-foreground rounded-full animate-pulse" />
</div>
</div>
<h4 className="text-lg font-bold text-white uppercase mb-1">
<h4 className="text-lg font-bold text-foreground uppercase mb-1">
{profile?.full_name || "未设置姓名"}
</h4>
<p className="text-gray-500 text-sm">{profile?.email}</p>
<p className="text-muted-foreground text-sm">{profile?.email}</p>
<div className="mt-6 pt-6 border-t border-gray-800 space-y-3 text-left">
<div className="mt-6 pt-6 border-t border-border space-y-3 text-left">
<div className="flex items-center gap-3 text-sm">
<Shield className="w-4 h-4 text-violet-400" />
<span className="text-gray-500">:</span>
<span className="text-muted-foreground">:</span>
<span className="text-violet-400 font-bold uppercase">
{profile?.role === 'admin' ? '管理员' : '成员'}
</span>
</div>
<div className="flex items-center gap-3 text-sm">
<Calendar className="w-4 h-4 text-sky-400" />
<span className="text-gray-500">:</span>
<span className="text-white font-mono">{formatDate(profile?.created_at)}</span>
<span className="text-muted-foreground">:</span>
<span className="text-foreground font-mono">{formatDate(profile?.created_at)}</span>
</div>
</div>
<div className="mt-6 pt-6 border-t border-gray-800 space-y-2">
<div className="mt-6 pt-6 border-t border-border space-y-2">
<Button
variant="outline"
onClick={handleSwitchAccount}
@ -216,24 +216,24 @@ export default function Account() {
<div className="lg:col-span-2 cyber-card p-0">
<div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6 space-y-6">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="email" className="text-xs font-bold text-gray-500 uppercase flex items-center gap-2">
<Label htmlFor="email" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
<Mail className="w-3 h-3" />
</Label>
<Input
id="email"
value={profile?.email || ""}
disabled
className="cyber-input bg-gray-900/50 text-gray-500 cursor-not-allowed"
className="cyber-input bg-muted text-muted-foreground cursor-not-allowed"
/>
<p className="text-xs text-gray-600"></p>
<p className="text-xs text-muted-foreground"></p>
</div>
<div className="space-y-2">
<Label htmlFor="full_name" className="text-xs font-bold text-gray-500 uppercase flex items-center gap-2">
<Label htmlFor="full_name" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
<User className="w-3 h-3" />
</Label>
<Input
@ -245,7 +245,7 @@ export default function Account() {
/>
</div>
<div className="space-y-2">
<Label htmlFor="phone" className="text-xs font-bold text-gray-500 uppercase flex items-center gap-2">
<Label htmlFor="phone" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
<Phone className="w-3 h-3" />
</Label>
<Input
@ -258,14 +258,14 @@ export default function Account() {
</div>
</div>
<div className="pt-6 border-t border-gray-800">
<div className="pt-6 border-t border-border">
<h3 className="section-title text-sm mb-4 flex items-center gap-2">
<GitBranch className="w-4 h-4" />
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="github" className="text-xs font-bold text-gray-500 uppercase flex items-center gap-2">
<Label htmlFor="github" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
<GitBranch className="w-3 h-3" /> GitHub
</Label>
<Input
@ -277,7 +277,7 @@ export default function Account() {
/>
</div>
<div className="space-y-2">
<Label htmlFor="gitlab" className="text-xs font-bold text-gray-500 uppercase flex items-center gap-2">
<Label htmlFor="gitlab" className="text-xs font-bold text-muted-foreground uppercase flex items-center gap-2">
<GitBranch className="w-3 h-3" /> GitLab
</Label>
<Input
@ -313,12 +313,12 @@ export default function Account() {
<div className="lg:col-span-3 cyber-card p-0">
<div className="cyber-card-header">
<KeyRound className="w-5 h-5 text-amber-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6">
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="space-y-2">
<Label htmlFor="new_password" className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label htmlFor="new_password" className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input
id="new_password"
type="password"
@ -329,7 +329,7 @@ export default function Account() {
/>
</div>
<div className="space-y-2">
<Label htmlFor="confirm_password" className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label htmlFor="confirm_password" className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input
id="confirm_password"
type="password"
@ -365,13 +365,13 @@ export default function Account() {
{/* Logout Confirmation Dialog */}
<AlertDialog open={showLogoutDialog} onOpenChange={setShowLogoutDialog}>
<AlertDialogContent className="cyber-card border-rose-500/30 bg-[#0c0c12]">
<AlertDialogContent className="cyber-card border-rose-500/30 cyber-dialog">
<AlertDialogHeader>
<AlertDialogTitle className="text-lg font-bold uppercase text-white flex items-center gap-2">
<AlertDialogTitle className="text-lg font-bold uppercase text-foreground flex items-center gap-2">
<LogOut className="w-5 h-5 text-rose-400" />
退
</AlertDialogTitle>
<AlertDialogDescription className="text-gray-400">
<AlertDialogDescription className="text-muted-foreground">
退访
</AlertDialogDescription>
</AlertDialogHeader>

View File

@ -10,7 +10,7 @@ import { Settings, Database, Terminal } from "lucide-react";
export default function AdminDashboard() {
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -19,24 +19,24 @@ export default function AdminDashboard() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" />
<h1 className="text-lg font-bold uppercase tracking-wider text-white"></h1>
<h1 className="text-lg font-bold uppercase tracking-wider text-foreground"></h1>
</div>
</div>
</div>
{/* Main Content Tabs */}
<Tabs defaultValue="config" className="w-full relative z-10">
<TabsList className="grid w-full grid-cols-2 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded-lg mb-6">
<TabsList className="grid w-full grid-cols-2 bg-muted border border-border p-1 h-auto gap-1 rounded-lg mb-6">
<TabsTrigger
value="config"
className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-3 text-gray-400 transition-all rounded text-sm flex items-center gap-2"
className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-3 text-muted-foreground transition-all rounded text-sm flex items-center gap-2"
>
<Settings className="w-4 h-4" />
</TabsTrigger>
<TabsTrigger
value="data"
className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-3 text-gray-400 transition-all rounded text-sm flex items-center gap-2"
className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-3 text-muted-foreground transition-all rounded text-sm flex items-center gap-2"
>
<Database className="w-4 h-4" />

View File

@ -53,7 +53,7 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-primary/50 to-transparent" />
{/* Header */}
<div className="flex items-center justify-between p-3 border-b border-gray-800/50">
<div className="flex items-center justify-between p-3 border-b border-border">
<div className="flex items-center gap-2.5">
{/* Agent type icon with color */}
<div className={`text-${typeConfig.color}-400`}>
@ -62,22 +62,22 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Agent name */}
<div>
<span className="text-sm font-medium text-white block">{agent.agent_name}</span>
<span className="text-[10px] text-gray-500 uppercase tracking-wider">{typeConfig.label}</span>
<span className="text-sm font-medium text-foreground block">{agent.agent_name}</span>
<span className="text-xs text-muted-foreground uppercase tracking-wider">{typeConfig.label}</span>
</div>
</div>
{/* Close button */}
<button
onClick={onClose}
className="w-6 h-6 flex items-center justify-center rounded hover:bg-white/10 transition-colors text-gray-500 hover:text-white"
className="w-6 h-6 flex items-center justify-center rounded hover:bg-white/10 transition-colors text-muted-foreground hover:text-foreground"
>
<X className="w-4 h-4" />
</button>
</div>
{/* Status indicator */}
<div className="px-3 py-2 border-b border-gray-800/50 bg-gray-900/20">
<div className="px-3 py-2 border-b border-border bg-muted/30">
<div className="flex items-center gap-2">
<div className="relative">
<div className={`
@ -86,7 +86,7 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
${agent.status === 'completed' ? 'bg-green-500' : ''}
${agent.status === 'failed' ? 'bg-red-400' : ''}
${agent.status === 'waiting' ? 'bg-yellow-400' : ''}
${agent.status === 'created' ? 'bg-gray-500' : ''}
${agent.status === 'created' ? 'bg-background0' : ''}
`} />
{isRunning && (
<div className="absolute inset-0 w-2.5 h-2.5 rounded-full bg-green-400 animate-ping opacity-30" />
@ -101,30 +101,30 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Metrics grid */}
<div className="p-3 grid grid-cols-2 gap-2">
{/* Iterations */}
<div className="flex items-center gap-2 p-2 rounded bg-gray-900/30 border border-gray-800/30">
<div className="flex items-center gap-2 p-2 rounded bg-muted/50 border border-border">
<Repeat className="w-3.5 h-3.5 text-cyan-400/70" />
<div>
<div className="text-[9px] text-gray-600 uppercase">Iterations</div>
<div className="text-sm text-white font-mono">{agent.iterations || 0}</div>
<div className="text-xs text-muted-foreground uppercase">Iterations</div>
<div className="text-sm text-foreground font-mono">{agent.iterations || 0}</div>
</div>
</div>
{/* Tool Calls */}
<div className="flex items-center gap-2 p-2 rounded bg-gray-900/30 border border-gray-800/30">
<div className="flex items-center gap-2 p-2 rounded bg-muted/50 border border-border">
<Zap className="w-3.5 h-3.5 text-amber-400/70" />
<div>
<div className="text-[9px] text-gray-600 uppercase">Tool Calls</div>
<div className="text-sm text-white font-mono">{agent.tool_calls || 0}</div>
<div className="text-xs text-muted-foreground uppercase">Tool Calls</div>
<div className="text-sm text-foreground font-mono">{agent.tool_calls || 0}</div>
</div>
</div>
{/* Findings - Only show for Orchestrator (root agent with no parent) */}
{!agent.parent_agent_id && (
<div className="flex items-center gap-2 p-2 rounded bg-gray-900/30 border border-gray-800/30">
<Bug className={`w-3.5 h-3.5 ${agent.findings_count > 0 ? 'text-red-400/70' : 'text-gray-500/70'}`} />
<div className="flex items-center gap-2 p-2 rounded bg-muted/50 border border-border">
<Bug className={`w-3.5 h-3.5 ${agent.findings_count > 0 ? 'text-red-400/70' : 'text-muted-foreground/70'}`} />
<div>
<div className="text-[9px] text-gray-600 uppercase">Findings</div>
<div className={`text-sm font-mono ${agent.findings_count > 0 ? 'text-red-400' : 'text-white'}`}>
<div className="text-xs text-muted-foreground uppercase">Findings</div>
<div className={`text-sm font-mono ${agent.findings_count > 0 ? 'text-red-400' : 'text-foreground'}`}>
{agent.findings_count}
</div>
</div>
@ -133,13 +133,13 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Duration/Status - Show for sub-agents instead of Findings */}
{agent.parent_agent_id && (
<div className="flex items-center gap-2 p-2 rounded bg-gray-900/30 border border-gray-800/30">
<Clock className="w-3.5 h-3.5 text-slate-400/70" />
<div className="flex items-center gap-2 p-2 rounded bg-muted/50 border border-border">
<Clock className="w-3.5 h-3.5 text-muted-foreground/70" />
<div>
<div className="text-[9px] text-gray-600 uppercase">
<div className="text-xs text-muted-foreground uppercase">
{agent.duration_ms ? "Duration" : "Status"}
</div>
<div className="text-sm text-white font-mono">
<div className="text-sm text-foreground font-mono">
{agent.duration_ms
? `${(agent.duration_ms / 1000).toFixed(1)}s`
: (AGENT_STATUS_CONFIG[agent.status]?.text || agent.status)
@ -150,11 +150,11 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
)}
{/* Tokens */}
<div className="flex items-center gap-2 p-2 rounded bg-gray-900/30 border border-gray-800/30">
<div className="flex items-center gap-2 p-2 rounded bg-muted/50 border border-border">
<FileCode className="w-3.5 h-3.5 text-purple-400/70" />
<div>
<div className="text-[9px] text-gray-600 uppercase">Tokens</div>
<div className="text-sm text-white font-mono">
<div className="text-xs text-muted-foreground uppercase">Tokens</div>
<div className="text-sm text-foreground font-mono">
{((agent.tokens_used || 0) / 1000).toFixed(1)}k
</div>
</div>
@ -164,12 +164,12 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Task description */}
{agent.task_description && (
<div className="px-3 pb-3">
<div className="p-2.5 rounded bg-gray-900/30 border border-gray-800/30">
<div className="p-2.5 rounded bg-muted/50 border border-border">
<div className="flex items-center gap-1.5 mb-1.5">
<Clock className="w-3 h-3 text-gray-500" />
<span className="text-[9px] text-gray-500 uppercase tracking-wider">Current Task</span>
<Clock className="w-3 h-3 text-muted-foreground" />
<span className="text-xs text-muted-foreground uppercase tracking-wider">Current Task</span>
</div>
<p className="text-xs text-gray-400 leading-relaxed line-clamp-3">
<p className="text-xs text-muted-foreground leading-relaxed line-clamp-3">
{agent.task_description}
</p>
</div>
@ -179,7 +179,7 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Sub-agents indicator */}
{agent.children && agent.children.length > 0 && (
<div className="px-3 pb-3">
<div className="flex items-center gap-2 text-[10px] text-gray-500">
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Network className="w-3 h-3" />
<span className="uppercase tracking-wider">
{agent.children.length} Sub-agent{agent.children.length > 1 ? 's' : ''}

View File

@ -165,7 +165,7 @@ export class AgentErrorBoundary extends Component<Props, State> {
}
return (
<div className="h-screen bg-[#0a0a0f] flex items-center justify-center p-4">
<div className="h-screen cyber-bg-elevated flex items-center justify-center p-4">
<div className="w-full max-w-lg space-y-6">
{/* Error Header */}
<div className="flex items-center gap-4">
@ -179,16 +179,16 @@ export class AgentErrorBoundary extends Component<Props, State> {
)} />
</div>
<div>
<h2 className="text-xl font-bold text-white">Agent Error</h2>
<p className="text-sm text-gray-400">{this.getRecoveryHint()}</p>
<h2 className="text-xl font-bold text-foreground">Agent Error</h2>
<p className="text-sm text-muted-foreground">{this.getRecoveryHint()}</p>
</div>
</div>
{/* Error Details */}
<div className="bg-[#0d0d12] border border-gray-800 rounded-lg overflow-hidden">
<div className="px-4 py-3 border-b border-gray-800 flex items-center gap-2">
<Terminal className="w-4 h-4 text-gray-500" />
<span className="text-xs text-gray-500 uppercase tracking-wider font-bold">
<div className="cyber-dialog border border-border rounded-lg overflow-hidden">
<div className="px-4 py-3 border-b border-border flex items-center gap-2">
<Terminal className="w-4 h-4 text-muted-foreground" />
<span className="text-xs text-muted-foreground uppercase tracking-wider font-bold">
Error Details
</span>
</div>
@ -199,20 +199,20 @@ export class AgentErrorBoundary extends Component<Props, State> {
<Bug className="w-4 h-4 text-red-400 mt-0.5 flex-shrink-0" />
<div>
<p className="text-sm font-mono text-red-400">{error.name}</p>
<p className="text-sm text-gray-300">{error.message}</p>
<p className="text-sm text-foreground">{error.message}</p>
</div>
</div>
</div>
)}
{this.props.taskId && (
<div className="text-xs text-gray-500">
Task ID: <span className="font-mono text-gray-400">{this.props.taskId}</span>
<div className="text-xs text-muted-foreground">
Task ID: <span className="font-mono text-muted-foreground">{this.props.taskId}</span>
</div>
)}
{retryCount > 0 && (
<div className="text-xs text-gray-500">
<div className="text-xs text-muted-foreground">
Retry attempts: <span className="text-yellow-400">{retryCount}/{maxRetries}</span>
</div>
)}
@ -220,10 +220,10 @@ export class AgentErrorBoundary extends Component<Props, State> {
{/* Stack trace (dev only) */}
{import.meta.env.DEV && error?.stack && (
<details className="text-xs">
<summary className="cursor-pointer text-gray-500 hover:text-gray-300 transition-colors">
<summary className="cursor-pointer text-muted-foreground hover:text-foreground transition-colors">
Stack Trace
</summary>
<pre className="mt-2 p-3 bg-black/50 rounded text-[10px] text-gray-400 overflow-auto max-h-40">
<pre className="mt-2 p-3 bg-background/50 rounded text-xs text-muted-foreground overflow-auto max-h-40">
{error.stack}
</pre>
</details>
@ -231,10 +231,10 @@ export class AgentErrorBoundary extends Component<Props, State> {
{import.meta.env.DEV && errorInfo?.componentStack && (
<details className="text-xs">
<summary className="cursor-pointer text-gray-500 hover:text-gray-300 transition-colors">
<summary className="cursor-pointer text-muted-foreground hover:text-foreground transition-colors">
Component Stack
</summary>
<pre className="mt-2 p-3 bg-black/50 rounded text-[10px] text-gray-400 overflow-auto max-h-40">
<pre className="mt-2 p-3 bg-background/50 rounded text-xs text-muted-foreground overflow-auto max-h-40">
{errorInfo.componentStack}
</pre>
</details>
@ -257,7 +257,7 @@ export class AgentErrorBoundary extends Component<Props, State> {
<Button
onClick={this.handleGoBack}
variant="outline"
className="flex-1 border-gray-700 hover:bg-gray-800"
className="flex-1 border-border hover:bg-muted"
>
<ArrowLeft className="w-4 h-4 mr-2" />
Go Back
@ -265,7 +265,7 @@ export class AgentErrorBoundary extends Component<Props, State> {
<Button
onClick={this.handleReload}
variant="ghost"
className="flex-1 text-gray-400 hover:text-white"
className="flex-1 text-muted-foreground hover:text-foreground"
>
Refresh Page
</Button>
@ -273,7 +273,7 @@ export class AgentErrorBoundary extends Component<Props, State> {
{/* Recovery suggestion */}
{!canRetry && (
<p className="text-center text-xs text-gray-500">
<p className="text-center text-xs text-muted-foreground">
Maximum retry attempts reached. Please refresh the page or contact support.
</p>
)}

View File

@ -11,12 +11,12 @@ import { Badge } from "@/components/ui/badge";
import { AGENT_STATUS_CONFIG } from "../constants";
import type { AgentTreeNodeItemProps } from "../types";
// Agent type icons with enhanced colors
// Agent type icons with enhanced colors (light/dark mode compatible)
const AGENT_TYPE_ICONS: Record<string, React.ReactNode> = {
orchestrator: <Cpu className="w-3.5 h-3.5 text-violet-400" />,
recon: <Scan className="w-3.5 h-3.5 text-teal-400" />,
analysis: <FileSearch className="w-3.5 h-3.5 text-amber-400" />,
verification: <ShieldCheck className="w-3.5 h-3.5 text-emerald-400" />,
orchestrator: <Cpu className="w-4 h-4 text-violet-600 dark:text-violet-400" />,
recon: <Scan className="w-4 h-4 text-teal-600 dark:text-teal-400" />,
analysis: <FileSearch className="w-4 h-4 text-amber-600 dark:text-amber-400" />,
verification: <ShieldCheck className="w-4 h-4 text-emerald-600 dark:text-emerald-400" />,
};
// Status colors for the glow effect
@ -40,14 +40,14 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
const isRunning = node.status === 'running';
const statusConfig = AGENT_STATUS_CONFIG[node.status] || AGENT_STATUS_CONFIG.created;
const typeIcon = AGENT_TYPE_ICONS[node.agent_type] || <Bot className="w-3.5 h-3.5 text-slate-400" />;
const typeIcon = AGENT_TYPE_ICONS[node.agent_type] || <Bot className="w-3.5 h-3.5 text-muted-foreground" />;
return (
<div className="relative">
{/* Connection line to parent - vertical line */}
{depth > 0 && (
<div
className="absolute top-0 w-px bg-gradient-to-b from-slate-600 to-slate-700"
className="absolute top-0 w-px bg-gradient-to-b from-border to-border"
style={{
left: `${depth * 16 - 8}px`,
height: '20px',
@ -58,7 +58,7 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
{/* Horizontal connector line */}
{depth > 0 && (
<div
className="absolute top-[20px] h-px bg-slate-600"
className="absolute top-[20px] h-px bg-muted-foreground"
style={{
left: `${depth * 16 - 8}px`,
width: '8px',
@ -73,7 +73,7 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
transition-all duration-200 ease-out
${isSelected
? 'bg-primary/15 border border-primary/40'
: 'border border-transparent hover:bg-white/5 hover:border-slate-700/50'
: 'border border-transparent hover:bg-white/5 hover:border-border/50'
}
${STATUS_GLOW_COLORS[node.status] || ''}
`}
@ -87,9 +87,9 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
className="flex-shrink-0 w-5 h-5 flex items-center justify-center rounded hover:bg-white/10 transition-colors"
>
{expanded ? (
<ChevronDown className="w-3.5 h-3.5 text-slate-400" />
<ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
) : (
<ChevronRight className="w-3.5 h-3.5 text-slate-400" />
<ChevronRight className="w-3.5 h-3.5 text-muted-foreground" />
)}
</button>
) : (
@ -104,7 +104,7 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
${node.status === 'completed' ? 'bg-emerald-500' : ''}
${node.status === 'failed' ? 'bg-rose-400' : ''}
${node.status === 'waiting' ? 'bg-amber-400' : ''}
${node.status === 'created' ? 'bg-slate-500' : ''}
${node.status === 'created' ? 'bg-muted' : ''}
`} />
{isRunning && (
<div className="absolute inset-0 w-2.5 h-2.5 rounded-full bg-emerald-400 animate-ping opacity-30" />
@ -118,8 +118,8 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
{/* Agent name */}
<span className={`
text-xs font-mono truncate flex-1 transition-colors duration-200
${isSelected ? 'text-white font-medium' : 'text-slate-300 group-hover:text-white'}
text-sm font-mono truncate flex-1 transition-colors duration-200
${isSelected ? 'text-foreground font-medium' : 'text-foreground group-hover:text-foreground'}
`}>
{node.agent_name}
</span>
@ -128,14 +128,14 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
<div className="flex items-center gap-1.5 flex-shrink-0">
{/* Iterations */}
{(node.iterations ?? 0) > 0 && (
<span className="text-[9px] text-slate-400 font-mono bg-slate-800/60 px-1.5 py-0.5 rounded">
<span className="text-xs text-muted-foreground font-mono bg-muted px-1.5 py-0.5 rounded">
{node.iterations}x
</span>
)}
{/* Findings count - Only show for Orchestrator (root agent) */}
{!node.parent_agent_id && node.findings_count > 0 && (
<Badge className="h-4 px-1.5 text-[9px] bg-rose-500/25 text-rose-300 border border-rose-500/40 font-mono font-semibold">
<Badge className="h-5 px-2 text-sm bg-rose-500/25 text-rose-700 dark:text-rose-300 border border-rose-500/40 font-mono font-semibold">
{node.findings_count}
</Badge>
)}
@ -152,7 +152,7 @@ export const AgentTreeNodeItem = memo(function AgentTreeNodeItem({
>
{/* Vertical connection line for children */}
<div
className="absolute w-px bg-gradient-to-b from-slate-600 via-slate-700 to-transparent"
className="absolute w-px bg-gradient-to-b from-border via-border to-transparent"
style={{
left: `${(depth + 1) * 16 - 8}px`,
top: '0',

View File

@ -24,8 +24,8 @@ const STATUS_CONFIG: Record<ConnectionState, {
disconnected: {
icon: WifiOff,
label: 'Disconnected',
color: 'text-gray-400',
bgColor: 'bg-gray-400/10',
color: 'text-muted-foreground',
bgColor: 'bg-muted/30',
},
connecting: {
icon: RefreshCw,
@ -67,7 +67,7 @@ export function ConnectionStatus({
return (
<div className={cn('flex items-center gap-1.5', className)}>
<div className={cn(
'flex items-center gap-1 px-2 py-0.5 rounded-full text-[10px] font-medium',
'flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium',
config.bgColor,
config.color
)}>

View File

@ -18,21 +18,21 @@ export function Header({
onNewAudit
}: HeaderProps) {
return (
<header className="flex-shrink-0 h-14 border-b border-gray-800/80 flex items-center justify-between px-5 bg-gradient-to-r from-[#0d0d12] via-[#0e0e14] to-[#0d0d12] relative overflow-hidden">
<header className="flex-shrink-0 h-14 border-b border-border flex items-center justify-between px-5 bg-card relative overflow-hidden">
{/* Subtle animated line at top */}
<div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-primary/30 to-transparent" />
{/* Left side - Brand and task info */}
<div className="flex items-center gap-4">
{/* Logo section */}
<div className="flex items-center gap-2.5 pr-4 border-r border-gray-800/50">
<div className="flex items-center gap-2.5 pr-4 border-r border-border">
<div className="relative">
<Cpu className="w-5 h-5 text-primary" />
{isRunning && (
<span className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-green-400 rounded-full animate-pulse" />
)}
</div>
<span className="font-bold text-white tracking-wide text-sm">
<span className="font-bold text-foreground tracking-wide text-sm">
DEEP<span className="text-primary">AUDIT</span>
</span>
</div>
@ -40,11 +40,11 @@ export function Header({
{/* Task info */}
{task && (
<div className="flex items-center gap-3">
<div className="flex items-center gap-2 text-gray-400">
<div className="flex items-center gap-2 text-muted-foreground">
<Radio className="w-3 h-3" />
<span className="text-xs font-mono uppercase tracking-wider">Task</span>
</div>
<span className="text-gray-300 text-sm font-mono truncate max-w-[180px]">
<span className="text-foreground text-sm font-mono truncate max-w-[180px]">
{task.name || task.id.slice(0, 8)}
</span>
<StatusBadge status={task.status} />
@ -76,7 +76,7 @@ export function Header({
</Button>
)}
<div className="h-6 w-px bg-gray-800/50 mx-1" />
<div className="h-6 w-px bg-muted mx-1" />
<Button
variant="ghost"

View File

@ -93,8 +93,8 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
<div className={`
relative rounded border-l-2 overflow-hidden
${config.borderColor}
${isExpanded ? 'bg-gray-900/60' : 'bg-gray-900/30'}
${isCollapsible ? 'hover:bg-gray-900/50' : ''}
${isExpanded ? 'bg-card/60' : 'bg-muted/50'}
${isCollapsible ? 'hover:bg-muted' : ''}
${isFinding ? 'border-r border-r-red-900/30' : ''}
${isError ? 'border-r border-r-red-900/30' : ''}
transition-all duration-200
@ -120,35 +120,35 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Type label */}
<span className={`
text-[9px] font-mono font-bold uppercase tracking-wider px-1.5 py-0.5 rounded
${isThinking ? 'bg-violet-500/25 text-violet-300' : ''}
${isTool ? 'bg-amber-500/25 text-amber-300' : ''}
${isFinding ? 'bg-rose-500/25 text-rose-300' : ''}
${isError ? 'bg-red-500/25 text-red-300' : ''}
${isInfo ? 'bg-slate-500/25 text-slate-300' : ''}
${isProgress ? 'bg-cyan-500/25 text-cyan-300' : ''}
${item.type === 'dispatch' ? 'bg-sky-500/25 text-sky-300' : ''}
${item.type === 'phase' ? 'bg-teal-500/25 text-teal-300' : ''}
${item.type === 'user' ? 'bg-indigo-500/25 text-indigo-300' : ''}
text-sm font-mono font-bold uppercase tracking-wider px-2.5 py-1 rounded
${isThinking ? 'bg-violet-500/30 text-violet-700 dark:text-violet-300' : ''}
${isTool ? 'bg-amber-500/30 text-amber-700 dark:text-amber-300' : ''}
${isFinding ? 'bg-rose-500/30 text-rose-700 dark:text-rose-300' : ''}
${isError ? 'bg-red-500/30 text-red-700 dark:text-red-300' : ''}
${isInfo ? 'bg-muted text-foreground' : ''}
${isProgress ? 'bg-cyan-500/30 text-cyan-700 dark:text-cyan-300' : ''}
${item.type === 'dispatch' ? 'bg-sky-500/30 text-sky-700 dark:text-sky-300' : ''}
${item.type === 'phase' ? 'bg-teal-500/30 text-teal-700 dark:text-teal-300' : ''}
${item.type === 'user' ? 'bg-indigo-500/30 text-indigo-700 dark:text-indigo-300' : ''}
flex-shrink-0
`}>
{LOG_TYPE_LABELS[item.type] || 'LOG'}
</span>
{/* Timestamp */}
<span className="text-[10px] text-gray-600 font-mono flex-shrink-0">
<span className="text-xs text-muted-foreground font-mono flex-shrink-0">
{item.time}
</span>
{/* Separator */}
<ArrowRight className="w-3 h-3 text-gray-700 flex-shrink-0" />
<ArrowRight className="w-3 h-3 text-muted-foreground flex-shrink-0" />
{/* Status icon for info messages */}
{statusIcon && <span className="flex-shrink-0">{statusIcon}</span>}
{/* Title - for non-thinking types */}
{!isThinking && (
<span className="text-sm text-gray-300 truncate flex-1">
<span className="text-base text-foreground font-medium truncate flex-1">
{formattedTitle}
</span>
)}
@ -162,7 +162,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.tool?.status === 'running' && (
<div className="flex items-center gap-1.5 flex-shrink-0 bg-amber-500/10 px-2 py-0.5 rounded">
<Loader2 className="w-3 h-3 animate-spin text-amber-400" />
<span className="text-[9px] text-amber-400 font-mono uppercase">Running</span>
<span className="text-xs text-amber-400 font-mono uppercase">Running</span>
</div>
)}
@ -176,7 +176,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.agentName && (
<Badge
variant="outline"
className="h-5 px-2 text-[9px] uppercase tracking-wider border-primary/40 text-primary bg-primary/10 flex-shrink-0 font-semibold"
className="h-5 px-2 text-xs uppercase tracking-wider border-primary/40 text-primary bg-primary/10 flex-shrink-0 font-semibold"
>
{item.agentName}
</Badge>
@ -186,7 +186,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
<div className="flex items-center gap-2 flex-shrink-0 ml-auto">
{/* Duration badge */}
{item.tool?.duration !== undefined && (
<span className="text-[10px] text-gray-500 font-mono bg-gray-800/50 px-1.5 py-0.5 rounded">
<span className="text-xs text-muted-foreground font-mono bg-muted px-1.5 py-0.5 rounded">
{item.tool.duration}ms
</span>
)}
@ -195,7 +195,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.severity && (
<Badge
className={`
text-[9px] uppercase tracking-wider font-bold px-1.5 py-0
text-xs uppercase tracking-wider font-bold px-1.5 py-0
${SEVERITY_COLORS[item.severity] || SEVERITY_COLORS.info}
`}
>
@ -205,11 +205,11 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Expand indicator */}
{isCollapsible && (
<div className="w-5 h-5 flex items-center justify-center rounded bg-gray-800/30 group-hover:bg-gray-800/50 transition-colors">
<div className="w-5 h-5 flex items-center justify-center rounded bg-muted/50 group-hover:bg-muted/50 transition-colors">
{isExpanded ? (
<ChevronUp className="w-3.5 h-3.5 text-gray-500" />
<ChevronUp className="w-3.5 h-3.5 text-muted-foreground" />
) : (
<ChevronDown className="w-3.5 h-3.5 text-gray-500" />
<ChevronDown className="w-3.5 h-3.5 text-muted-foreground" />
)}
</div>
)}
@ -220,7 +220,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{isThinking && item.content && (
<div className="mt-2.5 relative">
<div className="absolute left-0 top-0 bottom-0 w-px bg-gradient-to-b from-purple-500/50 via-purple-500/20 to-transparent" />
<div className="pl-3 text-sm text-purple-200/90 leading-relaxed whitespace-pre-wrap break-words">
<div className="pl-3 text-base text-foreground/90 leading-relaxed whitespace-pre-wrap break-words">
{item.content}
</div>
</div>
@ -229,24 +229,24 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Collapsible content */}
{!isThinking && showContent && item.content && (
<div className="mt-2.5 overflow-hidden">
<div className="bg-[#08080c] rounded border border-gray-800/50 overflow-hidden">
<div className="bg-card rounded border border-border overflow-hidden">
{/* Mini header */}
<div className="flex items-center justify-between px-2.5 py-1.5 border-b border-gray-800/50 bg-gray-900/50">
<div className="flex items-center justify-between px-2.5 py-1.5 border-b border-border bg-muted">
<div className="flex items-center gap-2">
<Square className="w-2.5 h-2.5 text-gray-600" />
<span className="text-[9px] text-gray-500 font-mono uppercase tracking-wider">
<Square className="w-2.5 h-2.5 text-muted-foreground" />
<span className="text-xs text-muted-foreground font-mono uppercase tracking-wider">
{isTool ? 'Output' : 'Details'}
</span>
</div>
{item.tool?.status === 'completed' && (
<div className="flex items-center gap-1">
<CheckCircle2 className="w-3 h-3 text-green-500/70" />
<span className="text-[9px] text-green-500/70 font-mono">Complete</span>
<span className="text-xs text-green-500/70 font-mono">Complete</span>
</div>
)}
</div>
{/* Content */}
<pre className="p-3 text-xs font-mono text-gray-400 max-h-56 overflow-y-auto custom-scrollbar whitespace-pre-wrap break-words leading-relaxed">
<pre className="p-3 text-base font-mono text-foreground/80 max-h-56 overflow-y-auto custom-scrollbar whitespace-pre-wrap break-words leading-relaxed">
{item.content}
</pre>
</div>

View File

@ -130,7 +130,7 @@ function getSeverityColor(severity: string): string {
high: "text-orange-400",
medium: "text-amber-400",
low: "text-sky-400",
info: "text-slate-400",
info: "text-muted-foreground",
};
return colors[severity.toLowerCase()] || colors.info;
}
@ -181,7 +181,7 @@ const CircularProgress = memo(function CircularProgress({
fill="none"
stroke="currentColor"
strokeWidth={strokeWidth}
className="text-slate-800/50"
className="text-foreground/50"
/>
{/* Progress circle */}
<circle
@ -200,7 +200,7 @@ const CircularProgress = memo(function CircularProgress({
<span className={`text-xl font-bold font-mono ${colors.text}`}>
{value.toFixed(0)}
</span>
<span className="text-[8px] text-slate-500 uppercase tracking-wider"></span>
<span className="text-[8px] text-muted-foreground uppercase tracking-wider"></span>
</div>
</div>
);
@ -223,7 +223,7 @@ const EnhancedStatsPanel = memo(function EnhancedStatsPanel({
icon: <Bug className="w-4 h-4" />,
label: "漏洞总数",
value: totalFindings,
color: "text-white",
color: "text-foreground",
iconColor: "text-rose-400",
trend: totalFindings > 0 ? "up" : null,
},
@ -231,7 +231,7 @@ const EnhancedStatsPanel = memo(function EnhancedStatsPanel({
icon: <AlertTriangle className="w-4 h-4" />,
label: "高危问题",
value: criticalAndHigh,
color: criticalAndHigh > 0 ? "text-rose-400" : "text-slate-400",
color: criticalAndHigh > 0 ? "text-rose-400" : "text-muted-foreground",
iconColor: "text-orange-400",
trend: criticalAndHigh > 0 ? "critical" : null,
},
@ -248,7 +248,7 @@ const EnhancedStatsPanel = memo(function EnhancedStatsPanel({
return (
<div className="flex items-stretch gap-4">
{/* 环形安全评分 */}
<div className="flex items-center justify-center p-3 rounded-xl bg-gradient-to-br from-slate-800/60 to-slate-900/60 border border-slate-700/40 backdrop-blur-sm">
<div className="flex items-center justify-center p-3 rounded-xl bg-gradient-to-br from-muted to-background border border-border backdrop-blur-sm">
<CircularProgress value={score} size={72} strokeWidth={5} />
</div>
@ -257,13 +257,13 @@ const EnhancedStatsPanel = memo(function EnhancedStatsPanel({
{stats.map((stat, index) => (
<div
key={index}
className="relative p-3 rounded-xl bg-gradient-to-br from-slate-800/40 to-slate-900/40 border border-slate-700/30 backdrop-blur-sm group hover:border-slate-600/50 transition-all duration-300"
className="relative p-3 rounded-xl bg-gradient-to-br from-muted/40 to-background/40 border border-border backdrop-blur-sm group hover:border-border transition-all duration-300"
>
<div className="flex items-center gap-2 mb-1.5">
<div className={`${stat.iconColor} opacity-80`}>
{stat.icon}
</div>
<span className="text-[10px] text-slate-500 uppercase tracking-wider font-medium">
<span className="text-xs text-muted-foreground uppercase tracking-wider font-medium">
{stat.label}
</span>
</div>
@ -307,25 +307,25 @@ const FormatSelector = memo(function FormatSelector({
relative p-4 rounded-xl border transition-all duration-300 text-left group
${isActive
? `${config.bgColor} border-opacity-100 shadow-lg`
: "bg-slate-800/30 border-slate-700/30 hover:border-slate-600/50 hover:bg-slate-800/50"
: "bg-muted border-border hover:border-border hover:bg-muted"
}
`}
>
{/* 选中指示器 */}
{isActive && (
<div className="absolute -top-1 -right-1 w-5 h-5 rounded-full bg-primary flex items-center justify-center shadow-lg shadow-primary/30">
<Check className="w-3 h-3 text-white" />
<Check className="w-3 h-3 text-foreground" />
</div>
)}
<div className={`mb-2 ${isActive ? config.color : "text-slate-400 group-hover:text-slate-300"}`}>
<div className={`mb-2 ${isActive ? config.color : "text-muted-foreground group-hover:text-foreground"}`}>
{config.icon}
</div>
<div className={`text-sm font-semibold mb-0.5 ${isActive ? "text-white" : "text-slate-300"}`}>
<div className={`text-sm font-semibold mb-0.5 ${isActive ? "text-foreground" : "text-foreground"}`}>
{config.label}
</div>
<div className="text-[10px] text-slate-500">
<div className="text-xs text-muted-foreground">
{config.description}
</div>
@ -363,19 +363,19 @@ const ExportOptionsPanel = memo(function ExportOptionsPanel({
];
return (
<div className="rounded-xl border border-slate-700/40 bg-slate-800/20 overflow-hidden">
<div className="rounded-xl border border-border bg-muted/50 overflow-hidden">
<button
onClick={onToggle}
className="w-full flex items-center justify-between p-3 hover:bg-slate-700/20 transition-colors"
className="w-full flex items-center justify-between p-3 hover:bg-muted/20 transition-colors"
>
<div className="flex items-center gap-2">
<Settings2 className="w-4 h-4 text-slate-400" />
<span className="text-sm font-medium text-slate-300"></span>
<Settings2 className="w-4 h-4 text-muted-foreground" />
<span className="text-sm font-medium text-foreground"></span>
</div>
{expanded ? (
<ChevronUp className="w-4 h-4 text-slate-500" />
<ChevronUp className="w-4 h-4 text-muted-foreground" />
) : (
<ChevronDown className="w-4 h-4 text-slate-500" />
<ChevronDown className="w-4 h-4 text-muted-foreground" />
)}
</button>
@ -390,11 +390,11 @@ const ExportOptionsPanel = memo(function ExportOptionsPanel({
{optionItems.map((item) => (
<label
key={item.key}
className="flex items-center justify-between p-2 rounded-lg hover:bg-slate-700/20 cursor-pointer transition-colors"
className="flex items-center justify-between p-2 rounded-lg hover:bg-muted/20 cursor-pointer transition-colors"
>
<div className="flex-1">
<div className="text-xs font-medium text-slate-300">{item.label}</div>
<div className="text-[10px] text-slate-500">{item.description}</div>
<div className="text-xs font-medium text-foreground">{item.label}</div>
<div className="text-xs text-muted-foreground">{item.description}</div>
</div>
<Switch
checked={options[item.key as keyof ExportOptions]}
@ -425,23 +425,23 @@ const PreviewSearchBar = memo(function PreviewSearchBar({
onClear: () => void;
}) {
return (
<div className="flex items-center gap-2 px-3 py-2 bg-slate-800/30 border-b border-slate-700/30">
<Search className="w-3.5 h-3.5 text-slate-500" />
<div className="flex items-center gap-2 px-3 py-2 bg-muted border-b border-border">
<Search className="w-3.5 h-3.5 text-muted-foreground" />
<input
type="text"
value={searchQuery}
onChange={(e) => onSearchChange(e.target.value)}
placeholder="搜索预览内容..."
className="flex-1 bg-transparent text-xs text-slate-300 placeholder:text-slate-600 outline-none"
className="flex-1 bg-transparent text-xs text-foreground placeholder:text-muted-foreground outline-none"
/>
{searchQuery && (
<>
<span className="text-[10px] text-slate-500 font-mono">
<span className="text-xs text-muted-foreground font-mono">
{matchCount}
</span>
<button
onClick={onClear}
className="p-1 rounded hover:bg-slate-700/50 text-slate-500 hover:text-slate-300 transition-colors"
className="p-1 rounded hover:bg-muted/50 text-muted-foreground hover:text-foreground transition-colors"
>
<X className="w-3 h-3" />
</button>
@ -455,18 +455,18 @@ const PreviewSearchBar = memo(function PreviewSearchBar({
const PreviewSkeleton = memo(function PreviewSkeleton() {
return (
<div className="space-y-4 animate-pulse">
<div className="h-6 bg-slate-700/30 rounded w-3/4" />
<div className="h-6 bg-muted/30 rounded w-3/4" />
<div className="space-y-2">
<div className="h-4 bg-slate-700/20 rounded w-full" />
<div className="h-4 bg-slate-700/20 rounded w-5/6" />
<div className="h-4 bg-slate-700/20 rounded w-4/6" />
<div className="h-4 bg-muted/20 rounded w-full" />
<div className="h-4 bg-muted/20 rounded w-5/6" />
<div className="h-4 bg-muted/20 rounded w-4/6" />
</div>
<div className="h-20 bg-slate-700/20 rounded" />
<div className="h-20 bg-muted/20 rounded" />
<div className="space-y-2">
<div className="h-4 bg-slate-700/20 rounded w-full" />
<div className="h-4 bg-slate-700/20 rounded w-3/4" />
<div className="h-4 bg-muted/20 rounded w-full" />
<div className="h-4 bg-muted/20 rounded w-3/4" />
</div>
<div className="h-16 bg-slate-700/20 rounded" />
<div className="h-16 bg-muted/20 rounded" />
</div>
);
});
@ -486,7 +486,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
const parts = text.split(regex);
return parts.map((part, i) =>
regex.test(part) ? (
<mark key={i} className="bg-primary/40 text-white px-0.5 rounded">{part}</mark>
<mark key={i} className="bg-primary/40 text-foreground px-0.5 rounded">{part}</mark>
) : (
part
)
@ -506,30 +506,30 @@ const MarkdownPreview = memo(function MarkdownPreview({
if (line.startsWith("```")) {
if (inCodeBlock) {
elements.push(
<div key={`code-${index}`} className="my-4 rounded-xl bg-[#0d1117] border border-slate-700/50 overflow-hidden shadow-lg">
<div className="flex items-center justify-between px-4 py-2 bg-gradient-to-r from-slate-800/80 to-slate-800/40 border-b border-slate-700/50">
<div key={`code-${index}`} className="my-4 rounded-xl bg-card border border-border/50 overflow-hidden shadow-lg">
<div className="flex items-center justify-between px-4 py-2 bg-gradient-to-r from-muted to-muted/40 border-b border-border/50">
<div className="flex items-center gap-2">
<div className="flex gap-1.5">
<div className="w-2.5 h-2.5 rounded-full bg-rose-500/80" />
<div className="w-2.5 h-2.5 rounded-full bg-amber-500/80" />
<div className="w-2.5 h-2.5 rounded-full bg-emerald-500/80" />
</div>
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-mono ml-2">
<span className="text-xs text-muted-foreground uppercase tracking-wider font-mono ml-2">
{codeLanguage || "code"}
</span>
</div>
<Terminal className="w-3.5 h-3.5 text-slate-500" />
<Terminal className="w-3.5 h-3.5 text-muted-foreground" />
</div>
<div className="relative">
{/* 行号 */}
<div className="absolute left-0 top-0 bottom-0 w-10 bg-slate-900/50 border-r border-slate-700/30 select-none">
<div className="p-3 text-[10px] font-mono text-slate-600 leading-5">
<div className="absolute left-0 top-0 bottom-0 w-10 bg-background border-r border-border select-none">
<div className="p-3 text-xs font-mono text-muted-foreground leading-5">
{codeContent.map((_, i) => (
<div key={i}>{i + 1}</div>
))}
</div>
</div>
<pre className="p-3 pl-14 text-xs font-mono text-slate-300 overflow-x-auto leading-5">
<pre className="p-3 pl-14 text-xs font-mono text-foreground overflow-x-auto leading-5">
{codeContent.map((codeLine, i) => (
<div key={i}>{highlightText(codeLine, searchQuery) || " "}</div>
))}
@ -555,7 +555,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
// Headers with decorative elements
if (line.startsWith("# ")) {
elements.push(
<h1 key={index} className="text-xl font-bold text-white mt-8 mb-4 pb-3 border-b border-slate-700/50 flex items-center gap-3">
<h1 key={index} className="text-xl font-bold text-foreground mt-8 mb-4 pb-3 border-b border-border/50 flex items-center gap-3">
<span className="w-1 h-6 bg-primary rounded-full" />
{highlightText(line.slice(2), searchQuery)}
</h1>
@ -564,7 +564,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
}
if (line.startsWith("## ")) {
elements.push(
<h2 key={index} className="text-lg font-bold text-white mt-6 mb-3 flex items-center gap-2">
<h2 key={index} className="text-lg font-bold text-foreground mt-6 mb-3 flex items-center gap-2">
<Sparkles className="w-4 h-4 text-primary/60" />
{highlightText(line.slice(3), searchQuery)}
</h2>
@ -573,7 +573,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
}
if (line.startsWith("### ")) {
elements.push(
<h3 key={index} className="text-base font-semibold text-slate-200 mt-5 mb-2 pl-2 border-l-2 border-slate-600">
<h3 key={index} className="text-base font-semibold text-foreground mt-5 mb-2 pl-2 border-l-2 border-border">
{highlightText(line.slice(4), searchQuery)}
</h3>
);
@ -584,9 +584,9 @@ const MarkdownPreview = memo(function MarkdownPreview({
if (line.match(/^---+$/)) {
elements.push(
<div key={index} className="my-6 flex items-center gap-3">
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-slate-700 to-transparent" />
<div className="w-1.5 h-1.5 rounded-full bg-slate-700" />
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-slate-700 to-transparent" />
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-border to-transparent" />
<div className="w-1.5 h-1.5 rounded-full bg-muted" />
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-border to-transparent" />
</div>
);
return;
@ -595,7 +595,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
// List items with better styling
if (line.match(/^[-*]\s/)) {
elements.push(
<div key={index} className="flex gap-3 text-sm text-slate-300 ml-3 my-1 group">
<div key={index} className="flex gap-3 text-sm text-foreground ml-3 my-1 group">
<span className="text-primary mt-1.5 text-xs group-hover:scale-125 transition-transform"></span>
<span className="flex-1">{highlightText(line.slice(2), searchQuery)}</span>
</div>
@ -608,12 +608,12 @@ const MarkdownPreview = memo(function MarkdownPreview({
const parts = line.split(/\*\*(.+?)\*\*/g);
const lineElements = parts.map((part, i) => {
if (i % 2 === 1) {
return <strong key={i} className="text-white font-semibold">{highlightText(part, searchQuery)}</strong>;
return <strong key={i} className="text-foreground font-semibold">{highlightText(part, searchQuery)}</strong>;
}
return highlightText(part, searchQuery);
});
elements.push(
<p key={index} className="text-sm text-slate-300 my-1.5 leading-relaxed">
<p key={index} className="text-sm text-foreground my-1.5 leading-relaxed">
{lineElements}
</p>
);
@ -628,7 +628,7 @@ const MarkdownPreview = memo(function MarkdownPreview({
// Regular paragraphs
elements.push(
<p key={index} className="text-sm text-slate-300 my-1.5 leading-relaxed">
<p key={index} className="text-sm text-foreground my-1.5 leading-relaxed">
{highlightText(line, searchQuery)}
</p>
);
@ -663,11 +663,11 @@ const JsonPreview = memo(function JsonPreview({
.replace(/: "([^"]+)"/g, ': <span class="text-emerald-400">"$1"</span>')
.replace(/: (\d+\.?\d*)/g, ': <span class="text-amber-400">$1</span>')
.replace(/: (true|false)/g, ': <span class="text-sky-400">$1</span>')
.replace(/: (null)/g, ': <span class="text-slate-500">$1</span>');
.replace(/: (null)/g, ': <span class="text-muted-foreground">$1</span>');
if (searchQuery) {
const regex = new RegExp(`(${searchQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
result = result.replace(regex, '<mark class="bg-primary/40 text-white px-0.5 rounded">$1</mark>');
result = result.replace(regex, '<mark class="bg-primary/40 text-foreground px-0.5 rounded">$1</mark>');
}
return result;
@ -681,15 +681,15 @@ const JsonPreview = memo(function JsonPreview({
return (
<div className="relative">
{/* 行号区域 */}
<div className="absolute left-0 top-0 bottom-0 w-10 bg-slate-900/30 border-r border-slate-700/30 select-none">
<div className="py-3 text-[10px] font-mono text-slate-600 text-right pr-2 leading-5">
<div className="absolute left-0 top-0 bottom-0 w-10 bg-background border-r border-border select-none">
<div className="py-3 text-xs font-mono text-muted-foreground text-right pr-2 leading-5">
{lines.map((_, i) => (
<div key={i}>{i + 1}</div>
))}
</div>
</div>
<pre
className="text-xs font-mono text-slate-300 whitespace-pre-wrap pl-14 py-3 leading-5"
className="text-xs font-mono text-foreground whitespace-pre-wrap pl-14 py-3 leading-5"
dangerouslySetInnerHTML={{ __html: highlightJson(content) }}
/>
</div>
@ -716,11 +716,11 @@ const HtmlPreview = memo(function HtmlPreview({
.replace(/(&lt;\/?[a-zA-Z][a-zA-Z0-9]*)/g, '<span class="text-rose-400">$1</span>')
.replace(/(\s[a-zA-Z-]+)=/g, '<span class="text-amber-400">$1</span>=')
.replace(/"([^"]*)"/g, '"<span class="text-emerald-400">$1</span>"')
.replace(/(&lt;!DOCTYPE[^&]*&gt;)/gi, '<span class="text-slate-500">$1</span>');
.replace(/(&lt;!DOCTYPE[^&]*&gt;)/gi, '<span class="text-muted-foreground">$1</span>');
if (searchQuery) {
const regex = new RegExp(`(${searchQuery.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
result = result.replace(regex, '<mark class="bg-primary/40 text-white px-0.5 rounded">$1</mark>');
result = result.replace(regex, '<mark class="bg-primary/40 text-foreground px-0.5 rounded">$1</mark>');
}
return result;
@ -729,12 +729,12 @@ const HtmlPreview = memo(function HtmlPreview({
return (
<div className="relative">
<pre
className="text-xs font-mono text-slate-400 whitespace-pre-wrap leading-5"
className="text-xs font-mono text-muted-foreground whitespace-pre-wrap leading-5"
dangerouslySetInnerHTML={{ __html: highlightHtml(truncatedContent) }}
/>
{isTruncated && (
<div className="mt-4 pt-4 border-t border-slate-700/30 text-center">
<span className="text-xs text-slate-500 bg-slate-800/50 px-3 py-1.5 rounded-full">
<div className="mt-4 pt-4 border-t border-border text-center">
<span className="text-xs text-muted-foreground bg-muted px-3 py-1.5 rounded-full">
</span>
</div>
@ -1622,9 +1622,9 @@ export const ReportExportDialog = memo(function ReportExportDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-5xl h-[90vh] bg-gradient-to-b from-[#0a0a0f] to-[#0d0d14] border-slate-700/50 p-0 gap-0 overflow-hidden shadow-2xl shadow-black/50">
<DialogContent className="max-w-5xl h-[90vh] bg-gradient-to-b from-[#0a0a0f] to-[#0d0d14] border-border/50 p-0 gap-0 overflow-hidden shadow-2xl shadow-black/50">
{/* Header - 增强设计 */}
<div className="relative px-6 py-5 border-b border-slate-700/50 bg-gradient-to-r from-[#0d0d12] via-[#0f0f16] to-[#0d0d12]">
<div className="relative px-6 py-5 border-b border-border/50 bg-gradient-to-r from-[#0d0d12] via-[#0f0f16] to-[#0d0d12]">
{/* 装饰性背景元素 */}
<div className="absolute inset-0 overflow-hidden">
<div className="absolute -top-20 -right-20 w-40 h-40 bg-primary/5 rounded-full blur-3xl" />
@ -1636,14 +1636,14 @@ export const ReportExportDialog = memo(function ReportExportDialog({
<div className="flex items-center gap-4">
<div className="relative p-3 rounded-xl bg-gradient-to-br from-primary/20 to-primary/5 border border-primary/30 shadow-lg shadow-primary/10">
<FileDown className="w-6 h-6 text-primary" />
<div className="absolute -top-1 -right-1 w-3 h-3 rounded-full bg-emerald-500 border-2 border-[#0a0a0f] animate-pulse" />
<div className="absolute -top-1 -right-1 w-3 h-3 rounded-full bg-emerald-500 border-2 border-background animate-pulse" />
</div>
<div>
<DialogTitle className="text-xl font-bold text-white flex items-center gap-2">
<DialogTitle className="text-xl font-bold text-foreground flex items-center gap-2">
<Sparkles className="w-4 h-4 text-primary/60" />
</DialogTitle>
<p className="text-xs text-slate-500 mt-1 font-mono flex items-center gap-2">
<p className="text-xs text-muted-foreground mt-1 font-mono flex items-center gap-2">
<Clock className="w-3 h-3" />
{task.name || `Task ${task.id.slice(0, 8)}`}
</p>
@ -1651,12 +1651,12 @@ export const ReportExportDialog = memo(function ReportExportDialog({
</div>
{/* 快捷键提示 */}
<div className="hidden md:flex items-center gap-2 text-[10px] text-slate-600">
<div className="flex items-center gap-1 px-2 py-1 rounded bg-slate-800/50 border border-slate-700/30">
<div className="hidden md:flex items-center gap-2 text-xs text-muted-foreground">
<div className="flex items-center gap-1 px-2 py-1 rounded bg-muted border border-border">
<Keyboard className="w-3 h-3" />
<span>S </span>
</div>
<div className="flex items-center gap-1 px-2 py-1 rounded bg-slate-800/50 border border-slate-700/30">
<div className="flex items-center gap-1 px-2 py-1 rounded bg-muted border border-border">
<span>1-3 </span>
</div>
</div>
@ -1667,17 +1667,17 @@ export const ReportExportDialog = memo(function ReportExportDialog({
{/* 主体内容区域 */}
<div className="flex-1 flex flex-col overflow-hidden">
{/* Stats Summary - 增强统计卡片 */}
<div className="px-6 py-4 border-b border-slate-700/30 bg-[#0b0b10]/80">
<div className="px-6 py-4 border-b border-border bg-card/80">
<EnhancedStatsPanel task={task} findings={findings} />
</div>
{/* 两栏布局:左侧配置,右侧预览 */}
<div className="flex-1 flex min-h-0">
{/* 左侧:格式选择和配置 */}
<div className="w-72 flex-shrink-0 border-r border-slate-700/30 bg-[#0a0a0e]/50 p-4 space-y-4 overflow-y-auto">
<div className="w-72 flex-shrink-0 border-r border-border bg-card/50 p-4 space-y-4 overflow-y-auto">
{/* 格式选择 */}
<div>
<h3 className="text-xs font-semibold text-slate-400 uppercase tracking-wider mb-3 flex items-center gap-2">
<h3 className="text-xs font-semibold text-muted-foreground uppercase tracking-wider mb-3 flex items-center gap-2">
<FileText className="w-3.5 h-3.5" />
</h3>
@ -1696,16 +1696,16 @@ export const ReportExportDialog = memo(function ReportExportDialog({
/>
{/* 格式信息 */}
<div className="p-3 rounded-xl bg-slate-800/30 border border-slate-700/30">
<div className="p-3 rounded-xl bg-muted border border-border">
<div className="flex items-center gap-2 mb-2">
<div className={FORMAT_CONFIG[activeFormat].color}>
{FORMAT_CONFIG[activeFormat].icon}
</div>
<span className="text-sm font-medium text-white">
<span className="text-sm font-medium text-foreground">
{FORMAT_CONFIG[activeFormat].label}
</span>
</div>
<p className="text-[11px] text-slate-500 leading-relaxed">
<p className="text-xs text-muted-foreground leading-relaxed">
{activeFormat === "markdown" && "Markdown格式便于编辑和版本控制可用任何文本编辑器打开。"}
{activeFormat === "json" && "JSON格式包含完整的结构化数据适合程序处理和数据分析。"}
{activeFormat === "html" && "HTML格式可直接在浏览器中查看包含完整样式和布局。"}
@ -1714,32 +1714,32 @@ export const ReportExportDialog = memo(function ReportExportDialog({
</div>
{/* 右侧:预览区域 */}
<div className="flex-1 flex flex-col min-h-0 bg-[#0d0d12]">
<div className="flex-1 flex flex-col min-h-0 cyber-dialog">
{/* 预览工具栏 */}
<div className="flex-shrink-0 flex items-center justify-between px-4 py-2.5 border-b border-slate-700/30 bg-slate-800/20">
<div className="flex-shrink-0 flex items-center justify-between px-4 py-2.5 border-b border-border bg-muted/50">
<div className="flex items-center gap-3">
<div className="flex items-center gap-2">
<Eye className="w-4 h-4 text-slate-500" />
<span className="text-xs text-slate-400 font-medium"></span>
<Eye className="w-4 h-4 text-muted-foreground" />
<span className="text-xs text-muted-foreground font-medium"></span>
</div>
<Badge className="text-[10px] bg-slate-700/50 text-slate-400 border-0 font-mono">
<Badge className="text-xs bg-muted/50 text-muted-foreground border-0 font-mono">
{formatBytes(preview.content.length)}
</Badge>
</div>
<div className="flex items-center gap-2">
{/* 搜索框 */}
<div className="flex items-center gap-2 px-2.5 py-1.5 rounded-lg bg-slate-800/50 border border-slate-700/30">
<Search className="w-3.5 h-3.5 text-slate-500" />
<div className="flex items-center gap-2 px-2.5 py-1.5 rounded-lg bg-muted border border-border">
<Search className="w-3.5 h-3.5 text-muted-foreground" />
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="搜索..."
className="w-24 bg-transparent text-xs text-slate-300 placeholder:text-slate-600 outline-none"
className="w-24 bg-transparent text-xs text-foreground placeholder:text-muted-foreground outline-none"
/>
{searchQuery && (
<span className="text-[10px] text-slate-500 font-mono">
<span className="text-xs text-muted-foreground font-mono">
{searchMatchCount}
</span>
)}
@ -1751,7 +1751,7 @@ export const ReportExportDialog = memo(function ReportExportDialog({
size="sm"
onClick={handleCopy}
disabled={preview.loading || !preview.content}
className="h-8 px-2.5 text-xs text-slate-400 hover:text-white hover:bg-slate-700/50"
className="h-8 px-2.5 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50"
>
{copied ? (
<Check className="w-3.5 h-3.5 mr-1.5 text-emerald-400" />
@ -1766,7 +1766,7 @@ export const ReportExportDialog = memo(function ReportExportDialog({
size="sm"
onClick={() => fetchPreview(activeFormat, true)}
disabled={preview.loading}
className="h-8 px-2.5 text-xs text-slate-400 hover:text-white hover:bg-slate-700/50"
className="h-8 px-2.5 text-xs text-muted-foreground hover:text-foreground hover:bg-muted/50"
>
<RefreshCw className={`w-3.5 h-3.5 mr-1.5 ${preview.loading ? 'animate-spin' : ''}`} />
@ -1787,8 +1787,8 @@ export const ReportExportDialog = memo(function ReportExportDialog({
<AlertTriangle className="w-8 h-8 text-amber-400" />
</div>
<div>
<p className="text-sm text-slate-300 font-medium mb-1"></p>
<p className="text-xs text-slate-500">{preview.error}</p>
<p className="text-sm text-foreground font-medium mb-1"></p>
<p className="text-xs text-muted-foreground">{preview.error}</p>
</div>
<Button
variant="outline"
@ -1802,7 +1802,7 @@ export const ReportExportDialog = memo(function ReportExportDialog({
</div>
</div>
) : (
<div className="rounded-xl border border-slate-700/40 overflow-hidden bg-[#0a0a0e]">
<div className="rounded-xl border border-border overflow-hidden bg-card">
<div className="p-5 min-h-[300px]">
{activeFormat === "markdown" && (
<MarkdownPreview content={preview.content} searchQuery={searchQuery} />
@ -1824,9 +1824,9 @@ export const ReportExportDialog = memo(function ReportExportDialog({
</div>
{/* Footer - 增强设计 */}
<div className="px-6 py-4 border-t border-slate-700/50 bg-gradient-to-r from-[#0d0d12] via-[#0f0f16] to-[#0d0d12]">
<div className="px-6 py-4 border-t border-border/50 bg-gradient-to-r from-[#0d0d12] via-[#0f0f16] to-[#0d0d12]">
<div className="flex items-center justify-between">
<div className="flex items-center gap-3 text-xs text-slate-500">
<div className="flex items-center gap-3 text-xs text-muted-foreground">
<div className={`flex items-center gap-2 px-3 py-1.5 rounded-lg border ${FORMAT_CONFIG[activeFormat].bgColor}`}>
<span className={FORMAT_CONFIG[activeFormat].color}>
{FORMAT_CONFIG[activeFormat].icon}
@ -1841,7 +1841,7 @@ export const ReportExportDialog = memo(function ReportExportDialog({
<Button
variant="ghost"
onClick={() => onOpenChange(false)}
className="h-10 px-5 text-sm text-slate-400 hover:text-white"
className="h-10 px-5 text-sm text-muted-foreground hover:text-foreground"
>
</Button>

View File

@ -151,7 +151,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
};
return (
<div className="h-screen bg-[#0a0a0f] flex flex-col overflow-hidden relative">
<div className="h-screen cyber-bg-elevated flex flex-col overflow-hidden relative">
{/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20">
<div
@ -192,26 +192,26 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
style={{ textShadow: "0 0 30px rgba(255,107,44,0.5), 0 0 60px rgba(255,107,44,0.3)" }}
>
<span className="text-primary">DEEP</span>
<span className="text-white">AUDIT</span>
<span className="text-foreground">AUDIT</span>
</div>
<div className="text-gray-500 text-xs sm:text-sm tracking-[0.3em] uppercase">
<div className="text-muted-foreground text-xs sm:text-sm tracking-[0.3em] uppercase">
Autonomous Security Agent
</div>
</div>
{/* Terminal window */}
<div
className="bg-[#0c0c12] border border-gray-800/60 rounded-lg overflow-hidden shadow-2xl"
className="cyber-dialog border border-border rounded-lg overflow-hidden shadow-2xl"
onClick={handleTerminalClick}
>
{/* Terminal header */}
<div className="flex items-center gap-2 px-4 py-2.5 bg-[#0a0a0f] border-b border-gray-800/50">
<div className="flex items-center gap-2 px-4 py-2.5 cyber-bg-elevated border-b border-border">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="text-[11px] text-gray-500 ml-3 font-mono tracking-wider">
<span className="text-xs text-muted-foreground ml-3 font-mono tracking-wider">
deepaudit@terminal
</span>
</div>
@ -228,7 +228,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
className={`mb-1 ${
log.includes("[READY]") ? "text-green-400" :
log.includes("[INIT]") ? "text-primary" :
"text-gray-500"
"text-muted-foreground"
}`}
style={{
animation: "fadeSlideIn 0.2s ease-out",
@ -236,17 +236,17 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
animationDelay: `${i * 0.05}s`
}}
>
<span className="text-gray-600 mr-2">&gt;</span>
<span className="text-muted-foreground mr-2">&gt;</span>
{log}
</div>
))}
{/* Welcome message */}
{bootComplete && (
<div className="mt-4 mb-4 pt-3 border-t border-gray-800/50">
<div className="mt-4 mb-4 pt-3 border-t border-border">
<div className="text-primary mb-1">Welcome to DeepAudit Agent Terminal</div>
<div className="text-gray-500 text-xs">
Type <span className="text-emerald-400 font-semibold">'audit'</span> to start a new security audit, or <span className="text-gray-400">'help'</span> for commands.
<div className="text-muted-foreground text-xs">
Type <span className="text-emerald-400 font-semibold">'audit'</span> to start a new security audit, or <span className="text-muted-foreground">'help'</span> for commands.
</div>
</div>
)}
@ -254,13 +254,13 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
{/* Command history */}
{commandHistory.map((entry, i) => (
<div key={`cmd-${i}`} className="mb-2">
<div className="flex items-center gap-2 text-gray-300">
<div className="flex items-center gap-2 text-foreground">
<span className="text-emerald-500">$</span>
<span>{entry.input}</span>
</div>
{entry.output && (
<div className={`ml-4 mt-1 whitespace-pre-wrap text-xs ${
entry.isError ? "text-red-400" : "text-gray-500"
entry.isError ? "text-red-400" : "text-muted-foreground"
}`}>
{entry.output}
</div>
@ -270,7 +270,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
{/* Current input line */}
{bootComplete && (
<div className="flex items-center gap-2 text-gray-300">
<div className="flex items-center gap-2 text-foreground">
<span className="text-emerald-500">$</span>
<div className="flex-1 relative">
<input
@ -285,7 +285,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
autoComplete="off"
autoFocus
/>
<span className="text-gray-200">{currentInput}</span>
<span className="text-foreground">{currentInput}</span>
<span
className={`inline-block w-2 h-4 bg-emerald-400 ml-0.5 align-middle transition-opacity ${
cursorBlink ? "opacity-100" : "opacity-0"
@ -301,7 +301,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
<div className={`mt-4 text-center transition-all duration-500 ${bootComplete ? "opacity-100" : "opacity-0"}`}>
<div className="flex items-center justify-center gap-3">
<div className="h-px w-8 bg-gradient-to-r from-transparent to-gray-700" />
<span className="text-gray-600 text-[10px] font-mono tracking-wider">PRESS ENTER TO EXECUTE</span>
<span className="text-muted-foreground text-xs font-mono tracking-wider">PRESS ENTER TO EXECUTE</span>
<div className="h-px w-8 bg-gradient-to-l from-transparent to-gray-700" />
</div>
</div>
@ -309,18 +309,18 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
</div>
{/* Corner decorations */}
<div className="absolute top-4 left-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute top-4 left-4 text-xs font-mono text-muted-foreground z-30">
<div>SYS.VERSION: 3.0.0</div>
<div>MODE: INTERACTIVE</div>
</div>
<div className="absolute top-4 right-4 text-[10px] font-mono text-gray-700 text-right z-30">
<div className="absolute top-4 right-4 text-xs font-mono text-muted-foreground text-right z-30">
<div>MEM: 16384MB</div>
<div>STATUS: READY</div>
</div>
<div className="absolute bottom-4 left-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 left-4 text-xs font-mono text-muted-foreground z-30">
DEEPAUDIT_AGENT_v3
</div>
<div className="absolute bottom-4 right-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 right-4 text-xs font-mono text-muted-foreground z-30">
{new Date().toISOString().split("T")[0]}
</div>

View File

@ -60,7 +60,7 @@ function CircularProgress({ value, size = 48, strokeWidth = 3, color = "primary"
}
// Metric card component with enhanced colors
function MetricCard({ icon, label, value, suffix = "", colorClass = "text-slate-400" }: {
function MetricCard({ icon, label, value, suffix = "", colorClass = "text-muted-foreground" }: {
icon: React.ReactNode;
label: string;
value: string | number;
@ -68,14 +68,14 @@ function MetricCard({ icon, label, value, suffix = "", colorClass = "text-slate-
colorClass?: string;
}) {
return (
<div className="flex items-center gap-2.5 p-2.5 rounded bg-slate-900/40 border border-slate-700/30">
<div className="flex items-center gap-2.5 p-3 rounded bg-card border border-border">
<div className={colorClass}>
{icon}
</div>
<div className="flex-1 min-w-0">
<div className="text-[9px] text-slate-500 uppercase tracking-wider truncate">{label}</div>
<div className="text-sm text-white font-mono font-medium">
{value}<span className="text-slate-500 text-xs">{suffix}</span>
<div className="text-sm text-muted-foreground uppercase tracking-wider truncate font-medium">{label}</div>
<div className="text-lg text-foreground font-mono font-bold">
{value}<span className="text-muted-foreground text-base">{suffix}</span>
</div>
</div>
</div>
@ -106,17 +106,17 @@ export const StatsPanel = memo(function StatsPanel({ task, findings }: StatsPane
return (
<div className="space-y-3">
{/* Progress Section */}
<div className="p-3 rounded border border-slate-700/40 bg-gradient-to-br from-slate-900/60 to-slate-900/30">
<div className="p-4 rounded border border-border bg-card">
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<Activity className="w-3.5 h-3.5 text-primary" />
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-medium">Progress</span>
<span className="text-sm text-muted-foreground uppercase tracking-wider font-medium">Progress</span>
</div>
<span className="text-xs text-primary font-mono font-bold">{progressPercent.toFixed(0)}%</span>
</div>
{/* Progress bar */}
<div className="relative h-2 bg-slate-800 rounded-full overflow-hidden">
<div className="relative h-2 bg-muted rounded-full overflow-hidden">
<div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-primary to-primary/80 rounded-full transition-all duration-700 ease-out"
style={{ width: `${progressPercent}%` }}
@ -132,17 +132,17 @@ export const StatsPanel = memo(function StatsPanel({ task, findings }: StatsPane
</div>
{/* File progress */}
<div className="flex items-center justify-between mt-2 text-[10px]">
<span className="text-slate-500">Files scanned</span>
<span className="text-slate-300 font-mono">
{task.analyzed_files}<span className="text-slate-500">/{task.total_files}</span>
<div className="flex items-center justify-between mt-3 text-base">
<span className="text-muted-foreground font-medium">Files scanned</span>
<span className="text-foreground font-mono font-bold">
{task.analyzed_files}<span className="text-muted-foreground font-normal">/{task.total_files}</span>
</span>
</div>
{/* Files with findings */}
{task.files_with_findings > 0 && (
<div className="flex items-center justify-between mt-1 text-[10px]">
<span className="text-slate-500">Files with findings</span>
<span className="text-rose-400 font-mono font-medium">
<div className="flex items-center justify-between mt-2 text-base">
<span className="text-muted-foreground font-medium">Files with findings</span>
<span className="text-rose-500 dark:text-rose-400 font-mono font-bold">
{task.files_with_findings}
</span>
</div>
@ -152,58 +152,58 @@ export const StatsPanel = memo(function StatsPanel({ task, findings }: StatsPane
{/* Metrics Grid */}
<div className="grid grid-cols-2 gap-2">
<MetricCard
icon={<Repeat className="w-3.5 h-3.5" />}
icon={<Repeat className="w-4 h-4" />}
label="Iterations"
value={task.total_iterations || 0}
colorClass="text-teal-400"
colorClass="text-teal-600 dark:text-teal-400"
/>
<MetricCard
icon={<Zap className="w-3.5 h-3.5" />}
icon={<Zap className="w-4 h-4" />}
label="Tool Calls"
value={task.tool_calls_count || 0}
colorClass="text-amber-400"
colorClass="text-amber-600 dark:text-amber-400"
/>
<MetricCard
icon={<FileCode className="w-3.5 h-3.5" />}
icon={<FileCode className="w-4 h-4" />}
label="Tokens"
value={((task.tokens_used || 0) / 1000).toFixed(1)}
suffix="k"
colorClass="text-violet-400"
colorClass="text-violet-600 dark:text-violet-400"
/>
<MetricCard
icon={<Bug className="w-3.5 h-3.5" />}
icon={<Bug className="w-4 h-4" />}
label="Findings"
value={totalFindings}
colorClass={totalFindings > 0 ? "text-rose-400" : "text-slate-400"}
colorClass={totalFindings > 0 ? "text-rose-600 dark:text-rose-400" : "text-muted-foreground"}
/>
</div>
{/* Findings breakdown */}
{totalFindings > 0 && (
<div className="p-3 rounded border border-slate-700/40 bg-slate-900/40">
<div className="p-4 rounded border border-border bg-card">
<div className="flex items-center gap-2 mb-2">
<AlertTriangle className="w-3.5 h-3.5 text-rose-400" />
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-medium">Severity Breakdown</span>
<span className="text-sm text-muted-foreground uppercase tracking-wider font-medium">Severity Breakdown</span>
</div>
<div className="flex flex-wrap gap-1.5">
{severityCounts.critical > 0 && (
<Badge className="bg-rose-500/25 text-rose-300 border border-rose-500/40 text-[10px] font-mono font-semibold">
<Badge className="bg-rose-500/25 text-rose-700 dark:text-rose-300 border border-rose-500/40 text-sm font-mono font-semibold">
CRIT: {severityCounts.critical}
</Badge>
)}
{severityCounts.high > 0 && (
<Badge className="bg-orange-500/25 text-orange-300 border border-orange-500/40 text-[10px] font-mono font-semibold">
<Badge className="bg-orange-500/25 text-orange-700 dark:text-orange-300 border border-orange-500/40 text-sm font-mono font-semibold">
HIGH: {severityCounts.high}
</Badge>
)}
{severityCounts.medium > 0 && (
<Badge className="bg-amber-500/25 text-amber-300 border border-amber-500/40 text-[10px] font-mono font-semibold">
<Badge className="bg-amber-500/25 text-amber-700 dark:text-amber-300 border border-amber-500/40 text-sm font-mono font-semibold">
MED: {severityCounts.medium}
</Badge>
)}
{severityCounts.low > 0 && (
<Badge className="bg-sky-500/25 text-sky-300 border border-sky-500/40 text-[10px] font-mono font-semibold">
<Badge className="bg-sky-500/25 text-sky-700 dark:text-sky-300 border border-sky-500/40 text-sm font-mono font-semibold">
LOW: {severityCounts.low}
</Badge>
)}
@ -213,11 +213,11 @@ export const StatsPanel = memo(function StatsPanel({ task, findings }: StatsPane
{/* Security Score */}
{task.security_score !== null && task.security_score !== undefined && (
<div className="p-3 rounded border border-slate-700/40 bg-gradient-to-br from-slate-900/60 to-slate-900/30">
<div className="p-4 rounded border border-border bg-card">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Shield className="w-3.5 h-3.5 text-emerald-400" />
<span className="text-[10px] text-slate-400 uppercase tracking-wider font-medium">Security Score</span>
<span className="text-sm text-muted-foreground uppercase tracking-wider font-medium">Security Score</span>
</div>
<div className="relative">
<CircularProgress
@ -227,9 +227,9 @@ export const StatsPanel = memo(function StatsPanel({ task, findings }: StatsPane
color={getScoreColor(task.security_score)}
/>
<div className="absolute inset-0 flex items-center justify-center">
<span className={`text-sm font-bold font-mono ${task.security_score >= 80 ? 'text-emerald-400' :
task.security_score >= 60 ? 'text-amber-400' :
'text-rose-400'
<span className={`text-sm font-bold font-mono ${task.security_score >= 80 ? 'text-emerald-600 dark:text-emerald-400' :
task.security_score >= 60 ? 'text-amber-600 dark:text-amber-400' :
'text-rose-600 dark:text-rose-400'
}`}>
{task.security_score.toFixed(0)}
</span>

View File

@ -24,48 +24,48 @@ const STATUS_CONFIG: Record<string, {
pending: {
icon: <Clock className="w-3.5 h-3.5" />,
iconSm: <Clock className="w-3 h-3" />,
bg: "bg-gray-800/80 border-gray-600/50",
text: "text-gray-300",
bg: "bg-muted border-border",
text: "text-foreground",
label: "PENDING",
},
running: {
icon: <Loader2 className="w-3.5 h-3.5 animate-spin" />,
iconSm: <Loader2 className="w-3 h-3 animate-spin" />,
bg: "bg-green-950/80 border-green-500/50",
text: "text-green-400",
bg: "bg-green-100 dark:bg-green-950/80 border-green-500/50",
text: "text-green-700 dark:text-green-400",
label: "RUNNING",
glow: "shadow-[0_0_8px_rgba(74,222,128,0.3)]",
glow: "dark:shadow-[0_0_8px_rgba(74,222,128,0.3)]",
animate: true,
},
completed: {
icon: <CheckCircle2 className="w-3.5 h-3.5" />,
iconSm: <CheckCircle2 className="w-3 h-3" />,
bg: "bg-green-950/60 border-green-600/50",
text: "text-green-400",
bg: "bg-green-100 dark:bg-green-950/60 border-green-600/50",
text: "text-green-700 dark:text-green-400",
label: "COMPLETED",
},
failed: {
icon: <XCircle className="w-3.5 h-3.5" />,
iconSm: <XCircle className="w-3 h-3" />,
bg: "bg-red-950/60 border-red-600/50",
text: "text-red-400",
bg: "bg-red-100 dark:bg-red-950/60 border-red-600/50",
text: "text-red-700 dark:text-red-400",
label: "FAILED",
glow: "shadow-[0_0_8px_rgba(248,113,113,0.2)]",
glow: "dark:shadow-[0_0_8px_rgba(248,113,113,0.2)]",
},
cancelled: {
icon: <Square className="w-3.5 h-3.5" />,
iconSm: <Square className="w-3 h-3" />,
bg: "bg-yellow-950/60 border-yellow-600/50",
text: "text-yellow-400",
bg: "bg-yellow-100 dark:bg-yellow-950/60 border-yellow-600/50",
text: "text-yellow-700 dark:text-yellow-400",
label: "CANCELLED",
},
error: {
icon: <AlertCircle className="w-3.5 h-3.5" />,
iconSm: <AlertCircle className="w-3 h-3" />,
bg: "bg-red-950/60 border-red-600/50",
text: "text-red-400",
bg: "bg-red-100 dark:bg-red-950/60 border-red-600/50",
text: "text-red-700 dark:text-red-400",
label: "ERROR",
glow: "shadow-[0_0_8px_rgba(248,113,113,0.2)]",
glow: "dark:shadow-[0_0_8px_rgba(248,113,113,0.2)]",
},
};
@ -81,7 +81,7 @@ export const StatusBadge = memo(function StatusBadge({ status, size = "default"
${config.bg}
${config.text}
${config.glow || ''}
${isSmall ? 'px-1.5 py-0.5 text-[9px]' : 'px-2 py-1 text-[10px]'}
${isSmall ? 'px-2 py-1 text-sm' : 'px-2.5 py-1.5 text-sm'}
`}
>
{isSmall ? config.iconSm : config.icon}

View File

@ -16,11 +16,11 @@ import {
// ============ Severity Colors (Enhanced contrast) ============
export const SEVERITY_COLORS: Record<string, string> = {
critical: "text-rose-300 bg-rose-500/20 border border-rose-500/40",
high: "text-orange-300 bg-orange-500/20 border border-orange-500/40",
medium: "text-amber-300 bg-amber-500/20 border border-amber-500/40",
low: "text-sky-300 bg-sky-500/20 border border-sky-500/40",
info: "text-slate-300 bg-slate-500/20 border border-slate-500/40",
critical: "text-rose-700 dark:text-rose-300 bg-rose-500/20 border border-rose-500/40",
high: "text-orange-700 dark:text-orange-300 bg-orange-500/20 border border-orange-500/40",
medium: "text-amber-700 dark:text-amber-300 bg-amber-500/20 border border-amber-500/40",
low: "text-sky-700 dark:text-sky-300 bg-sky-500/20 border border-sky-500/40",
info: "text-foreground bg-muted/20 border border-border",
};
// ============ Action Verbs for Animation ============
@ -39,47 +39,47 @@ export const LOG_TYPE_CONFIG: Record<string, {
bgColor: string;
}> = {
thinking: {
icon: React.createElement(Brain, { className: "w-4 h-4 text-violet-400" }),
icon: React.createElement(Brain, { className: "w-4 h-4 text-violet-600 dark:text-violet-400" }),
borderColor: "border-l-violet-500",
bgColor: "bg-violet-500/10"
},
tool: {
icon: React.createElement(Wrench, { className: "w-4 h-4 text-amber-400" }),
icon: React.createElement(Wrench, { className: "w-4 h-4 text-amber-600 dark:text-amber-400" }),
borderColor: "border-l-amber-500",
bgColor: "bg-amber-500/10"
},
phase: {
icon: React.createElement(Target, { className: "w-4 h-4 text-teal-400" }),
icon: React.createElement(Target, { className: "w-4 h-4 text-teal-600 dark:text-teal-400" }),
borderColor: "border-l-teal-500",
bgColor: "bg-teal-500/10"
},
finding: {
icon: React.createElement(Bug, { className: "w-4 h-4 text-rose-400" }),
icon: React.createElement(Bug, { className: "w-4 h-4 text-rose-600 dark:text-rose-400" }),
borderColor: "border-l-rose-500",
bgColor: "bg-rose-500/10"
},
dispatch: {
icon: React.createElement(Zap, { className: "w-4 h-4 text-sky-400" }),
icon: React.createElement(Zap, { className: "w-4 h-4 text-sky-600 dark:text-sky-400" }),
borderColor: "border-l-sky-500",
bgColor: "bg-sky-500/10"
},
info: {
icon: React.createElement(Terminal, { className: "w-4 h-4 text-slate-400" }),
borderColor: "border-l-slate-500",
bgColor: "bg-slate-500/10"
icon: React.createElement(Terminal, { className: "w-4 h-4 text-muted-foreground" }),
borderColor: "border-l-muted-foreground",
bgColor: "bg-muted/10"
},
error: {
icon: React.createElement(AlertTriangle, { className: "w-4 h-4 text-red-400" }),
icon: React.createElement(AlertTriangle, { className: "w-4 h-4 text-red-600 dark:text-red-400" }),
borderColor: "border-l-red-500",
bgColor: "bg-red-500/15"
},
user: {
icon: React.createElement(Shield, { className: "w-4 h-4 text-indigo-400" }),
icon: React.createElement(Shield, { className: "w-4 h-4 text-indigo-600 dark:text-indigo-400" }),
borderColor: "border-l-indigo-500",
bgColor: "bg-indigo-500/10"
},
progress: {
icon: React.createElement(Loader2, { className: "w-4 h-4 text-cyan-400 animate-spin" }),
icon: React.createElement(Loader2, { className: "w-4 h-4 text-cyan-600 dark:text-cyan-400 animate-spin" }),
borderColor: "border-l-cyan-500",
bgColor: "bg-cyan-500/10"
},
@ -94,29 +94,29 @@ export const AGENT_STATUS_CONFIG: Record<string, {
animate?: boolean;
}> = {
running: {
icon: React.createElement("div", { className: "w-2 h-2 rounded-full bg-emerald-400" }),
color: "text-emerald-400",
icon: React.createElement("div", { className: "w-2 h-2 rounded-full bg-emerald-500 dark:bg-emerald-400" }),
color: "text-emerald-600 dark:text-emerald-400",
text: "Running",
animate: true
},
completed: {
icon: React.createElement(CheckCircle2, { className: "w-3 h-3 text-emerald-400" }),
color: "text-emerald-400",
icon: React.createElement(CheckCircle2, { className: "w-3 h-3 text-emerald-600 dark:text-emerald-400" }),
color: "text-emerald-600 dark:text-emerald-400",
text: "Completed"
},
failed: {
icon: React.createElement(XCircle, { className: "w-3 h-3 text-rose-400" }),
color: "text-rose-400",
icon: React.createElement(XCircle, { className: "w-3 h-3 text-rose-600 dark:text-rose-400" }),
color: "text-rose-600 dark:text-rose-400",
text: "Failed"
},
waiting: {
icon: React.createElement(Clock, { className: "w-3 h-3 text-amber-400" }),
color: "text-amber-400",
icon: React.createElement(Clock, { className: "w-3 h-3 text-amber-600 dark:text-amber-400" }),
color: "text-amber-600 dark:text-amber-400",
text: "Waiting"
},
created: {
icon: React.createElement("div", { className: "w-2 h-2 rounded-full bg-slate-500" }),
color: "text-slate-400",
icon: React.createElement("div", { className: "w-2 h-2 rounded-full bg-muted" }),
color: "text-muted-foreground",
text: "Created"
},
};
@ -129,22 +129,22 @@ export const AGENT_TYPE_CONFIG: Record<string, {
color: string;
}> = {
orchestrator: {
icon: React.createElement(Cpu, { className: "w-3.5 h-3.5 text-violet-400" }),
icon: React.createElement(Cpu, { className: "w-4 h-4 text-violet-600 dark:text-violet-400" }),
label: "Orchestrator",
color: "violet"
},
recon: {
icon: React.createElement(Scan, { className: "w-3.5 h-3.5 text-teal-400" }),
icon: React.createElement(Scan, { className: "w-4 h-4 text-teal-600 dark:text-teal-400" }),
label: "Reconnaissance",
color: "teal"
},
analysis: {
icon: React.createElement(FileSearch, { className: "w-3.5 h-3.5 text-amber-400" }),
icon: React.createElement(FileSearch, { className: "w-4 h-4 text-amber-600 dark:text-amber-400" }),
label: "Analysis",
color: "amber"
},
verification: {
icon: React.createElement(ShieldCheck, { className: "w-3.5 h-3.5 text-emerald-400" }),
icon: React.createElement(ShieldCheck, { className: "w-4 h-4 text-emerald-600 dark:text-emerald-400" }),
label: "Verification",
color: "emerald"
},
@ -158,7 +158,7 @@ export const TASK_STATUS_CONFIG: Record<string, {
text: string;
}> = {
pending: {
bg: "bg-slate-600",
bg: "bg-muted",
icon: React.createElement(Clock, { className: "w-3 h-3" }),
text: "PENDING"
},

View File

@ -757,12 +757,12 @@ function AgentAuditPageContent() {
if (isLoading && !task) {
return (
<div className="h-screen bg-[#08090d] flex items-center justify-center relative overflow-hidden">
<div className="h-screen bg-background flex items-center justify-center relative overflow-hidden">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid opacity-30" />
{/* Vignette */}
<div className="absolute inset-0 vignette pointer-events-none" />
<div className="flex items-center gap-3 text-[#8a95a5] relative z-10">
<div className="flex items-center gap-3 text-muted-foreground relative z-10">
<Loader2 className="w-5 h-5 animate-spin text-primary" />
<span className="font-mono text-sm tracking-wide">LOADING AUDIT TASK...</span>
</div>
@ -771,7 +771,7 @@ function AgentAuditPageContent() {
}
return (
<div className="h-screen bg-[#08090d] flex flex-col overflow-hidden relative">
<div className="h-screen bg-background flex flex-col overflow-hidden relative">
{/* Subtle grid background */}
<div className="absolute inset-0 cyber-grid-subtle opacity-40 pointer-events-none" />
{/* Scanline effect */}
@ -790,24 +790,24 @@ function AgentAuditPageContent() {
{/* Main content */}
<div className="flex-1 flex overflow-hidden relative">
{/* Left Panel - Activity Log */}
<div className="w-3/4 flex flex-col border-r border-[#1a2535]">
<div className="w-3/4 flex flex-col border-r border-border">
{/* Log header */}
<div className="flex-shrink-0 h-11 border-b border-[#1a2535] flex items-center justify-between px-4 bg-[#0a0c10]/90 backdrop-blur-sm">
<div className="flex items-center gap-3 text-xs text-[#8a95a5]">
<div className="flex-shrink-0 h-11 border-b border-border flex items-center justify-between px-4 cyber-bg-elevated/90 backdrop-blur-sm">
<div className="flex items-center gap-3 text-xs text-muted-foreground">
<div className="flex items-center gap-2">
<Terminal className="w-4 h-4 text-[#5a6577]" />
<span className="uppercase font-bold tracking-[0.15em] text-[#d0d8e8]">Activity Log</span>
<Terminal className="w-4 h-4 text-muted-foreground" />
<span className="uppercase font-bold tracking-[0.15em] text-foreground">Activity Log</span>
</div>
{isConnected && (
<div className="flex items-center gap-1.5 text-[#3dd68c]">
<div className="flex items-center gap-1.5 text-emerald-400">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#3dd68c] opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-[#3dd68c] shadow-[0_0_8px_rgba(61,214,140,0.5)]"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-emerald-400 shadow-[0_0_8px_rgba(61,214,140,0.5)]"></span>
</span>
<span className="text-[10px] font-mono uppercase tracking-wider">Live</span>
<span className="text-xs font-mono uppercase tracking-wider">Live</span>
</div>
)}
<Badge variant="outline" className="h-5 px-1.5 text-[10px] border-[#2a3545] text-[#6a7587] font-mono bg-[#0d1015]">
<Badge variant="outline" className="h-5 px-1.5 text-xs border-border text-muted-foreground font-mono bg-muted">
{filteredLogs.length}{!showAllLogs && logs.length !== filteredLogs.length ? ` / ${logs.length}` : ''}
</Badge>
</div>
@ -815,11 +815,11 @@ function AgentAuditPageContent() {
<button
onClick={() => setAutoScroll(!isAutoScroll)}
className={`
flex items-center gap-1.5 text-[10px] px-2.5 py-1 rounded font-mono uppercase tracking-wider
flex items-center gap-1.5 text-xs px-2.5 py-1 rounded font-mono uppercase tracking-wider
transition-all duration-200
${isAutoScroll
? 'bg-primary/15 text-primary border border-primary/40 shadow-[0_0_10px_rgba(255,95,31,0.15)]'
: 'text-[#6a7587] hover:text-[#a8b0c0] border border-transparent hover:border-[#2a3545] hover:bg-[#1a2030]/50'
: 'text-muted-foreground hover:text-foreground border border-transparent hover:border-border hover:bg-muted/50'
}
`}
>
@ -829,7 +829,7 @@ function AgentAuditPageContent() {
</div>
{/* Log content */}
<div className="flex-1 overflow-y-auto p-4 custom-scrollbar bg-[#060810]/50">
<div className="flex-1 overflow-y-auto p-4 custom-scrollbar bg-background/50">
{/* Filter indicator */}
{selectedAgentId && !showAllLogs && (
<div className="mb-3 px-3 py-2 bg-primary/8 border border-primary/25 rounded flex items-center justify-between">
@ -839,7 +839,7 @@ function AgentAuditPageContent() {
</div>
<button
onClick={() => selectAgent(null)}
className="text-[10px] text-[#6a7587] hover:text-[#d0d8e8] transition-colors font-mono uppercase tracking-wider"
className="text-xs text-muted-foreground hover:text-foreground transition-colors font-mono uppercase tracking-wider"
>
Clear
</button>
@ -849,10 +849,10 @@ function AgentAuditPageContent() {
{/* Logs */}
{filteredLogs.length === 0 ? (
<div className="h-full flex items-center justify-center">
<div className="text-center text-[#4a5565]">
<div className="text-center text-muted-foreground">
{isRunning ? (
<div className="flex flex-col items-center gap-3">
<Loader2 className="w-6 h-6 animate-spin text-[#5a6577]" />
<Loader2 className="w-6 h-6 animate-spin text-muted-foreground" />
<span className="text-sm font-mono tracking-wide">
{selectedAgentId && !showAllLogs
? 'WAITING FOR ACTIVITY FROM SELECTED AGENT...'
@ -885,36 +885,36 @@ function AgentAuditPageContent() {
{/* Status bar */}
{task && (
<div className="flex-shrink-0 h-9 border-t border-[#1a2535] flex items-center justify-between px-4 text-xs bg-[#0a0c10]/90 backdrop-blur-sm">
<div className="flex-shrink-0 h-9 border-t border-border flex items-center justify-between px-4 text-xs cyber-bg-elevated/90 backdrop-blur-sm">
<span>
{isRunning ? (
<span className="flex items-center gap-2 text-[#3dd68c]">
<span className="flex items-center gap-2 text-emerald-400">
<span className="relative flex h-1.5 w-1.5">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#3dd68c] opacity-75"></span>
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-[#3dd68c] shadow-[0_0_6px_rgba(61,214,140,0.5)]"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-emerald-400 shadow-[0_0_6px_rgba(61,214,140,0.5)]"></span>
</span>
<span className="font-mono tracking-wide">{statusVerb}{'.'.repeat(statusDots)}</span>
</span>
) : isComplete ? (
<span className="text-[#6a7587] font-mono tracking-wide">AUDIT {task.status?.toUpperCase()}</span>
<span className="text-muted-foreground font-mono tracking-wide">AUDIT {task.status?.toUpperCase()}</span>
) : (
<span className="text-[#4a5565] font-mono tracking-wide">READY</span>
<span className="text-muted-foreground font-mono tracking-wide">READY</span>
)}
</span>
<div className="flex items-center gap-4 font-mono text-[#6a7587]">
<div className="flex items-center gap-4 font-mono text-muted-foreground">
<span>
<span className="text-primary text-glow-primary">{task.progress_percentage?.toFixed(0) || 0}</span>
<span className="text-[#4a5565]">%</span>
<span className="text-muted-foreground">%</span>
</span>
<span className="text-[#2a3545]"></span>
<span className="text-border"></span>
<span>
<span className="text-[#a8b0c0]">{task.analyzed_files}</span>
<span className="text-[#4a5565]">/{task.total_files} files</span>
<span className="text-foreground">{task.analyzed_files}</span>
<span className="text-muted-foreground">/{task.total_files} files</span>
</span>
<span className="text-[#2a3545]"></span>
<span className="text-border"></span>
<span>
<span className="text-[#a8b0c0]">{task.tool_calls_count || 0}</span>
<span className="text-[#4a5565]"> tools</span>
<span className="text-foreground">{task.tool_calls_count || 0}</span>
<span className="text-muted-foreground"> tools</span>
</span>
</div>
</div>
@ -922,16 +922,16 @@ function AgentAuditPageContent() {
</div>
{/* Right Panel - Agent Tree + Stats */}
<div className="w-1/4 flex flex-col bg-[#080a0e]">
<div className="w-1/4 flex flex-col bg-background">
{/* Agent Tree section */}
<div className="flex-1 flex flex-col border-b border-[#1a2535] overflow-hidden">
<div className="flex-1 flex flex-col border-b border-border overflow-hidden">
{/* Tree header */}
<div className="flex-shrink-0 h-11 border-b border-[#1a2535] flex items-center justify-between px-4 bg-[#0a0c10]/90">
<div className="flex items-center gap-2 text-xs text-[#8a95a5]">
<Bot className="w-4 h-4 text-[#5a6577]" />
<span className="uppercase font-bold tracking-[0.15em] text-[#d0d8e8]">Agent Tree</span>
<div className="flex-shrink-0 h-11 border-b border-border flex items-center justify-between px-4 cyber-bg-elevated/90">
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Bot className="w-4 h-4 text-muted-foreground" />
<span className="uppercase font-bold tracking-[0.15em] text-foreground">Agent Tree</span>
{agentTree && (
<Badge variant="outline" className="h-5 px-1.5 text-[10px] border-[#2a3545] text-[#6a7587] font-mono bg-[#0d1015]">
<Badge variant="outline" className="h-5 px-1.5 text-xs border-border text-muted-foreground font-mono bg-muted">
{agentTree.total_agents}
</Badge>
)}
@ -940,25 +940,25 @@ function AgentAuditPageContent() {
{selectedAgentId && !showAllLogs && (
<button
onClick={() => selectAgent(null)}
className="text-[10px] text-primary hover:text-primary/80 transition-colors font-mono uppercase tracking-wider"
className="text-xs text-primary hover:text-primary/80 transition-colors font-mono uppercase tracking-wider"
>
Show All
</button>
)}
{agentTree && agentTree.running_agents > 0 && (
<div className="flex items-center gap-1.5 text-[#3dd68c]">
<div className="flex items-center gap-1.5 text-emerald-400">
<span className="relative flex h-1.5 w-1.5">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-[#3dd68c] opacity-75"></span>
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-[#3dd68c] shadow-[0_0_6px_rgba(61,214,140,0.5)]"></span>
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-emerald-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-1.5 w-1.5 bg-emerald-400 shadow-[0_0_6px_rgba(61,214,140,0.5)]"></span>
</span>
<span className="text-[10px] font-mono">{agentTree.running_agents}</span>
<span className="text-xs font-mono">{agentTree.running_agents}</span>
</div>
)}
</div>
</div>
{/* Tree content */}
<div className="flex-1 overflow-y-auto p-2 custom-scrollbar bg-[#060810]/50">
<div className="flex-1 overflow-y-auto p-2 custom-scrollbar bg-background/50">
{treeNodes.length > 0 ? (
treeNodes.map(node => (
<AgentTreeNodeItem
@ -969,7 +969,7 @@ function AgentAuditPageContent() {
/>
))
) : (
<div className="h-full flex items-center justify-center text-[#4a5565] text-xs">
<div className="h-full flex items-center justify-center text-muted-foreground text-xs">
{isRunning ? (
<div className="flex items-center gap-2">
<Loader2 className="w-3 h-3 animate-spin" />
@ -984,7 +984,7 @@ function AgentAuditPageContent() {
</div>
{/* Bottom section - Details + Stats */}
<div className="flex-shrink-0 p-3 space-y-3 max-h-[50%] overflow-y-auto custom-scrollbar">
<div className="flex-shrink-0 p-3 space-y-3">
{/* Agent detail panel */}
{selectedAgentId && !showAllLogs && (
<AgentDetailPanel

View File

@ -235,17 +235,17 @@ export default function AuditRules() {
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen bg-[#0a0a0f]">
<div className="flex items-center justify-center min-h-screen cyber-bg-elevated">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -304,7 +304,7 @@ export default function AuditRules() {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto flex gap-2">
<Button variant="outline" onClick={() => setShowImportDialog(true)} className="cyber-btn-outline h-9">
<Upload className="w-4 h-4 mr-2" />
@ -336,26 +336,26 @@ export default function AuditRules() {
ruleSets.map(ruleSet => (
<div key={ruleSet.id} className={`cyber-card p-0 ${!ruleSet.is_active ? 'opacity-60' : ''}`}>
{/* Rule Set Header */}
<div className="p-6 border-b border-gray-800">
<div className="p-6 border-b border-border">
<div className="flex items-center justify-between">
<div className="flex items-center gap-4 cursor-pointer" onClick={() => toggleExpand(ruleSet.id)}>
<div className="w-10 h-10 bg-gray-800 border border-gray-700 flex items-center justify-center rounded">
{expandedSets.has(ruleSet.id) ? <ChevronDown className="w-5 h-5 text-gray-400" /> : <ChevronRight className="w-5 h-5 text-gray-400" />}
<div className="w-10 h-10 bg-muted border border-border flex items-center justify-center rounded">
{expandedSets.has(ruleSet.id) ? <ChevronDown className="w-5 h-5 text-muted-foreground" /> : <ChevronRight className="w-5 h-5 text-muted-foreground" />}
</div>
<div>
<h3 className="font-bold text-lg text-white uppercase flex items-center gap-2">
<h3 className="font-bold text-lg text-foreground uppercase flex items-center gap-2">
{ruleSet.name}
{ruleSet.is_system && <Badge className="cyber-badge-info"></Badge>}
{ruleSet.is_default && <Badge className="cyber-badge-success"></Badge>}
</h3>
<p className="text-sm text-gray-500">{ruleSet.description}</p>
<p className="text-sm text-muted-foreground">{ruleSet.description}</p>
</div>
</div>
<div className="flex items-center gap-3">
<Badge className="cyber-badge-muted">{LANGUAGES.find(l => l.value === ruleSet.language)?.label}</Badge>
<Badge className="cyber-badge-muted">{RULE_TYPES.find(t => t.value === ruleSet.rule_type)?.label}</Badge>
<span className="text-sm font-mono text-gray-400 px-3 py-1 bg-gray-800 border border-gray-700 rounded">
<span className="text-sm font-mono text-muted-foreground px-3 py-1 bg-muted border border-border rounded">
{ruleSet.enabled_rules_count}/{ruleSet.rules_count}
</span>
<Button variant="ghost" size="icon" onClick={() => handleExport(ruleSet)} className="cyber-btn-ghost h-9 w-9">
@ -391,19 +391,19 @@ export default function AuditRules() {
const severityInfo = getSeverityInfo(rule.severity);
const CategoryIcon = categoryInfo.icon;
return (
<div key={rule.id} className={`cyber-card p-4 hover:border-gray-700 transition-all ${!rule.enabled ? 'opacity-50' : ''}`}>
<div key={rule.id} className={`cyber-card p-4 hover:border-border transition-all ${!rule.enabled ? 'opacity-50' : ''}`}>
<div className="flex items-start justify-between">
<div className="flex items-start gap-4">
<div className={`w-10 h-10 ${categoryInfo.bg} border border-gray-700 flex items-center justify-center rounded`}>
<div className={`w-10 h-10 ${categoryInfo.bg} border border-border flex items-center justify-center rounded`}>
<CategoryIcon className={`w-5 h-5 ${categoryInfo.color}`} />
</div>
<div>
<div className="flex items-center gap-2 mb-1">
<span className="font-mono text-xs bg-gray-800 text-primary px-2 py-0.5 rounded">{rule.rule_code}</span>
<span className="font-bold uppercase text-gray-200">{rule.name}</span>
<span className="font-mono text-xs bg-muted text-primary px-2 py-0.5 rounded">{rule.rule_code}</span>
<span className="font-bold uppercase text-foreground">{rule.name}</span>
<Badge className={severityInfo.color}>{severityInfo.label}</Badge>
</div>
{rule.description && <p className="text-sm text-gray-500 mb-2">{rule.description}</p>}
{rule.description && <p className="text-sm text-muted-foreground mb-2">{rule.description}</p>}
{rule.reference_url && (
<a href={rule.reference_url} target="_blank" rel="noopener noreferrer" className="text-sm text-primary hover:underline flex items-center gap-1">
<ExternalLink className="w-3 h-3" />
@ -435,9 +435,9 @@ export default function AuditRules() {
{/* Create Rule Set Dialog */}
<Dialog open={showCreateDialog} onOpenChange={setShowCreateDialog}>
<DialogContent className="!w-[min(90vw,500px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,500px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Terminal className="w-5 h-5 text-primary" />
</div>
@ -446,35 +446,35 @@ export default function AuditRules() {
</DialogHeader>
<div className="flex-1 overflow-y-auto p-6 space-y-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> *</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> *</Label>
<Input value={ruleSetForm.name} onChange={e => setRuleSetForm({ ...ruleSetForm, name: e.target.value })} placeholder="规则集名称" className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={ruleSetForm.description} onChange={e => setRuleSetForm({ ...ruleSetForm, description: e.target.value })} placeholder="规则集描述" className="cyber-input" />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleSetForm.language} onValueChange={v => setRuleSetForm({ ...ruleSetForm, language: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{LANGUAGES.map(l => <SelectItem key={l.value} value={l.value}>{l.label}</SelectItem>)}
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleSetForm.rule_type} onValueChange={v => setRuleSetForm({ ...ruleSetForm, rule_type: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{RULE_TYPES.map(t => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}
</SelectContent>
</Select>
</div>
</div>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowCreateDialog(false)} className="cyber-btn-outline"></Button>
<Button onClick={handleCreateRuleSet} className="cyber-btn-primary"></Button>
</DialogFooter>
@ -483,9 +483,9 @@ export default function AuditRules() {
{/* Edit Rule Set Dialog */}
<Dialog open={showEditDialog} onOpenChange={setShowEditDialog}>
<DialogContent className="!w-[min(90vw,500px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,500px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Edit className="w-5 h-5 text-primary" />
</div>
@ -494,31 +494,31 @@ export default function AuditRules() {
</DialogHeader>
<div className="flex-1 overflow-y-auto p-6 space-y-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input value={ruleSetForm.name} onChange={e => setRuleSetForm({ ...ruleSetForm, name: e.target.value })} className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={ruleSetForm.description} onChange={e => setRuleSetForm({ ...ruleSetForm, description: e.target.value })} className="cyber-input" />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleSetForm.language} onValueChange={v => setRuleSetForm({ ...ruleSetForm, language: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">{LANGUAGES.map(l => <SelectItem key={l.value} value={l.value}>{l.label}</SelectItem>)}</SelectContent>
<SelectContent className="cyber-dialog border-border">{LANGUAGES.map(l => <SelectItem key={l.value} value={l.value}>{l.label}</SelectItem>)}</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleSetForm.rule_type} onValueChange={v => setRuleSetForm({ ...ruleSetForm, rule_type: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">{RULE_TYPES.map(t => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}</SelectContent>
<SelectContent className="cyber-dialog border-border">{RULE_TYPES.map(t => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}</SelectContent>
</Select>
</div>
</div>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowEditDialog(false)} className="cyber-btn-outline"></Button>
<Button onClick={handleUpdateRuleSet} className="cyber-btn-primary"></Button>
</DialogFooter>
@ -527,9 +527,9 @@ export default function AuditRules() {
{/* Rule Edit Dialog */}
<Dialog open={showRuleDialog} onOpenChange={setShowRuleDialog}>
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Code className="w-5 h-5 text-primary" />
</div>
@ -539,48 +539,48 @@ export default function AuditRules() {
<div className="flex-1 overflow-y-auto p-6 space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> *</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> *</Label>
<Input value={ruleForm.rule_code} onChange={e => setRuleForm({ ...ruleForm, rule_code: e.target.value })} placeholder="如 SEC001" className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> *</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> *</Label>
<Input value={ruleForm.name} onChange={e => setRuleForm({ ...ruleForm, name: e.target.value })} placeholder="规则名称" className="cyber-input" />
</div>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={ruleForm.description} onChange={e => setRuleForm({ ...ruleForm, description: e.target.value })} placeholder="规则描述" className="cyber-input" />
</div>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleForm.category} onValueChange={v => setRuleForm({ ...ruleForm, category: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">{CATEGORIES.map(c => <SelectItem key={c.value} value={c.value}>{c.label}</SelectItem>)}</SelectContent>
<SelectContent className="cyber-dialog border-border">{CATEGORIES.map(c => <SelectItem key={c.value} value={c.value}>{c.label}</SelectItem>)}</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={ruleForm.severity} onValueChange={v => setRuleForm({ ...ruleForm, severity: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">{SEVERITIES.map(s => <SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>)}</SelectContent>
<SelectContent className="cyber-dialog border-border">{SEVERITIES.map(s => <SelectItem key={s.value} value={s.value}>{s.label}</SelectItem>)}</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={ruleForm.custom_prompt} onChange={e => setRuleForm({ ...ruleForm, custom_prompt: e.target.value })} placeholder="用于增强LLM检测的自定义提示词" rows={3} className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={ruleForm.fix_suggestion} onChange={e => setRuleForm({ ...ruleForm, fix_suggestion: e.target.value })} placeholder="修复建议模板" rows={2} className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input value={ruleForm.reference_url} onChange={e => setRuleForm({ ...ruleForm, reference_url: e.target.value })} placeholder="如 https://owasp.org/..." className="cyber-input" />
</div>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowRuleDialog(false)} className="cyber-btn-outline"></Button>
<Button onClick={selectedRule ? handleUpdateRule : handleAddRule} className="cyber-btn-primary">{selectedRule ? '保存' : '添加'}</Button>
</DialogFooter>
@ -589,22 +589,22 @@ export default function AuditRules() {
{/* Import Dialog */}
<Dialog open={showImportDialog} onOpenChange={setShowImportDialog}>
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Upload className="w-5 h-5 text-primary" />
</div>
<div>
<span className="text-base font-bold uppercase tracking-wider"></span>
<p className="text-xs text-gray-500 font-normal mt-0.5"> JSON </p>
<p className="text-xs text-muted-foreground font-normal mt-0.5"> JSON </p>
</div>
</DialogTitle>
</DialogHeader>
<div className="flex-1 overflow-y-auto p-6">
<Textarea value={importJson} onChange={e => setImportJson(e.target.value)} placeholder='{"name": "...", "rules": [...]}' rows={15} className="cyber-input font-mono text-sm text-emerald-400" />
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowImportDialog(false)} className="cyber-btn-outline"></Button>
<Button onClick={handleImport} className="cyber-btn-primary"></Button>
</DialogFooter>

View File

@ -239,8 +239,8 @@ export default function AuditTasks() {
case 'completed': return <CheckCircle className="w-4 h-4 text-emerald-400" />;
case 'running': return <Activity className="w-4 h-4 text-sky-400" />;
case 'failed': return <AlertTriangle className="w-4 h-4 text-rose-400" />;
case 'cancelled': return <XCircle className="w-4 h-4 text-gray-400" />;
default: return <Clock className="w-4 h-4 text-gray-400" />;
case 'cancelled': return <XCircle className="w-4 h-4 text-muted-foreground" />;
default: return <Clock className="w-4 h-4 text-muted-foreground" />;
}
};
@ -290,14 +290,14 @@ export default function AuditTasks() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -311,7 +311,7 @@ export default function AuditTasks() {
transition-all duration-300 border-2 overflow-hidden
${activeTab === "agent"
? "bg-gradient-to-br from-primary/20 via-primary/10 to-transparent border-primary shadow-lg shadow-primary/20"
: "bg-gray-900/50 border-gray-800 hover:border-primary/50 hover:bg-gray-900/80"
: "bg-muted border-border hover:border-primary/50 hover:bg-card/80"
}
`}
>
@ -326,17 +326,17 @@ export default function AuditTasks() {
transition-all duration-300
${activeTab === "agent"
? "bg-primary/30 shadow-lg shadow-primary/30"
: "bg-gray-800/80 group-hover:bg-primary/20"
: "bg-muted/80 group-hover:bg-primary/20"
}
`}>
<Bot className={`w-7 h-7 transition-colors duration-300 ${activeTab === "agent" ? "text-primary" : "text-gray-400 group-hover:text-primary"
<Bot className={`w-7 h-7 transition-colors duration-300 ${activeTab === "agent" ? "text-primary" : "text-muted-foreground group-hover:text-primary"
}`} />
</div>
{/* 内容区域 */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<h3 className={`text-lg font-mono font-bold uppercase tracking-[0.15em] transition-colors duration-300 ${activeTab === "agent" ? "text-primary text-glow-primary" : "text-gray-300 group-hover:text-primary"}`}>
<h3 className={`text-lg font-mono font-bold uppercase tracking-[0.15em] transition-colors duration-300 ${activeTab === "agent" ? "text-primary text-glow-primary" : "text-foreground group-hover:text-primary"}`}>
Agent
</h3>
{agentStats.running > 0 && (
@ -345,20 +345,20 @@ export default function AuditTasks() {
</span>
)}
{activeTab === "agent" && (
<span className="px-2 py-0.5 text-xs font-bold rounded-full bg-primary text-black">
<span className="px-2 py-0.5 text-xs font-bold rounded-full bg-primary text-background">
</span>
)}
</div>
<p className={`text-sm transition-colors duration-300 ${activeTab === "agent" ? "text-gray-300" : "text-gray-500 group-hover:text-gray-400"
<p className={`text-sm transition-colors duration-300 ${activeTab === "agent" ? "text-foreground" : "text-muted-foreground group-hover:text-muted-foreground"
}`}>
LLM Agent
</p>
{/* 统计数据 */}
<div className="flex items-center gap-4 mt-3 text-xs">
<span className={`transition-colors duration-300 ${activeTab === "agent" ? "text-gray-400" : "text-gray-600"}`}>
<span className="font-bold text-white">{agentStats.total}</span>
<span className={`transition-colors duration-300 ${activeTab === "agent" ? "text-muted-foreground" : "text-muted-foreground"}`}>
<span className="font-bold text-foreground">{agentStats.total}</span>
</span>
<span className="text-emerald-400">
<CheckCircle className="w-3 h-3 inline mr-1" />
@ -388,7 +388,7 @@ export default function AuditTasks() {
transition-all duration-300 border-2 overflow-hidden
${activeTab === "regular"
? "bg-gradient-to-br from-cyan-500/20 via-cyan-500/10 to-transparent border-cyan-500 shadow-lg shadow-cyan-500/20"
: "bg-gray-900/50 border-gray-800 hover:border-cyan-500/50 hover:bg-gray-900/80"
: "bg-muted border-border hover:border-cyan-500/50 hover:bg-card/80"
}
`}
>
@ -403,17 +403,17 @@ export default function AuditTasks() {
transition-all duration-300
${activeTab === "regular"
? "bg-cyan-500/30 shadow-lg shadow-cyan-500/30"
: "bg-gray-800/80 group-hover:bg-cyan-500/20"
: "bg-muted/80 group-hover:bg-cyan-500/20"
}
`}>
<Zap className={`w-7 h-7 transition-colors duration-300 ${activeTab === "regular" ? "text-cyan-400" : "text-gray-400 group-hover:text-cyan-400"
<Zap className={`w-7 h-7 transition-colors duration-300 ${activeTab === "regular" ? "text-cyan-400" : "text-muted-foreground group-hover:text-cyan-400"
}`} />
</div>
{/* 内容区域 */}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<h3 className={`text-lg font-mono font-bold uppercase tracking-[0.15em] transition-colors duration-300 ${activeTab === "regular" ? "text-cyan-400 text-glow-cyan" : "text-gray-300 group-hover:text-cyan-400"}`}>
<h3 className={`text-lg font-mono font-bold uppercase tracking-[0.15em] transition-colors duration-300 ${activeTab === "regular" ? "text-cyan-400 text-glow-cyan" : "text-foreground group-hover:text-cyan-400"}`}>
</h3>
{regularStats.running > 0 && (
@ -422,20 +422,20 @@ export default function AuditTasks() {
</span>
)}
{activeTab === "regular" && (
<span className="px-2 py-0.5 text-xs font-bold rounded-full bg-cyan-500 text-black">
<span className="px-2 py-0.5 text-xs font-bold rounded-full bg-cyan-500 text-background">
</span>
)}
</div>
<p className={`text-sm transition-colors duration-300 ${activeTab === "regular" ? "text-gray-300" : "text-gray-500 group-hover:text-gray-400"
<p className={`text-sm transition-colors duration-300 ${activeTab === "regular" ? "text-foreground" : "text-muted-foreground group-hover:text-muted-foreground"
}`}>
</p>
{/* 统计数据 */}
<div className="flex items-center gap-4 mt-3 text-xs">
<span className={`transition-colors duration-300 ${activeTab === "regular" ? "text-gray-400" : "text-gray-600"}`}>
<span className="font-bold text-white">{regularStats.total}</span>
<span className={`transition-colors duration-300 ${activeTab === "regular" ? "text-muted-foreground" : "text-muted-foreground"}`}>
<span className="font-bold text-foreground">{regularStats.total}</span>
</span>
<span className="text-emerald-400">
<CheckCircle className="w-3 h-3 inline mr-1" />
@ -513,7 +513,7 @@ export default function AuditTasks() {
<div className="cyber-card p-4 relative z-10">
<div className="flex flex-col md:flex-row items-center gap-4">
<div className="flex-1 relative w-full">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 w-4 h-4 z-10" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4 z-10" />
<Input
placeholder={activeTab === "agent" ? "搜索Agent任务名称..." : "搜索项目名称或任务类型..."}
value={searchTerm}
@ -544,21 +544,21 @@ export default function AuditTasks() {
<Button
size="sm"
onClick={() => setStatusFilter("running")}
className={`h-10 ${statusFilter === "running" ? "bg-sky-500/90 border-sky-500/50 text-white hover:bg-sky-500" : "cyber-btn-outline"}`}
className={`h-10 ${statusFilter === "running" ? "bg-sky-500/90 border-sky-500/50 text-foreground hover:bg-sky-500" : "cyber-btn-outline"}`}
>
</Button>
<Button
size="sm"
onClick={() => setStatusFilter("completed")}
className={`h-10 ${statusFilter === "completed" ? "bg-emerald-500/90 border-emerald-500/50 text-white hover:bg-emerald-500" : "cyber-btn-outline"}`}
className={`h-10 ${statusFilter === "completed" ? "bg-emerald-500/90 border-emerald-500/50 text-foreground hover:bg-emerald-500" : "cyber-btn-outline"}`}
>
</Button>
<Button
size="sm"
onClick={() => setStatusFilter("failed")}
className={`h-10 ${statusFilter === "failed" ? "bg-rose-500/90 border-rose-500/50 text-white hover:bg-rose-500" : "cyber-btn-outline"}`}
className={`h-10 ${statusFilter === "failed" ? "bg-rose-500/90 border-rose-500/50 text-foreground hover:bg-rose-500" : "cyber-btn-outline"}`}
>
</Button>
@ -574,24 +574,24 @@ export default function AuditTasks() {
{filteredAgentTasks.map((task) => (
<div key={task.id} className="cyber-card p-6">
{/* Task Header */}
<div className="flex items-center justify-between mb-4 pb-4 border-b border-gray-800">
<div className="flex items-center justify-between mb-4 pb-4 border-b border-border">
<div className="flex items-center space-x-4">
<div className={`w-12 h-12 rounded-lg flex items-center justify-center ${task.status === 'completed' ? 'bg-emerald-500/20' :
task.status === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/20' :
'bg-gray-800/50'
'bg-muted'
}`}>
<Bot className={`w-6 h-6 ${task.status === 'completed' ? 'text-emerald-400' :
task.status === 'running' ? 'text-sky-400' :
task.status === 'failed' ? 'text-rose-400' :
'text-gray-400'
'text-muted-foreground'
}`} />
</div>
<div>
<h3 className="font-bold text-xl text-white uppercase tracking-wide">
<h3 className="font-bold text-xl text-foreground uppercase tracking-wide">
{task.name || 'Agent审计任务'}
</h3>
<p className="text-sm text-gray-500 font-mono">
<p className="text-sm text-muted-foreground font-mono">
{task.current_phase || task.task_type}
</p>
</div>
@ -611,25 +611,25 @@ export default function AuditTasks() {
{/* Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-4 font-mono">
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.total_files}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.total_files}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.analyzed_files}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.analyzed_files}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-amber-400">{task.findings_count}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-sky-400">{task.tool_calls_count || 0}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-primary">{task.security_score?.toFixed(1) || '-'}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
</div>
@ -654,25 +654,25 @@ export default function AuditTasks() {
{/* Progress Bar */}
<div className="mb-4 font-mono">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-bold text-gray-400 uppercase"></span>
<span className="text-sm text-gray-500">
<span className="text-sm font-bold text-muted-foreground uppercase"></span>
<span className="text-sm text-muted-foreground">
{task.analyzed_files || 0} / {task.total_files || 0}
</span>
</div>
<Progress
value={task.progress_percentage || 0}
className="h-2 bg-gray-800 [&>div]:bg-primary"
className="h-2 bg-muted [&>div]:bg-primary"
/>
<div className="text-right mt-1">
<span className="text-xs text-gray-500">
<span className="text-xs text-muted-foreground">
{(task.progress_percentage || 0).toFixed(0)}%
</span>
</div>
</div>
{/* Task Footer */}
<div className="flex items-center justify-between pt-4 border-t border-gray-800">
<div className="flex items-center space-x-6 text-sm text-gray-500 font-mono">
<div className="flex items-center justify-between pt-4 border-t border-border">
<div className="flex items-center space-x-6 text-sm text-muted-foreground font-mono">
<div className="flex items-center">
<Calendar className="w-4 h-4 mr-2" />
{formatDate(task.created_at)}
@ -684,7 +684,7 @@ export default function AuditTasks() {
</div>
)}
{task.tokens_used > 0 && (
<div className="flex items-center text-gray-600">
<div className="flex items-center text-muted-foreground">
<span>{task.tokens_used.toLocaleString()} tokens</span>
</div>
)}
@ -695,14 +695,14 @@ export default function AuditTasks() {
<>
{/* 🔥 查看终端实时流按钮 */}
<Link to={`/agent-audit/${task.id}`}>
<Button size="sm" className="cyber-btn bg-sky-500/90 border-sky-500/50 text-white hover:bg-sky-500 h-9">
<Button size="sm" className="cyber-btn bg-sky-500/90 border-sky-500/50 text-foreground hover:bg-sky-500 h-9">
<Terminal className="w-4 h-4 mr-2" />
</Button>
</Link>
<Button
size="sm"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-white hover:bg-rose-500 h-9"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-foreground hover:bg-rose-500 h-9"
onClick={() => handleCancelAgentTask(task.id)}
disabled={cancellingAgentTaskId === task.id}
>
@ -725,11 +725,11 @@ export default function AuditTasks() {
</div>
) : (
<div className="cyber-card p-16 text-center relative z-10 border-dashed">
<Bot className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<h3 className="text-xl font-bold text-gray-300 mb-2 uppercase">
<Bot className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-xl font-bold text-foreground mb-2 uppercase">
{searchTerm || statusFilter !== "all" ? '未找到匹配的Agent任务' : '暂无Agent审计任务'}
</h3>
<p className="text-gray-500 mb-6 font-mono">
<p className="text-muted-foreground mb-6 font-mono">
{searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个Agent审计任务开始智能安全审计'}
</p>
{!searchTerm && statusFilter === "all" && (
@ -751,20 +751,20 @@ export default function AuditTasks() {
{filteredTasks.map((task) => (
<div key={task.id} className="cyber-card p-6">
{/* Task Header */}
<div className="flex items-center justify-between mb-4 pb-4 border-b border-gray-800">
<div className="flex items-center justify-between mb-4 pb-4 border-b border-border">
<div className="flex items-center space-x-4">
<div className={`w-12 h-12 rounded-lg flex items-center justify-center ${task.status === 'completed' ? 'bg-emerald-500/20' :
task.status === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/20' :
'bg-gray-800/50'
'bg-muted'
}`}>
{getStatusIcon(task.status)}
</div>
<div>
<h3 className="font-bold text-xl text-white uppercase tracking-wide">
<h3 className="font-bold text-xl text-foreground uppercase tracking-wide">
{task.project?.name || '未知项目'}
</h3>
<p className="text-sm text-gray-500 font-mono">
<p className="text-sm text-muted-foreground font-mono">
{task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'}
</p>
</div>
@ -774,46 +774,46 @@ export default function AuditTasks() {
{/* Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4 font-mono">
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.total_files}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.total_files}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.total_lines.toLocaleString()}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.total_lines.toLocaleString()}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-amber-400">{task.issues_count}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-primary">{task.quality_score.toFixed(1)}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
</div>
{/* Progress Bar */}
<div className="mb-4 font-mono">
<div className="flex items-center justify-between mb-2">
<span className="text-sm font-bold text-gray-400 uppercase"></span>
<span className="text-sm text-gray-500">
<span className="text-sm font-bold text-muted-foreground uppercase"></span>
<span className="text-sm text-muted-foreground">
{task.scanned_files || 0} / {task.total_files || 0}
</span>
</div>
<Progress
value={calculateTaskProgress(task.scanned_files, task.total_files)}
className="h-2 bg-gray-800 [&>div]:bg-primary"
className="h-2 bg-muted [&>div]:bg-primary"
/>
<div className="text-right mt-1">
<span className="text-xs text-gray-500">
<span className="text-xs text-muted-foreground">
{calculateTaskProgress(task.scanned_files, task.total_files)}%
</span>
</div>
</div>
{/* Task Footer */}
<div className="flex items-center justify-between pt-4 border-t border-gray-800">
<div className="flex items-center space-x-6 text-sm text-gray-500 font-mono">
<div className="flex items-center justify-between pt-4 border-t border-border">
<div className="flex items-center space-x-6 text-sm text-muted-foreground font-mono">
<div className="flex items-center">
<Calendar className="w-4 h-4 mr-2" />
{formatDate(task.created_at)}
@ -830,7 +830,7 @@ export default function AuditTasks() {
{(task.status === 'running' || task.status === 'pending') && (
<Button
size="sm"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-white hover:bg-rose-500 h-9"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-foreground hover:bg-rose-500 h-9"
onClick={() => handleCancelTask(task.id)}
disabled={cancellingTaskId === task.id}
>
@ -859,11 +859,11 @@ export default function AuditTasks() {
</div>
) : (
<div className="cyber-card p-16 text-center relative z-10 border-dashed">
<Activity className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<h3 className="text-xl font-bold text-gray-300 mb-2 uppercase">
<Activity className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-xl font-bold text-foreground mb-2 uppercase">
{searchTerm || statusFilter !== "all" ? '未找到匹配的任务' : '暂无审计任务'}
</h3>
<p className="text-gray-500 mb-6 font-mono">
<p className="text-muted-foreground mb-6 font-mono">
{searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个审计任务开始代码质量分析'}
</p>
{!searchTerm && statusFilter === "all" && (

View File

@ -166,14 +166,14 @@ export default function Dashboard() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-base uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 bg-background min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -182,7 +182,7 @@ export default function Dashboard() {
<div className="relative z-10 cyber-card p-4 border-amber-500/30 bg-amber-500/5">
<div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 text-amber-400 mt-0.5" />
<div className="text-sm text-gray-300">
<div className="text-sm text-foreground/80">
使<span className="text-amber-400 font-bold"></span>
<Link to="/admin" className="ml-2 text-primary font-bold hover:underline">
@ -200,8 +200,8 @@ export default function Dashboard() {
<div>
<p className="stat-label"></p>
<p className="stat-value">{stats?.total_projects || 0}</p>
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
<p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-2 h-2 rounded-full bg-emerald-400" />
: {stats?.active_projects || 0}
</p>
</div>
@ -217,8 +217,8 @@ export default function Dashboard() {
<div>
<p className="stat-label"></p>
<p className="stat-value">{stats?.total_tasks || 0}</p>
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" />
<p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-2 h-2 rounded-full bg-emerald-400" />
: {stats?.completed_tasks || 0}
</p>
</div>
@ -234,8 +234,8 @@ export default function Dashboard() {
<div>
<p className="stat-label"></p>
<p className="stat-value">{stats?.total_issues || 0}</p>
<p className="text-xs text-amber-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-amber-400" />
<p className="text-sm text-amber-400 mt-1 flex items-center gap-1">
<span className="w-2 h-2 rounded-full bg-amber-400" />
: {stats?.resolved_issues || 0}
</p>
</div>
@ -254,12 +254,12 @@ export default function Dashboard() {
{stats?.avg_quality_score ? stats.avg_quality_score.toFixed(1) : '0.0'}
</p>
{stats?.avg_quality_score ? (
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1">
<TrendingUp className="w-3 h-3" />
<p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<TrendingUp className="w-4 h-4" />
</p>
) : (
<p className="text-xs text-gray-500 mt-1"></p>
<p className="text-sm text-muted-foreground mt-1"></p>
)}
</div>
<div className="stat-icon text-violet-400">
@ -284,25 +284,26 @@ export default function Dashboard() {
{qualityTrendData.length > 0 ? (
<ResponsiveContainer width="100%" height={220}>
<LineChart data={qualityTrendData}>
<CartesianGrid strokeDasharray="3 3" stroke="#1f1f2e" />
<XAxis dataKey="date" stroke="#6b7280" fontSize={11} tick={{ fontFamily: 'monospace' }} />
<YAxis stroke="#6b7280" fontSize={11} domain={[0, 100]} tick={{ fontFamily: 'monospace' }} />
<CartesianGrid strokeDasharray="3 3" stroke="var(--cyber-border)" />
<XAxis dataKey="date" stroke="var(--cyber-text-muted)" fontSize={11} tick={{ fontFamily: 'monospace' }} />
<YAxis stroke="var(--cyber-text-muted)" fontSize={11} domain={[0, 100]} tick={{ fontFamily: 'monospace' }} />
<Tooltip
contentStyle={{
backgroundColor: '#0c0c12',
border: '1px solid #2a2a35',
backgroundColor: 'var(--cyber-bg-elevated)',
border: '1px solid var(--cyber-border)',
borderRadius: '4px',
fontFamily: 'monospace',
fontSize: '12px'
fontSize: '12px',
color: 'var(--cyber-text)'
}}
/>
<Line
type="monotone"
dataKey="score"
stroke="#FF6B2C"
stroke="hsl(var(--primary))"
strokeWidth={2}
dot={{ fill: '#FF6B2C', stroke: '#0c0c12', strokeWidth: 2, r: 4 }}
activeDot={{ r: 6, fill: '#FF6B2C' }}
dot={{ fill: 'hsl(var(--primary))', stroke: 'var(--cyber-bg)', strokeWidth: 2, r: 4 }}
activeDot={{ r: 6, fill: 'hsl(var(--primary))' }}
/>
</LineChart>
</ResponsiveContainer>
@ -331,7 +332,7 @@ export default function Dashboard() {
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
outerRadius={70}
dataKey="value"
stroke="#0c0c12"
stroke="var(--cyber-bg)"
strokeWidth={2}
>
{issueTypeData.map((entry) => (
@ -340,11 +341,12 @@ export default function Dashboard() {
</Pie>
<Tooltip
contentStyle={{
backgroundColor: '#0c0c12',
border: '1px solid #2a2a35',
backgroundColor: 'var(--cyber-bg-elevated)',
border: '1px solid var(--cyber-border)',
borderRadius: '4px',
fontFamily: 'monospace',
fontSize: '12px'
fontSize: '12px',
color: 'var(--cyber-text)'
}}
/>
</PieChart>
@ -370,21 +372,33 @@ export default function Dashboard() {
<Link
key={project.id}
to={`/projects/${project.id}`}
className="block p-4 bg-gray-900/50 border border-gray-800/50 rounded-lg hover:bg-gray-800/50 hover:border-gray-700 transition-all group"
className="block p-4 rounded-lg transition-all group"
style={{
background: 'var(--cyber-bg-elevated)',
border: '1px solid var(--cyber-border)'
}}
onMouseOver={(e) => {
e.currentTarget.style.background = 'var(--cyber-hover-bg)';
e.currentTarget.style.borderColor = 'var(--cyber-border-accent)';
}}
onMouseOut={(e) => {
e.currentTarget.style.background = 'var(--cyber-bg-elevated)';
e.currentTarget.style.borderColor = 'var(--cyber-border)';
}}
>
<div className="flex items-start justify-between mb-2">
<h4 className="font-semibold text-gray-200 group-hover:text-primary transition-colors truncate">
<h4 className="font-semibold text-foreground group-hover:text-primary transition-colors truncate">
{project.name}
</h4>
<Badge className={`ml-2 flex-shrink-0 ${project.is_active ? 'cyber-badge-success' : 'cyber-badge-muted'}`}>
{project.is_active ? '活跃' : '暂停'}
</Badge>
</div>
<p className="text-xs text-gray-500 line-clamp-2 mb-3">
<p className="text-sm text-muted-foreground line-clamp-2 mb-3">
{project.description || '暂无描述'}
</p>
<div className="flex items-center text-xs text-gray-600">
<Calendar className="w-3 h-3 mr-1" />
<div className="flex items-center text-sm text-muted-foreground">
<Calendar className="w-4 h-4 mr-1" />
{new Date(project.created_at).toLocaleDateString('zh-CN')}
</div>
</Link>
@ -405,7 +419,7 @@ export default function Dashboard() {
<Clock className="w-5 h-5 text-emerald-400" />
<h3 className="section-title"></h3>
<Link to="/audit-tasks" className="ml-auto">
<Button variant="ghost" size="sm" className="text-gray-400 hover:text-white">
<Button variant="ghost" size="sm" className="text-muted-foreground hover:text-foreground">
<ArrowUpRight className="w-3 h-3 ml-1" />
</Button>
</Link>
@ -416,7 +430,16 @@ export default function Dashboard() {
<Link
key={task.id}
to={`/tasks/${task.id}`}
className="flex items-center justify-between p-3 bg-gray-900/30 rounded-lg hover:bg-gray-800/50 transition-all group"
className="flex items-center justify-between p-3 rounded-lg transition-all group"
style={{
background: 'var(--cyber-bg-elevated)',
}}
onMouseOver={(e) => {
e.currentTarget.style.background = 'var(--cyber-hover-bg)';
}}
onMouseOut={(e) => {
e.currentTarget.style.background = 'var(--cyber-bg-elevated)';
}}
>
<div className="flex items-center gap-3">
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
@ -429,11 +452,11 @@ export default function Dashboard() {
<AlertTriangle className="w-4 h-4" />}
</div>
<div>
<p className="text-sm font-medium text-gray-200 group-hover:text-primary transition-colors">
<p className="text-base font-medium text-foreground group-hover:text-primary transition-colors">
{task.project?.name || '未知项目'}
</p>
<p className="text-xs text-gray-500">
: <span className="text-white">{task.quality_score?.toFixed(1) || '0.0'}</span>
<p className="text-sm text-muted-foreground">
: <span className="text-foreground">{task.quality_score?.toFixed(1) || '0.0'}</span>
</p>
</div>
</div>
@ -494,7 +517,7 @@ export default function Dashboard() {
</div>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span>
<span className="text-base text-muted-foreground"></span>
<Badge className={`
${dbMode === 'api' ? 'cyber-badge-primary' :
dbMode === 'local' ? 'cyber-badge-info' :
@ -505,36 +528,36 @@ export default function Dashboard() {
</Badge>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span>
<span className="text-sm font-bold text-white">{stats?.active_projects || 0}</span>
<span className="text-base text-muted-foreground"></span>
<span className="text-base font-bold text-foreground">{stats?.active_projects || 0}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span>
<span className="text-sm font-bold text-sky-400">
<span className="text-base text-muted-foreground"></span>
<span className="text-base font-bold text-sky-400">
{recentTasks.filter(t => t.status === 'running').length}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span>
<span className="text-sm font-bold text-amber-400">
<span className="text-base text-muted-foreground"></span>
<span className="text-base font-bold text-amber-400">
{stats ? stats.total_issues - stats.resolved_issues : 0}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400 flex items-center gap-1">
<Shield className="w-3 h-3" />
<span className="text-base text-muted-foreground flex items-center gap-1">
<Shield className="w-4 h-4" />
</span>
<span className="text-sm font-bold text-violet-400">
<span className="text-base font-bold text-violet-400">
{ruleStats.enabled}/{ruleStats.total}
</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-400 flex items-center gap-1">
<MessageSquare className="w-3 h-3" />
<span className="text-base text-muted-foreground flex items-center gap-1">
<MessageSquare className="w-4 h-4" />
</span>
<span className="text-sm font-bold text-emerald-400">
<span className="text-base font-bold text-emerald-400">
{templateStats.active}/{templateStats.total}
</span>
</div>
@ -572,28 +595,28 @@ export default function Dashboard() {
<Link
key={task.id}
to={`/tasks/${task.id}`}
className={`block p-3 rounded-lg border transition-all hover:border-gray-700 ${
task.status === 'completed' ? 'bg-emerald-500/5 border-emerald-500/20' :
task.status === 'running' ? 'bg-sky-500/5 border-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/5 border-rose-500/20' :
'bg-gray-800/30 border-gray-800/50'
className={`block p-3 rounded-lg border transition-all ${
task.status === 'completed' ? 'bg-emerald-500/5 border-emerald-500/20 hover:border-emerald-500/40' :
task.status === 'running' ? 'bg-sky-500/5 border-sky-500/20 hover:border-sky-500/40' :
task.status === 'failed' ? 'bg-rose-500/5 border-rose-500/20 hover:border-rose-500/40' :
'bg-muted/30 border-border hover:border-border'
}`}
>
<p className="text-sm font-medium text-gray-200">{statusText}</p>
<p className="text-xs text-gray-500 mt-1 line-clamp-1">
<p className="text-base font-medium text-foreground">{statusText}</p>
<p className="text-sm text-muted-foreground mt-1 line-clamp-1">
"{task.project?.name || '未知项目'}"
{task.status === 'completed' && task.issues_count > 0 &&
` - 发现 ${task.issues_count} 个问题`
}
</p>
<p className="text-[10px] text-gray-600 mt-1">{timeAgo}</p>
<p className="text-sm text-muted-foreground/70 mt-1">{timeAgo}</p>
</Link>
);
})
) : (
<div className="empty-state py-6">
<Clock className="w-8 h-8 text-gray-600 mb-2" />
<p className="text-sm text-gray-500"></p>
<Clock className="w-10 h-10 text-muted-foreground mb-2" />
<p className="text-base text-muted-foreground"></p>
</div>
)}
</div>

View File

@ -346,8 +346,8 @@ public class Example {
// Render issue with cyberpunk style
const renderIssue = (issue: any, index: number) => (
<div key={index} className="cyber-card p-4 mb-4 hover:border-gray-700 transition-all group">
<div className="flex items-start justify-between mb-3 pb-3 border-b border-gray-800">
<div key={index} className="cyber-card p-4 mb-4 hover:border-border transition-all group">
<div className="flex items-start justify-between mb-3 pb-3 border-b border-border">
<div className="flex items-start space-x-3">
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${
issue.severity === 'critical' ? 'bg-rose-500/20 text-rose-400' :
@ -358,15 +358,15 @@ public class Example {
{getTypeIcon(issue.type)}
</div>
<div className="flex-1">
<h4 className="font-bold text-base text-gray-200 mb-1 group-hover:text-primary transition-colors uppercase">{issue.title}</h4>
<div className="flex items-center space-x-1 text-xs text-gray-500 font-mono">
<h4 className="font-bold text-base text-foreground mb-1 group-hover:text-primary transition-colors uppercase">{issue.title}</h4>
<div className="flex items-center space-x-1 text-xs text-muted-foreground font-mono">
<span className="text-primary">&gt;</span>
<span>LINE: {issue.line}</span>
{issue.column && <span>, COL: {issue.column}</span>}
</div>
</div>
</div>
<Badge className={`${getSeverityClasses(issue.severity)} font-bold uppercase px-2 py-1 rounded text-[10px]`}>
<Badge className={`${getSeverityClasses(issue.severity)} font-bold uppercase px-2 py-1 rounded text-xs`}>
{issue.severity === 'critical' ? '严重' :
issue.severity === 'high' ? '高' :
issue.severity === 'medium' ? '中等' : '低'}
@ -374,27 +374,27 @@ public class Example {
</div>
{issue.description && (
<div className="bg-gray-900/50 border border-gray-800 p-3 mb-3 rounded font-mono">
<div className="flex items-center mb-1 border-b border-gray-800 pb-1">
<Info className="w-3 h-3 text-gray-500 mr-1" />
<span className="font-bold text-gray-400 text-xs uppercase"></span>
<div className="bg-muted border border-border p-3 mb-3 rounded font-mono">
<div className="flex items-center mb-1 border-b border-border pb-1">
<Info className="w-3 h-3 text-muted-foreground mr-1" />
<span className="font-bold text-muted-foreground text-xs uppercase"></span>
</div>
<p className="text-gray-300 text-xs leading-relaxed mt-1">{issue.description}</p>
<p className="text-foreground text-xs leading-relaxed mt-1">{issue.description}</p>
</div>
)}
{issue.code_snippet && (
<div className="bg-[#0a0a0f] p-3 mb-3 border border-gray-800 rounded">
<div className="flex items-center justify-between mb-2 border-b border-gray-800 pb-1">
<div className="cyber-bg-elevated p-3 mb-3 border border-border rounded">
<div className="flex items-center justify-between mb-2 border-b border-border pb-1">
<div className="flex items-center space-x-1">
<div className="w-4 h-4 bg-primary rounded flex items-center justify-center">
<Code className="w-2 h-2 text-white" />
<Code className="w-2 h-2 text-foreground" />
</div>
<span className="text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
</div>
<span className="text-gray-500 text-xs font-mono">LINE: {issue.line}</span>
<span className="text-muted-foreground text-xs font-mono">LINE: {issue.line}</span>
</div>
<div className="bg-black/40 p-2 border border-gray-800 rounded">
<div className="bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
<code>{issue.code_snippet}</code>
</pre>
@ -431,19 +431,19 @@ public class Example {
{parsedExplanation.what && (
<div className="border-l-2 border-rose-500 pl-2">
<span className="font-bold text-rose-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.what}</span>
<span className="text-foreground ml-1">{parsedExplanation.what}</span>
</div>
)}
{parsedExplanation.why && (
<div className="border-l-2 border-amber-500 pl-2">
<span className="font-bold text-amber-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.why}</span>
<span className="text-foreground ml-1">{parsedExplanation.why}</span>
</div>
)}
{parsedExplanation.how && (
<div className="border-l-2 border-emerald-500 pl-2">
<span className="font-bold text-emerald-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.how}</span>
<span className="text-foreground ml-1">{parsedExplanation.how}</span>
</div>
)}
{parsedExplanation.learn_more && (
@ -469,7 +469,7 @@ public class Example {
<Zap className="w-4 h-4 text-violet-400 mr-2" />
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
</div>
<p className="text-gray-300 text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
<p className="text-foreground text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
</div>
);
}
@ -479,7 +479,7 @@ public class Example {
);
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -488,7 +488,7 @@ public class Example {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<History className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto flex items-center gap-2">
{historyRecords.length > 0 && (
<Button
@ -514,7 +514,7 @@ public class Example {
{loadingHistory ? (
<div className="text-center py-8">
<div className="loading-spinner mx-auto mb-4"></div>
<p className="text-gray-500 font-mono">...</p>
<p className="text-muted-foreground font-mono">...</p>
</div>
) : historyRecords.length === 0 ? (
<div className="empty-state">
@ -531,14 +531,14 @@ public class Example {
className={`p-4 rounded-lg border transition-colors cursor-pointer ${
selectedHistoryId === record.id
? 'bg-primary/10 border-primary/30'
: 'bg-gray-900/30 border-gray-800 hover:bg-gray-800/50 hover:border-gray-700'
: 'bg-muted/50 border-border hover:bg-muted hover:border-border'
}`}
onClick={() => viewHistoryRecord(record)}
>
<div className="flex items-center justify-between mb-2">
<div className="flex items-center gap-2">
<Badge className="cyber-badge-muted">{record.language}</Badge>
<span className="text-sm font-mono text-gray-500">{formatDate(record.created_at)}</span>
<span className="text-sm font-mono text-muted-foreground">{formatDate(record.created_at)}</span>
</div>
<div className="flex items-center gap-2">
<Badge className={`font-mono ${
@ -556,10 +556,10 @@ public class Example {
>
<X className="w-3 h-3" />
</Button>
<ChevronRight className="w-4 h-4 text-gray-500" />
<ChevronRight className="w-4 h-4 text-muted-foreground" />
</div>
</div>
<div className="flex items-center gap-4 text-xs font-mono text-gray-500">
<div className="flex items-center gap-4 text-xs font-mono text-muted-foreground">
<span className="flex items-center gap-1">
<AlertTriangle className="w-3 h-3" />
{record.issues_count}
@ -582,7 +582,7 @@ public class Example {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto flex items-center gap-2">
<Button
variant="outline"
@ -606,12 +606,12 @@ public class Example {
{/* Toolbar */}
<div className="flex flex-col sm:flex-row gap-3">
<div className="flex-1 space-y-1">
<label className="text-xs font-bold text-gray-500 uppercase"></label>
<label className="text-xs font-bold text-muted-foreground uppercase"></label>
<Select value={language} onValueChange={setLanguage}>
<SelectTrigger className="cyber-input h-10">
<SelectValue placeholder="选择编程语言" />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{supportedLanguages.map((lang) => (
<SelectItem key={lang} value={lang}>
{lang.charAt(0).toUpperCase() + lang.slice(1)}
@ -621,7 +621,7 @@ public class Example {
</Select>
</div>
<div className="flex-1 space-y-1">
<label className="text-xs font-bold text-gray-500 uppercase"></label>
<label className="text-xs font-bold text-muted-foreground uppercase"></label>
<Select value={selectedPromptTemplateId} onValueChange={setSelectedPromptTemplateId}>
<SelectTrigger className="cyber-input h-10">
<div className="flex items-center gap-2">
@ -629,7 +629,7 @@ public class Example {
<SelectValue placeholder="选择提示词模板" />
</div>
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{promptTemplates.map((pt) => (
<SelectItem key={pt.id} value={pt.id}>
{pt.name} {pt.is_default && '(默认)'}
@ -659,8 +659,8 @@ public class Example {
</div>
{/* Quick Examples */}
<div className="flex flex-wrap gap-2 items-center p-3 bg-gray-900/50 border border-gray-800 rounded">
<span className="text-xs font-bold uppercase text-gray-500 mr-2"></span>
<div className="flex flex-wrap gap-2 items-center p-3 bg-muted border border-border rounded">
<span className="text-xs font-bold uppercase text-muted-foreground mr-2"></span>
{['javascript', 'python', 'java'].map((lang) => (
<Button
key={lang}
@ -677,17 +677,17 @@ public class Example {
{/* Code Editor */}
<div className="relative">
<div className="absolute top-0 right-0 bg-gray-800 text-gray-400 px-2 py-1 text-[10px] font-mono uppercase z-10 rounded-bl border-l border-b border-gray-700">
<div className="absolute top-0 right-0 bg-muted text-muted-foreground px-2 py-1 text-xs font-mono uppercase z-10 rounded-bl border-l border-b border-border">
Editor
</div>
<Textarea
placeholder="// 粘贴代码或上传文件..."
value={code}
onChange={(e) => setCode(e.target.value)}
className="min-h-[300px] font-mono text-sm bg-[#0a0a0f] text-emerald-400 border border-gray-800 p-4 focus:ring-0 focus:border-primary/50 placeholder:text-gray-600"
className="min-h-[300px] font-mono text-sm cyber-bg-elevated text-emerald-400 border border-border p-4 focus:ring-0 focus:border-primary/50 placeholder:text-muted-foreground"
disabled={analyzing}
/>
<div className="text-xs text-gray-600 mt-1 font-mono text-right">
<div className="text-xs text-muted-foreground mt-1 font-mono text-right">
{code.length} {code.split('\n').length}
</div>
</div>
@ -720,7 +720,7 @@ public class Example {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<CheckCircle className="w-5 h-5 text-emerald-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto flex items-center gap-2">
<Badge className="cyber-badge-muted">
<Clock className="w-3 h-3 mr-1" />
@ -748,7 +748,7 @@ public class Example {
{(result.quality_score ?? 0).toFixed(1)}
</div>
<p className="stat-label mb-2"></p>
<Progress value={result.quality_score ?? 0} className="h-2 bg-gray-800 [&>div]:bg-primary" />
<Progress value={result.quality_score ?? 0} className="h-2 bg-muted [&>div]:bg-primary" />
</div>
<div className="cyber-card p-4 text-center">
@ -786,7 +786,7 @@ public class Example {
</div>
{/* Detailed Metrics */}
<div className="bg-gray-900/50 border border-gray-800 p-4 rounded-lg">
<div className="bg-muted border border-border p-4 rounded-lg">
<h3 className="section-title text-sm mb-4 flex items-center gap-2">
<TrendingUp className="w-4 h-4" />
@ -799,9 +799,9 @@ public class Example {
{ label: '性能', value: result.metrics?.performance ?? 0 },
].map((metric) => (
<div key={metric.label} className="text-center">
<div className="text-xl font-bold text-white mb-1">{metric.value}</div>
<p className="text-xs text-gray-500 uppercase mb-2">{metric.label}</p>
<Progress value={metric.value} className="h-2 bg-gray-800 [&>div]:bg-primary" />
<div className="text-xl font-bold text-foreground mb-1">{metric.value}</div>
<p className="text-xs text-muted-foreground uppercase mb-2">{metric.label}</p>
<Progress value={metric.value} className="h-2 bg-muted [&>div]:bg-primary" />
</div>
))}
</div>
@ -813,22 +813,22 @@ public class Example {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Shield className="w-5 h-5 text-amber-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"> ({result.issues.length})</h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"> ({result.issues.length})</h3>
</div>
<div className="p-6">
{result.issues.length > 0 ? (
<Tabs defaultValue="all" className="w-full">
<TabsList className="grid w-full grid-cols-4 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded mb-6">
<TabsTrigger value="all" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsList className="grid w-full grid-cols-4 bg-muted border border-border p-1 h-auto gap-1 rounded mb-6">
<TabsTrigger value="all" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({result.issues.length})
</TabsTrigger>
<TabsTrigger value="critical" className="data-[state=active]:bg-rose-500 data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="critical" className="data-[state=active]:bg-rose-500 data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({result.issues.filter(i => i.severity === 'critical').length})
</TabsTrigger>
<TabsTrigger value="high" className="data-[state=active]:bg-orange-500 data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="high" className="data-[state=active]:bg-orange-500 data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({result.issues.filter(i => i.severity === 'high').length})
</TabsTrigger>
<TabsTrigger value="medium" className="data-[state=active]:bg-amber-500 data-[state=active]:text-black font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="medium" className="data-[state=active]:bg-amber-500 data-[state=active]:text-background font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({result.issues.filter(i => i.severity === 'medium').length})
</TabsTrigger>
</TabsList>
@ -844,10 +844,10 @@ public class Example {
) : (
<div className="cyber-card p-12 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 uppercase mb-2">
<h3 className="text-lg font-bold text-foreground uppercase mb-2">
{severity === 'critical' ? '严重' : severity === 'high' ? '高优先级' : '中等优先级'}
</h3>
<p className="text-gray-500 font-mono"></p>
<p className="text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -877,9 +877,9 @@ public class Example {
<div className="w-20 h-20 bg-primary/20 border border-primary/40 rounded-lg flex items-center justify-center mx-auto mb-6">
<div className="loading-spinner w-12 h-12"></div>
</div>
<h3 className="text-2xl font-bold text-white uppercase mb-3">AI正在分析您的代码</h3>
<p className="text-gray-400 mb-6 font-mono">30...</p>
<p className="text-gray-500 text-sm mb-6 font-mono">使</p>
<h3 className="text-2xl font-bold text-foreground uppercase mb-3">AI正在分析您的代码</h3>
<p className="text-muted-foreground mb-6 font-mono">30...</p>
<p className="text-muted-foreground text-sm mb-6 font-mono">使</p>
<div className="bg-primary/10 border border-primary/30 p-4 max-w-md mx-auto rounded">
<p className="text-primary text-sm font-mono">
<br />

View File

@ -78,7 +78,7 @@ export default function Login() {
};
return (
<div className="min-h-screen flex items-center justify-center bg-[#0a0a0f] relative overflow-hidden">
<div className="min-h-screen flex items-center justify-center cyber-bg-elevated relative overflow-hidden">
{/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20">
<div
@ -110,32 +110,32 @@ export default function Login() {
/>
{/* Corner Decorations */}
<div className="absolute top-4 left-4 text-[10px] font-mono text-gray-700 z-30 space-y-1">
<div className="absolute top-4 left-4 text-sm font-mono text-muted-foreground z-30 space-y-1">
<div className="flex items-center gap-2">
<Terminal className="w-3 h-3" />
<Terminal className="w-4 h-4" />
<span>SYS_ID: 0x84F2</span>
</div>
<div className="flex items-center gap-2">
<Shield className="w-3 h-3" />
<Shield className="w-4 h-4" />
<span>ENCRYPT: AES-256</span>
</div>
<div className="flex items-center gap-2">
<Fingerprint className="w-3 h-3" />
<Fingerprint className="w-4 h-4" />
<span>AUTH: READY</span>
</div>
</div>
<div className="absolute top-4 right-4 text-[10px] font-mono text-gray-700 text-right z-30 space-y-1">
<div className="absolute top-4 right-4 text-sm font-mono text-muted-foreground text-right z-30 space-y-1">
<div>SECURE_CONN: TRUE</div>
<div>PORT: 443</div>
<div>TLS: 1.3</div>
</div>
<div className="absolute bottom-4 left-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 left-4 text-sm font-mono text-muted-foreground z-30">
DEEPAUDIT_AUTH_v3
</div>
<div className="absolute bottom-4 right-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 right-4 text-sm font-mono text-muted-foreground z-30">
{new Date().toISOString().split("T")[0]}
</div>
@ -143,7 +143,7 @@ export default function Login() {
<div className="w-full max-w-md relative z-30 px-4">
{/* Logo & Title */}
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center p-3 bg-[#0c0c12] border border-gray-800/60 rounded-lg mb-6"
<div className="inline-flex items-center justify-center p-3 cyber-dialog border border-border/60 rounded-lg mb-6"
style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}>
<img
src="/logo_deepaudit.png"
@ -156,24 +156,24 @@ export default function Login() {
style={{ textShadow: "0 0 30px rgba(255,107,44,0.5), 0 0 60px rgba(255,107,44,0.3)" }}
>
<span className="text-primary">DEEP</span>
<span className="text-white">AUDIT</span>
<span className="text-foreground">AUDIT</span>
</div>
<p className="text-sm font-mono text-gray-500">
<p className="text-base font-mono text-muted-foreground">
// Autonomous Security Agent
</p>
</div>
{/* Login Form Card */}
<div className="bg-[#0c0c12] border border-gray-800/60 rounded-lg overflow-hidden"
<div className="cyber-dialog border border-border/60 rounded-lg overflow-hidden"
style={{ boxShadow: '0 4px 30px rgba(0,0,0,0.5)' }}>
{/* Card Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#0a0a0f] border-b border-gray-800/50">
<div className="flex items-center gap-2 px-4 py-3 cyber-bg-elevated border-b border-border">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-gray-500 tracking-wider">
<span className="ml-2 font-mono text-sm text-muted-foreground tracking-wider">
authentication@deepaudit
</span>
</div>
@ -183,7 +183,7 @@ export default function Login() {
<div className="space-y-2">
<Label
htmlFor="email"
className="font-mono text-xs text-gray-400 uppercase tracking-wider"
className="font-mono text-sm text-muted-foreground uppercase tracking-wider"
>
</Label>
@ -195,16 +195,16 @@ export default function Login() {
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="h-12 pl-11 font-mono bg-[#0a0a0f] border-gray-700/50 text-gray-200 placeholder:text-gray-600 focus:border-primary/50 focus:ring-0"
className="h-12 pl-11 font-mono cyber-bg-elevated border-border/50 text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:ring-0"
/>
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="password"
className="font-mono text-xs text-gray-400 uppercase tracking-wider"
className="font-mono text-sm text-muted-foreground uppercase tracking-wider"
>
</Label>
@ -216,9 +216,9 @@ export default function Login() {
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="h-12 pl-11 font-mono bg-[#0a0a0f] border-gray-700/50 text-gray-200 placeholder:text-gray-600 focus:border-primary/50 focus:ring-0"
className="h-12 pl-11 font-mono cyber-bg-elevated border-border/50 text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:ring-0"
/>
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
</div>
</div>
@ -230,11 +230,11 @@ export default function Login() {
onCheckedChange={(checked) =>
setRememberMe(checked as boolean)
}
className="border-gray-600 data-[state=checked]:bg-primary data-[state=checked]:border-primary"
className="border-border data-[state=checked]:bg-primary data-[state=checked]:border-primary"
/>
<Label
htmlFor="remember"
className="text-sm font-mono text-gray-500 cursor-pointer"
className="text-base font-mono text-muted-foreground cursor-pointer"
>
</Label>
@ -243,7 +243,7 @@ export default function Login() {
<Button
type="submit"
className="w-full h-12 text-base font-bold uppercase tracking-wider bg-primary hover:bg-primary/90 text-white border border-primary/50 transition-all"
className="w-full h-12 text-base font-bold uppercase tracking-wider bg-primary hover:bg-primary/90 text-foreground border border-primary/50 transition-all"
style={{ boxShadow: '0 0 20px rgba(255,107,44,0.3)' }}
disabled={loading}
>
@ -259,8 +259,8 @@ export default function Login() {
</form>
{/* Footer */}
<div className="mt-6 pt-5 border-t border-gray-800/50 text-center">
<p className="text-sm font-mono text-gray-500">
<div className="mt-6 pt-5 border-t border-border text-center">
<p className="text-base font-mono text-muted-foreground">
{" "}
<span
className="text-primary font-bold cursor-pointer hover:underline"
@ -275,7 +275,7 @@ export default function Login() {
{/* Version Info */}
<div className="mt-6 text-center">
<p className="font-mono text-[10px] text-gray-600 uppercase">
<p className="font-mono text-sm text-muted-foreground uppercase">
Version {version} · Secure Connection
</p>
</div>

View File

@ -12,7 +12,7 @@ export default function NotFound() {
return (
<>
<PageMeta title="页面未找到" description="" />
<div className="relative flex flex-col items-center justify-center min-h-screen p-6 bg-[#0a0a0f] font-mono overflow-hidden">
<div className="relative flex flex-col items-center justify-center min-h-screen p-6 cyber-bg-elevated font-mono overflow-hidden">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -43,26 +43,26 @@ export default function NotFound() {
<div className="cyber-card p-0 mb-8">
<div className="cyber-card-header">
<Terminal className="w-4 h-4 text-primary" />
<span className="text-sm font-bold uppercase tracking-wider text-gray-300">ERROR_LOG</span>
<span className="text-sm font-bold uppercase tracking-wider text-foreground">ERROR_LOG</span>
</div>
<div className="p-4 text-left">
<div className="text-emerald-400 text-sm">
<span className="text-gray-500">[{new Date().toISOString()}]</span>
<span className="text-muted-foreground">[{new Date().toISOString()}]</span>
</div>
<div className="text-rose-400 text-sm mt-1">
<span className="text-gray-500">ERROR:</span> PAGE_NOT_FOUND
<span className="text-muted-foreground">ERROR:</span> PAGE_NOT_FOUND
</div>
<div className="text-amber-400 text-sm mt-1">
<span className="text-gray-500">STATUS:</span> 404
<span className="text-muted-foreground">STATUS:</span> 404
</div>
<div className="text-gray-400 text-sm mt-1">
<span className="text-gray-500">MESSAGE:</span>
<div className="text-muted-foreground text-sm mt-1">
<span className="text-muted-foreground">MESSAGE:</span>
</div>
</div>
</div>
{/* Description */}
<p className="text-gray-400 mb-8 text-sm">
<p className="text-muted-foreground mb-8 text-sm">
</p>
@ -76,7 +76,7 @@ export default function NotFound() {
</div>
{/* Footer */}
<p className="absolute bottom-6 left-1/2 -translate-x-1/2 text-xs text-gray-600 font-mono uppercase">
<p className="absolute bottom-6 left-1/2 -translate-x-1/2 text-xs text-muted-foreground font-mono uppercase">
&copy; {new Date().getFullYear()} DeepAudit
</p>
</div>

View File

@ -280,7 +280,7 @@ export default function ProjectDetail() {
case 'completed': return <CheckCircle className="w-4 h-4 text-emerald-400" />;
case 'running': return <Activity className="w-4 h-4 text-sky-400" />;
case 'failed': return <AlertTriangle className="w-4 h-4 text-rose-400" />;
default: return <Clock className="w-4 h-4 text-gray-400" />;
default: return <Clock className="w-4 h-4 text-muted-foreground" />;
}
};
@ -316,7 +316,7 @@ export default function ProjectDetail() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
@ -327,8 +327,8 @@ export default function ProjectDetail() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="cyber-card p-8 text-center">
<AlertTriangle className="w-16 h-16 text-rose-400 mx-auto mb-4" />
<h2 className="text-2xl font-bold text-white mb-2 uppercase"></h2>
<p className="text-gray-400 mb-4 font-mono">ID是否正确</p>
<h2 className="text-2xl font-bold text-foreground mb-2 uppercase"></h2>
<p className="text-muted-foreground mb-4 font-mono">ID是否正确</p>
<Link to="/projects">
<Button className="cyber-btn-primary">
<ArrowLeft className="w-4 h-4 mr-2" />
@ -341,7 +341,7 @@ export default function ProjectDetail() {
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -354,7 +354,7 @@ export default function ProjectDetail() {
</Button>
</Link>
<div className="flex items-center gap-3">
<h1 className="text-2xl font-bold text-white uppercase tracking-wider">{project.name}</h1>
<h1 className="text-2xl font-bold text-foreground uppercase tracking-wider">{project.name}</h1>
<Badge className={`${project.is_active ? 'cyber-badge-success' : 'cyber-badge-muted'}`}>
{project.is_active ? '活跃' : '暂停'}
</Badge>
@ -431,11 +431,11 @@ export default function ProjectDetail() {
{/* 主要内容 */}
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full relative z-10">
<TabsList className="grid w-full grid-cols-4 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded">
<TabsTrigger value="overview" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="tasks" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="issues" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="settings" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"></TabsTrigger>
<TabsList className="grid w-full grid-cols-4 bg-muted border border-border p-1 h-auto gap-1 rounded">
<TabsTrigger value="overview" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="tasks" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="issues" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"></TabsTrigger>
<TabsTrigger value="settings" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"></TabsTrigger>
</TabsList>
<TabsContent value="overview" className="flex flex-col gap-6 mt-6">
@ -450,7 +450,7 @@ export default function ProjectDetail() {
<div className="space-y-3">
{project.repository_url && (
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm text-muted-foreground uppercase"></span>
<a
href={project.repository_url}
target="_blank"
@ -464,7 +464,7 @@ export default function ProjectDetail() {
)}
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm text-muted-foreground uppercase"></span>
<Badge className={`${isRepositoryProject(project) ? 'cyber-badge-info' : 'cyber-badge-warning'}`}>
{getSourceTypeLabel(project.source_type)}
</Badge>
@ -473,7 +473,7 @@ export default function ProjectDetail() {
{isRepositoryProject(project) && (
<>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm text-muted-foreground uppercase"></span>
<Badge className="cyber-badge-muted">
{project.repository_type === 'github' ? 'GitHub' :
project.repository_type === 'gitlab' ? 'GitLab' : '其他'}
@ -481,26 +481,26 @@ export default function ProjectDetail() {
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm font-bold text-gray-200 bg-gray-800 px-2 py-0.5 rounded border border-gray-700">{project.default_branch}</span>
<span className="text-sm text-muted-foreground uppercase"></span>
<span className="text-sm font-bold text-foreground bg-muted px-2 py-0.5 rounded border border-border">{project.default_branch}</span>
</div>
</>
)}
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm text-gray-300">{formatDate(project.created_at)}</span>
<span className="text-sm text-muted-foreground uppercase"></span>
<span className="text-sm text-foreground">{formatDate(project.created_at)}</span>
</div>
<div className="flex items-center justify-between">
<span className="text-sm text-gray-500 uppercase"></span>
<span className="text-sm text-gray-300">{project.owner?.full_name || project.owner?.phone || '未知'}</span>
<span className="text-sm text-muted-foreground uppercase"></span>
<span className="text-sm text-foreground">{project.owner?.full_name || project.owner?.phone || '未知'}</span>
</div>
</div>
{project.programming_languages && (
<div className="pt-4 border-t border-gray-800">
<h4 className="text-sm font-bold mb-2 uppercase text-gray-500"></h4>
<div className="pt-4 border-t border-border">
<h4 className="text-sm font-bold mb-2 uppercase text-muted-foreground"></h4>
<div className="flex flex-wrap gap-2">
{JSON.parse(project.programming_languages).map((lang: string) => (
<Badge key={lang} className="cyber-badge-primary">
@ -526,22 +526,22 @@ export default function ProjectDetail() {
<Link
key={task.id}
to={`/tasks/${task.id}`}
className="flex items-center justify-between p-3 bg-gray-900/30 rounded-lg hover:bg-gray-800/50 transition-all group"
className="flex items-center justify-between p-3 bg-muted/50 rounded-lg hover:bg-muted transition-all group"
>
<div className="flex items-center space-x-3">
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
task.status === 'completed' ? 'bg-emerald-500/20' :
task.status === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/20' :
'bg-gray-800/50'
'bg-muted'
}`}>
{getStatusIcon(task.status)}
</div>
<div>
<p className="text-sm font-bold text-gray-200 group-hover:text-primary transition-colors uppercase">
<p className="text-sm font-bold text-foreground group-hover:text-primary transition-colors uppercase">
{task.task_type === 'repository' ? '仓库审计' : '即时分析'}
</p>
<p className="text-xs text-gray-500 font-mono">
<p className="text-xs text-muted-foreground font-mono">
{formatDate(task.created_at)}
</p>
</div>
@ -577,21 +577,21 @@ export default function ProjectDetail() {
<div className="space-y-4">
{tasks.map((task) => (
<div key={task.id} className="cyber-card p-6">
<div className="flex items-center justify-between mb-4 pb-4 border-b border-gray-800">
<div className="flex items-center justify-between mb-4 pb-4 border-b border-border">
<div className="flex items-center space-x-3">
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${
task.status === 'completed' ? 'bg-emerald-500/20' :
task.status === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/20' :
'bg-gray-800/50'
'bg-muted'
}`}>
{getStatusIcon(task.status)}
</div>
<div>
<h4 className="font-bold text-gray-200 uppercase">
<h4 className="font-bold text-foreground uppercase">
{task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'}
</h4>
<p className="text-sm text-gray-500 font-mono">
<p className="text-sm text-muted-foreground font-mono">
{formatDate(task.created_at)}
</p>
</div>
@ -600,35 +600,35 @@ export default function ProjectDetail() {
</div>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4 font-mono">
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.total_files}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.total_files}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<p className="text-2xl font-bold text-white">{task.total_lines}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-foreground">{task.total_lines}</p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-amber-400">{task.issues_count}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
<div className="text-center p-3 bg-gray-900/50 rounded-lg border border-gray-800">
<div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-primary">{task.quality_score.toFixed(1)}</p>
<p className="text-xs text-gray-500 uppercase"></p>
<p className="text-xs text-muted-foreground uppercase"></p>
</div>
</div>
{task.status === 'completed' && (
<div className="space-y-2 mb-4">
<div className="flex items-center justify-between text-sm font-mono">
<span className="text-gray-400"></span>
<span className="text-white font-bold">{task.quality_score.toFixed(1)}/100</span>
<span className="text-muted-foreground"></span>
<span className="text-foreground font-bold">{task.quality_score.toFixed(1)}/100</span>
</div>
<Progress value={task.quality_score} className="h-2 bg-gray-800 [&>div]:bg-primary" />
<Progress value={task.quality_score} className="h-2 bg-muted [&>div]:bg-primary" />
</div>
)}
<div className="flex justify-end space-x-2 pt-4 border-t border-gray-800">
<div className="flex justify-end space-x-2 pt-4 border-t border-border">
<Link to={`/tasks/${task.id}`}>
<Button variant="outline" size="sm" className="cyber-btn-outline">
<FileText className="w-4 h-4 mr-2" />
@ -641,9 +641,9 @@ export default function ProjectDetail() {
</div>
) : (
<div className="cyber-card p-12 text-center">
<Activity className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 mb-2 uppercase"></h3>
<p className="text-sm text-gray-500 mb-6 font-mono"></p>
<Activity className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-lg font-bold text-foreground mb-2 uppercase"></h3>
<p className="text-sm text-muted-foreground mb-6 font-mono"></p>
<Button onClick={handleCreateTask} className="cyber-btn-primary">
<Play className="w-4 h-4 mr-2" />
@ -659,7 +659,7 @@ export default function ProjectDetail() {
<h3 className="section-title"></h3>
</div>
{tasks.length > 0 && (
<p className="text-sm text-gray-500 font-mono">
<p className="text-sm text-muted-foreground font-mono">
({formatDate(tasks[0].created_at)})
</p>
)}
@ -668,12 +668,12 @@ export default function ProjectDetail() {
{loadingIssues ? (
<div className="text-center py-12">
<div className="loading-spinner mx-auto mb-4"></div>
<p className="text-gray-500 font-mono">...</p>
<p className="text-muted-foreground font-mono">...</p>
</div>
) : latestIssues.length > 0 ? (
<div className="space-y-4">
{latestIssues.map((issue, index) => (
<div key={index} className="cyber-card p-4 hover:border-gray-700 transition-all">
<div key={index} className="cyber-card p-4 hover:border-border transition-all">
<div className="flex items-start justify-between">
<div className="flex items-start space-x-3">
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
@ -685,9 +685,9 @@ export default function ProjectDetail() {
<AlertTriangle className="w-4 h-4" />
</div>
<div>
<h4 className="font-bold text-base text-gray-200 mb-1 uppercase">{issue.title}</h4>
<div className="flex items-center space-x-2 text-xs text-gray-500 font-mono">
<span className="bg-gray-800 px-2 py-0.5 rounded border border-gray-700">{issue.file_path}:{issue.line_number}</span>
<h4 className="font-bold text-base text-foreground mb-1 uppercase">{issue.title}</h4>
<div className="flex items-center space-x-2 text-xs text-muted-foreground font-mono">
<span className="bg-muted px-2 py-0.5 rounded border border-border">{issue.file_path}:{issue.line_number}</span>
<span>{issue.category}</span>
</div>
</div>
@ -697,14 +697,14 @@ export default function ProjectDetail() {
issue.severity === 'high' ? 'severity-high' :
issue.severity === 'medium' ? 'severity-medium' :
'severity-low'}
font-bold uppercase px-2 py-1 rounded text-[10px]
font-bold uppercase px-2 py-1 rounded text-xs
`}>
{issue.severity === 'critical' ? '严重' :
issue.severity === 'high' ? '高' :
issue.severity === 'medium' ? '中等' : '低'}
</Badge>
</div>
<p className="mt-3 text-sm text-gray-400 font-mono border-t border-gray-800 pt-3">
<p className="mt-3 text-sm text-muted-foreground font-mono border-t border-border pt-3">
{issue.description}
</p>
</div>
@ -713,8 +713,8 @@ export default function ProjectDetail() {
) : (
<div className="cyber-card p-12 text-center">
<CheckCircle className="w-16 h-16 text-emerald-500 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 mb-2 uppercase"></h3>
<p className="text-sm text-gray-500 font-mono"></p>
<h3 className="text-lg font-bold text-foreground mb-2 uppercase"></h3>
<p className="text-sm text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -730,7 +730,7 @@ export default function ProjectDetail() {
{/* 基本信息 */}
<div className="space-y-4">
<div>
<Label htmlFor="edit-name" className="font-mono font-bold uppercase text-xs text-gray-400"> *</Label>
<Label htmlFor="edit-name" className="font-mono font-bold uppercase text-xs text-muted-foreground"> *</Label>
<Input
id="edit-name"
value={editForm.name}
@ -741,7 +741,7 @@ export default function ProjectDetail() {
</div>
<div>
<Label htmlFor="edit-description" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-description" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Textarea
id="edit-description"
value={editForm.description}
@ -755,14 +755,14 @@ export default function ProjectDetail() {
{/* 仓库信息 - 仅远程仓库类型显示 */}
{editForm.source_type === 'repository' && (
<div className="space-y-4 border-t border-gray-800 pt-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400 flex items-center gap-2">
<div className="space-y-4 border-t border-border pt-4">
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground flex items-center gap-2">
<GitBranch className="w-4 h-4" />
</h3>
<div>
<Label htmlFor="edit-repo-url" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-repo-url" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="edit-repo-url"
value={editForm.repository_url}
@ -774,7 +774,7 @@ export default function ProjectDetail() {
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<Label htmlFor="edit-repo-type" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-repo-type" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Select
value={editForm.repository_type}
onValueChange={(value: any) => setEditForm({ ...editForm, repository_type: value })}
@ -782,7 +782,7 @@ export default function ProjectDetail() {
<SelectTrigger id="edit-repo-type" className="cyber-input mt-1">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="github">GitHub</SelectItem>
<SelectItem value="gitlab">GitLab</SelectItem>
<SelectItem value="other"></SelectItem>
@ -791,7 +791,7 @@ export default function ProjectDetail() {
</div>
<div>
<Label htmlFor="edit-branch" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-branch" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="edit-branch"
value={editForm.default_branch}
@ -806,7 +806,7 @@ export default function ProjectDetail() {
{/* ZIP项目提示 */}
{editForm.source_type === 'zip' && (
<div className="border-t border-gray-800 pt-4">
<div className="border-t border-border pt-4">
<div className="bg-amber-500/10 border border-amber-500/30 p-4 rounded">
<div className="flex items-start space-x-3">
<Upload className="w-5 h-5 text-amber-400 mt-0.5" />
@ -822,26 +822,26 @@ export default function ProjectDetail() {
)}
{/* 编程语言 */}
<div className="space-y-4 border-t border-gray-800 pt-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400"></h3>
<div className="space-y-4 border-t border-border pt-4">
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground"></h3>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
{supportedLanguages.map((lang) => (
<div
key={lang}
className={`flex items-center space-x-2 p-3 border cursor-pointer transition-all rounded ${editForm.programming_languages?.includes(lang)
? 'border-primary bg-primary/10 text-primary'
: 'border-gray-700 hover:border-gray-600 text-gray-400'
: 'border-border hover:border-border text-muted-foreground'
}`}
onClick={() => handleToggleLanguage(lang)}
>
<div
className={`w-4 h-4 border-2 rounded-sm flex items-center justify-center ${editForm.programming_languages?.includes(lang)
? 'bg-primary border-primary'
: 'border-gray-600'
: 'border-border'
}`}
>
{editForm.programming_languages?.includes(lang) && (
<CheckCircle className="w-3 h-3 text-white" />
<CheckCircle className="w-3 h-3 text-foreground" />
)}
</div>
<span className="text-sm font-bold font-mono">{lang}</span>
@ -850,7 +850,7 @@ export default function ProjectDetail() {
</div>
</div>
<div className="flex justify-end space-x-3 pt-6 border-t border-gray-800">
<div className="flex justify-end space-x-3 pt-6 border-t border-border">
<Button onClick={handleSaveSettings} className="cyber-btn-primary">
<Edit className="w-4 h-4 mr-2" />
@ -880,21 +880,21 @@ export default function ProjectDetail() {
{/* 审计选项对话框 */}
<Dialog open={showAuditOptionsDialog} onOpenChange={setShowAuditOptionsDialog}>
<DialogContent className="max-w-md cyber-card border-gray-700 bg-[#0c0c12] p-0">
<DialogContent className="max-w-md cyber-card border-border cyber-dialog p-0">
{/* Terminal Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#0a0a0f] border-b border-gray-800/50">
<div className="flex items-center gap-2 px-4 py-3 cyber-bg-elevated border-b border-border">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-gray-500 tracking-wider">
<span className="ml-2 font-mono text-xs text-muted-foreground tracking-wider">
audit_options@deepaudit
</span>
</div>
<DialogHeader className="px-6 pt-4">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-white">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-foreground">
<Shield className="w-5 h-5 text-primary" />
</DialogTitle>
@ -903,28 +903,28 @@ export default function ProjectDetail() {
<div className="p-6 space-y-4">
<Button
onClick={handleStartFullAudit}
className="w-full h-auto py-4 flex flex-col items-center justify-center space-y-2 cyber-btn-outline hover:bg-gray-800/50"
className="w-full h-auto py-4 flex flex-col items-center justify-center space-y-2 cyber-btn-outline hover:bg-muted"
>
<div className="flex items-center space-x-2">
<Activity className="w-5 h-5" />
<span className="text-lg font-bold uppercase"></span>
</div>
<span className="text-xs text-gray-500 font-mono"></span>
<span className="text-xs text-muted-foreground font-mono"></span>
</Button>
<Button
onClick={handleOpenCustomAudit}
className="w-full h-auto py-4 flex flex-col items-center justify-center space-y-2 cyber-btn-outline hover:bg-gray-800/50"
className="w-full h-auto py-4 flex flex-col items-center justify-center space-y-2 cyber-btn-outline hover:bg-muted"
>
<div className="flex items-center space-x-2">
<FileText className="w-5 h-5" />
<span className="text-lg font-bold uppercase"></span>
</div>
<span className="text-xs text-gray-500 font-mono"></span>
<span className="text-xs text-muted-foreground font-mono"></span>
</Button>
</div>
<DialogFooter className="p-4 border-t border-gray-800 bg-gray-900/30">
<DialogFooter className="p-4 border-t border-border bg-muted/50">
<Button variant="outline" onClick={() => setShowAuditOptionsDialog(false)} className="w-full cyber-btn-outline">
</Button>

View File

@ -275,7 +275,7 @@ export default function Projects() {
switch (type) {
case 'github': return <Github className="w-5 h-5" />;
case 'gitlab': return <GitBranch className="w-5 h-5 text-orange-500" />;
default: return <Folder className="w-5 h-5 text-gray-600" />;
default: return <Folder className="w-5 h-5 text-muted-foreground" />;
}
};
@ -404,14 +404,14 @@ export default function Projects() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 bg-background min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -423,21 +423,21 @@ export default function Projects() {
</Button>
</DialogTrigger>
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
{/* Terminal Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#0a0a0f] border-b border-gray-800/50 flex-shrink-0">
<div className="flex items-center gap-2 px-4 py-3 cyber-bg-elevated border-b border-border flex-shrink-0">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-gray-500 tracking-wider">
<span className="ml-2 font-mono text-xs text-muted-foreground tracking-wider">
new_project@deepaudit
</span>
</div>
<DialogHeader className="px-6 pt-4 flex-shrink-0">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-white">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-foreground">
<Terminal className="w-5 h-5 text-primary" />
</DialogTitle>
@ -445,17 +445,17 @@ export default function Projects() {
<div className="flex-1 overflow-y-auto p-6">
<Tabs defaultValue="repository" className="w-full">
<TabsList className="flex w-full bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded">
<TabsList className="flex w-full bg-muted border border-border p-1 h-auto gap-1 rounded">
<TabsTrigger
value="repository"
className="flex-1 data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"
className="flex-1 data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"
>
<GitBranch className="w-4 h-4 mr-2" />
Git
</TabsTrigger>
<TabsTrigger
value="upload"
className="flex-1 data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm"
className="flex-1 data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm"
>
<Upload className="w-4 h-4 mr-2" />
@ -465,7 +465,7 @@ export default function Projects() {
<TabsContent value="repository" className="flex flex-col gap-5 mt-5">
<div className="grid grid-cols-2 gap-5">
<div className="space-y-1.5">
<Label htmlFor="name" className="font-mono font-bold uppercase text-xs text-gray-400"> *</Label>
<Label htmlFor="name" className="font-mono font-bold uppercase text-xs text-muted-foreground"> *</Label>
<Input
id="name"
value={createForm.name}
@ -475,7 +475,7 @@ export default function Projects() {
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="repository_type" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="repository_type" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Select
value={createForm.repository_type}
onValueChange={(value: any) => setCreateForm({ ...createForm, repository_type: value })}
@ -483,7 +483,7 @@ export default function Projects() {
<SelectTrigger className="cyber-input">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="github">GITHUB</SelectItem>
<SelectItem value="gitlab">GITLAB</SelectItem>
<SelectItem value="other">OTHER</SelectItem>
@ -493,7 +493,7 @@ export default function Projects() {
</div>
<div className="space-y-1.5">
<Label htmlFor="description" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="description" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Textarea
id="description"
value={createForm.description}
@ -506,7 +506,7 @@ export default function Projects() {
<div className="grid grid-cols-2 gap-5">
<div className="space-y-1.5">
<Label htmlFor="repository_url" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="repository_url" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="repository_url"
value={createForm.repository_url}
@ -516,7 +516,7 @@ export default function Projects() {
/>
</div>
<div className="space-y-1.5">
<Label htmlFor="default_branch" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="default_branch" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="default_branch"
value={createForm.default_branch}
@ -528,12 +528,12 @@ export default function Projects() {
</div>
<div className="space-y-2">
<Label className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<div className="flex flex-wrap gap-2">
{supportedLanguages.map((lang) => (
<label key={lang} className={`flex items-center space-x-2 px-3 py-1.5 border cursor-pointer transition-all rounded ${createForm.programming_languages.includes(lang)
? 'border-primary bg-primary/10 text-primary'
: 'border-gray-700 hover:border-gray-600 text-gray-400'
: 'border-border hover:border-border text-muted-foreground'
}`}>
<input
type="checkbox"
@ -551,7 +551,7 @@ export default function Projects() {
});
}
}}
className="rounded border border-gray-600 w-3.5 h-3.5 text-primary focus:ring-0 bg-transparent"
className="rounded border border-border w-3.5 h-3.5 text-primary focus:ring-0 bg-transparent"
/>
<span className="text-xs font-mono font-bold uppercase">{lang}</span>
</label>
@ -559,7 +559,7 @@ export default function Projects() {
</div>
</div>
<div className="flex justify-end space-x-4 pt-4 border-t border-gray-800">
<div className="flex justify-end space-x-4 pt-4 border-t border-border">
<Button variant="outline" onClick={() => setShowCreateDialog(false)} className="cyber-btn-outline">
</Button>
@ -571,7 +571,7 @@ export default function Projects() {
<TabsContent value="upload" className="flex flex-col gap-5 mt-5">
<div className="space-y-1.5">
<Label htmlFor="upload-name" className="font-mono font-bold uppercase text-xs text-gray-400"> *</Label>
<Label htmlFor="upload-name" className="font-mono font-bold uppercase text-xs text-muted-foreground"> *</Label>
<Input
id="upload-name"
value={createForm.name}
@ -582,7 +582,7 @@ export default function Projects() {
</div>
<div className="space-y-1.5">
<Label htmlFor="upload-description" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="upload-description" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Textarea
id="upload-description"
value={createForm.description}
@ -594,12 +594,12 @@ export default function Projects() {
</div>
<div className="space-y-2">
<Label className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<div className="flex flex-wrap gap-2">
{supportedLanguages.map((lang) => (
<label key={lang} className={`flex items-center space-x-2 px-3 py-1.5 border cursor-pointer transition-all rounded ${createForm.programming_languages.includes(lang)
? 'border-primary bg-primary/10 text-primary'
: 'border-gray-700 hover:border-gray-600 text-gray-400'
: 'border-border hover:border-border text-muted-foreground'
}`}>
<input
type="checkbox"
@ -617,7 +617,7 @@ export default function Projects() {
});
}
}}
className="rounded border border-gray-600 w-3.5 h-3.5 text-primary focus:ring-0 bg-transparent"
className="rounded border border-border w-3.5 h-3.5 text-primary focus:ring-0 bg-transparent"
/>
<span className="text-xs font-mono font-bold uppercase">{lang}</span>
</label>
@ -626,16 +626,16 @@ export default function Projects() {
</div>
<div className="space-y-4">
<Label className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
{!selectedFile ? (
<div
className="border border-dashed border-gray-700 bg-gray-900/30 rounded p-6 text-center hover:bg-gray-900/50 hover:border-gray-600 transition-colors cursor-pointer group"
className="border border-dashed border-border bg-muted/50 rounded p-6 text-center hover:bg-muted hover:border-border transition-colors cursor-pointer group"
onClick={() => fileInputRef.current?.click()}
>
<Upload className="w-10 h-10 text-gray-500 mx-auto mb-3 group-hover:text-primary transition-colors" />
<h3 className="text-base font-bold text-gray-300 uppercase mb-1"> ZIP </h3>
<p className="text-[10px] font-mono text-gray-500 mb-3">
<Upload className="w-10 h-10 text-muted-foreground mx-auto mb-3 group-hover:text-primary transition-colors" />
<h3 className="text-base font-bold text-foreground uppercase mb-1"> ZIP </h3>
<p className="text-xs font-mono text-muted-foreground mb-3">
最大: 500MB // 格式: .ZIP
</p>
<input
@ -661,14 +661,14 @@ export default function Projects() {
</Button>
</div>
) : (
<div className="border border-gray-700 bg-gray-900/30 p-4 flex items-center justify-between rounded">
<div className="border border-border bg-muted/50 p-4 flex items-center justify-between rounded">
<div className="flex items-center space-x-3 overflow-hidden">
<div className="w-10 h-10 bg-gray-800 border border-gray-700 rounded flex items-center justify-center flex-shrink-0">
<div className="w-10 h-10 bg-muted border border-border rounded flex items-center justify-center flex-shrink-0">
<FileText className="w-5 h-5 text-primary" />
</div>
<div className="min-w-0">
<p className="font-mono font-bold text-sm text-gray-200 truncate">{selectedFile.name}</p>
<p className="font-mono text-xs text-gray-500">{(selectedFile.size / 1024 / 1024).toFixed(2)} MB</p>
<p className="font-mono font-bold text-sm text-foreground truncate">{selectedFile.name}</p>
<p className="font-mono text-xs text-muted-foreground">{(selectedFile.size / 1024 / 1024).toFixed(2)} MB</p>
</div>
</div>
<Button
@ -685,18 +685,18 @@ export default function Projects() {
{uploading && (
<div className="space-y-1.5">
<div className="flex items-center justify-between text-xs font-mono text-gray-400">
<div className="flex items-center justify-between text-xs font-mono text-muted-foreground">
<span>...</span>
<span className="text-primary">{uploadProgress}%</span>
</div>
<Progress value={uploadProgress} className="h-2 bg-gray-800 [&>div]:bg-primary" />
<Progress value={uploadProgress} className="h-2 bg-muted [&>div]:bg-primary" />
</div>
)}
<div className="bg-amber-500/10 border border-amber-500/30 p-3 rounded">
<div className="flex items-start space-x-3">
<AlertCircle className="w-4 h-4 text-amber-400 mt-0.5" />
<div className="text-[10px] font-mono text-amber-300">
<div className="text-xs font-mono text-amber-300">
<p className="font-bold mb-1 uppercase">:</p>
<ul className="space-y-0.5 list-disc list-inside text-amber-400/80">
<li></li>
@ -708,7 +708,7 @@ export default function Projects() {
</div>
</div>
<div className="flex justify-end space-x-4 pt-4 border-t border-gray-800 mt-auto">
<div className="flex justify-end space-x-4 pt-4 border-t border-border mt-auto">
<Button variant="outline" onClick={() => setShowCreateDialog(false)} disabled={uploading} className="cyber-btn-outline">
</Button>
@ -782,7 +782,7 @@ export default function Projects() {
{/* Search and Filter */}
<div className="cyber-card p-4 flex items-center gap-4 relative z-10">
<div className="flex-1 relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 w-4 h-4 z-10" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4 z-10" />
<Input
placeholder="搜索项目..."
value={searchTerm}
@ -802,13 +802,13 @@ export default function Projects() {
filteredProjects.map((project) => (
<div key={project.id} className="cyber-card flex flex-col h-full group">
{/* Card Header */}
<div className="p-4 border-b border-gray-800/50 bg-gray-900/30 flex justify-between items-start">
<div className="p-4 border-b border-border bg-muted/50 flex justify-between items-start">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 border border-gray-700 bg-gray-800/50 rounded flex items-center justify-center text-gray-400">
<div className="w-10 h-10 border border-border bg-muted rounded flex items-center justify-center text-muted-foreground">
{getRepositoryIcon(project.repository_type)}
</div>
<div>
<h3 className="font-bold text-base text-gray-200 group-hover:text-primary transition-colors">
<h3 className="font-bold text-base text-foreground group-hover:text-primary transition-colors">
<Link to={`/projects/${project.id}`}>
{project.name}
</Link>
@ -828,15 +828,15 @@ export default function Projects() {
{/* Card Body */}
<div className="p-4 flex-1 space-y-3">
{project.description && (
<p className="text-sm text-gray-400 font-mono line-clamp-2 border-l-2 border-gray-700 pl-2">
<p className="text-sm text-muted-foreground font-mono line-clamp-2 border-l-2 border-border pl-2">
{project.description}
</p>
)}
<div className="space-y-2">
{project.repository_url && (
<div className="flex items-center text-xs font-mono text-gray-500 bg-gray-900/50 p-2 border border-gray-800 rounded">
<GitBranch className="w-3 h-3 mr-2 flex-shrink-0 text-gray-600" />
<div className="flex items-center text-xs font-mono text-muted-foreground bg-muted p-2 border border-border rounded">
<GitBranch className="w-3 h-3 mr-2 flex-shrink-0 text-muted-foreground" />
<a
href={project.repository_url}
target="_blank"
@ -848,7 +848,7 @@ export default function Projects() {
</div>
)}
<div className="flex justify-between items-center text-xs font-mono text-gray-500">
<div className="flex justify-between items-center text-xs font-mono text-muted-foreground">
<span className="flex items-center"><Calendar className="w-3 h-3 mr-1" /> {formatDate(project.created_at)}</span>
<span className="flex items-center"><Users className="w-3 h-3 mr-1" /> {project.owner?.full_name || '未知'}</span>
</div>
@ -857,12 +857,12 @@ export default function Projects() {
{project.programming_languages && (
<div className="flex flex-wrap gap-1">
{JSON.parse(project.programming_languages).slice(0, 4).map((lang: string) => (
<span key={lang} className="text-[10px] font-mono font-bold border border-primary/30 px-1.5 py-0.5 bg-primary/10 text-primary rounded">
<span key={lang} className="text-xs font-mono font-bold border border-primary/30 px-1.5 py-0.5 bg-primary/10 text-primary rounded">
{lang.toUpperCase()}
</span>
))}
{JSON.parse(project.programming_languages).length > 4 && (
<span className="text-[10px] font-mono font-bold border border-gray-700 px-1.5 py-0.5 bg-gray-800/50 text-gray-400 rounded">
<span className="text-xs font-mono font-bold border border-border px-1.5 py-0.5 bg-muted text-muted-foreground rounded">
+{JSON.parse(project.programming_languages).length - 4}
</span>
)}
@ -871,7 +871,7 @@ export default function Projects() {
</div>
{/* Card Footer */}
<div className="p-4 border-t border-gray-800/50 bg-gray-900/30 grid grid-cols-2 gap-2">
<div className="p-4 border-t border-border bg-muted/50 grid grid-cols-2 gap-2">
<Link to={`/projects/${project.id}`} className="col-span-2">
<Button variant="outline" className="w-full cyber-btn-outline h-8 text-xs">
<Code className="w-3 h-3 mr-2" />
@ -897,11 +897,11 @@ export default function Projects() {
) : (
<div className="col-span-full">
<div className="cyber-card p-16 text-center border-dashed">
<Code className="w-16 h-16 text-gray-600 mx-auto mb-4" />
<h3 className="text-xl font-bold text-gray-300 mb-2">
<Code className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-xl font-bold text-foreground mb-2">
{searchTerm ? '未找到匹配项' : '未初始化项目'}
</h3>
<p className="text-gray-500 font-mono mb-6">
<p className="text-muted-foreground font-mono mb-6">
{searchTerm ? '调整搜索参数' : '初始化第一个项目以开始'}
</p>
{!searchTerm && (
@ -934,21 +934,21 @@ export default function Projects() {
{/* Edit Dialog */}
<Dialog open={showEditDialog} onOpenChange={setShowEditDialog}>
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
{/* Terminal Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#0a0a0f] border-b border-gray-800/50 flex-shrink-0">
<div className="flex items-center gap-2 px-4 py-3 cyber-bg-elevated border-b border-border flex-shrink-0">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-gray-500 tracking-wider">
<span className="ml-2 font-mono text-xs text-muted-foreground tracking-wider">
edit_project@deepaudit
</span>
</div>
<DialogHeader className="px-6 pt-4 flex-shrink-0">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-white">
<DialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-foreground">
<Edit className="w-5 h-5 text-primary" />
{projectToEdit && (
@ -962,9 +962,9 @@ export default function Projects() {
<div className="flex-1 overflow-y-auto p-6 space-y-6">
{/* 基本信息 */}
<div className="space-y-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400 border-b border-gray-800 pb-2"></h3>
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground border-b border-border pb-2"></h3>
<div>
<Label htmlFor="edit-name" className="font-mono font-bold uppercase text-xs text-gray-400"> *</Label>
<Label htmlFor="edit-name" className="font-mono font-bold uppercase text-xs text-muted-foreground"> *</Label>
<Input
id="edit-name"
value={editForm.name}
@ -973,7 +973,7 @@ export default function Projects() {
/>
</div>
<div>
<Label htmlFor="edit-description" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-description" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Textarea
id="edit-description"
value={editForm.description}
@ -987,13 +987,13 @@ export default function Projects() {
{/* 仓库信息 - 仅远程仓库类型显示 */}
{editForm.source_type === 'repository' && (
<div className="space-y-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400 border-b border-gray-800 pb-2 flex items-center gap-2">
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground border-b border-border pb-2 flex items-center gap-2">
<GitBranch className="w-4 h-4" />
</h3>
<div>
<Label htmlFor="edit-repo-url" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-repo-url" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="edit-repo-url"
value={editForm.repository_url}
@ -1005,7 +1005,7 @@ export default function Projects() {
<div className="grid grid-cols-2 gap-4">
<div>
<Label htmlFor="edit-repo-type" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-repo-type" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Select
value={editForm.repository_type}
onValueChange={(value: any) => setEditForm({ ...editForm, repository_type: value })}
@ -1013,7 +1013,7 @@ export default function Projects() {
<SelectTrigger id="edit-repo-type" className="cyber-input mt-1">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="github">GITHUB</SelectItem>
<SelectItem value="gitlab">GITLAB</SelectItem>
<SelectItem value="other">OTHER</SelectItem>
@ -1022,7 +1022,7 @@ export default function Projects() {
</div>
<div>
<Label htmlFor="edit-default-branch" className="font-mono font-bold uppercase text-xs text-gray-400"></Label>
<Label htmlFor="edit-default-branch" className="font-mono font-bold uppercase text-xs text-muted-foreground"></Label>
<Input
id="edit-default-branch"
value={editForm.default_branch}
@ -1038,7 +1038,7 @@ export default function Projects() {
{/* ZIP项目文件管理 */}
{editForm.source_type === 'zip' && (
<div className="space-y-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400 border-b border-gray-800 pb-2 flex items-center gap-2">
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground border-b border-border pb-2 flex items-center gap-2">
<Upload className="w-4 h-4" />
ZIP文件管理
</h3>
@ -1087,7 +1087,7 @@ export default function Projects() {
{/* 上传新文件 */}
<div className="space-y-2">
<Label className="font-mono font-bold uppercase text-xs text-gray-400">
<Label className="font-mono font-bold uppercase text-xs text-muted-foreground">
{editZipInfo?.has_file ? '更新ZIP文件' : '上传ZIP文件'}
</Label>
<input
@ -1115,7 +1115,7 @@ export default function Projects() {
<div className="flex items-center space-x-2">
<FileText className="w-4 h-4 text-sky-400" />
<span className="text-sm font-mono font-bold text-sky-300">{editZipFile.name}</span>
<span className="text-xs text-gray-500">
<span className="text-xs text-muted-foreground">
({(editZipFile.size / 1024 / 1024).toFixed(2)} MB)
</span>
</div>
@ -1144,25 +1144,25 @@ export default function Projects() {
{/* 技术栈 */}
<div className="space-y-4">
<h3 className="font-mono font-bold uppercase text-sm text-gray-400 border-b border-gray-800 pb-2"></h3>
<h3 className="font-mono font-bold uppercase text-sm text-muted-foreground border-b border-border pb-2"></h3>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
{supportedLanguages.map((lang) => (
<div
key={lang}
className={`flex items-center space-x-2 p-2 border cursor-pointer transition-all rounded ${editForm.programming_languages?.includes(lang)
? 'border-primary bg-primary/10 text-primary'
: 'border-gray-700 hover:border-gray-600 text-gray-400'
: 'border-border hover:border-border text-muted-foreground'
}`}
onClick={() => handleToggleLanguage(lang)}
>
<div
className={`w-4 h-4 border-2 rounded-sm flex items-center justify-center ${editForm.programming_languages?.includes(lang)
? 'bg-primary border-primary'
: 'border-gray-600'
: 'border-border'
}`}
>
{editForm.programming_languages?.includes(lang) && (
<CheckCircle className="w-3 h-3 text-white" />
<CheckCircle className="w-3 h-3 text-foreground" />
)}
</div>
<span className="text-sm font-mono font-bold uppercase">{lang}</span>
@ -1172,7 +1172,7 @@ export default function Projects() {
</div>
</div>
<div className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<div className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowEditDialog(false)} className="cyber-btn-outline">
</Button>
@ -1185,7 +1185,7 @@ export default function Projects() {
{/* Delete Dialog */}
<AlertDialog open={showDeleteDialog} onOpenChange={setShowDeleteDialog}>
<AlertDialogContent className="cyber-card border-gray-700 bg-[#0c0c12] p-0 !fixed">
<AlertDialogContent className="cyber-card border-border cyber-dialog p-0 !fixed">
{/* Terminal Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-rose-500/10 border-b border-rose-500/30">
<div className="flex items-center gap-1.5">
@ -1193,17 +1193,17 @@ export default function Projects() {
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-rose-400 tracking-wider">
<span className="ml-2 font-mono text-xs text-rose-400 tracking-wider">
confirm_delete@deepaudit
</span>
</div>
<AlertDialogHeader className="p-6">
<AlertDialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-white">
<AlertDialogTitle className="font-mono text-lg uppercase tracking-wider flex items-center gap-2 text-foreground">
<Trash2 className="w-5 h-5 text-rose-400" />
</AlertDialogTitle>
<AlertDialogDescription className="text-gray-400 font-mono">
<AlertDialogDescription className="text-muted-foreground font-mono">
<span className="font-bold text-rose-400">"{projectToDelete?.name}"</span>
</AlertDialogDescription>
</AlertDialogHeader>
@ -1220,11 +1220,11 @@ export default function Projects() {
</div>
</div>
<AlertDialogFooter className="p-4 border-t border-gray-800 bg-gray-900/30">
<AlertDialogFooter className="p-4 border-t border-border bg-muted/50">
<AlertDialogCancel className="cyber-btn-outline"></AlertDialogCancel>
<AlertDialogAction
onClick={handleConfirmDelete}
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-white hover:bg-rose-500"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-foreground hover:bg-rose-500"
>
</AlertDialogAction>

View File

@ -180,17 +180,17 @@ export default function PromptManager() {
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen bg-[#0a0a0f]">
<div className="flex items-center justify-center min-h-screen cyber-bg-elevated">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -249,7 +249,7 @@ export default function PromptManager() {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<div className="ml-auto">
<Button onClick={() => { resetForm(); setShowCreateDialog(true); }} className="cyber-btn-primary h-9">
<Plus className="w-4 h-4 mr-2" />
@ -279,15 +279,15 @@ export default function PromptManager() {
return (
<div key={template.id} className={`cyber-card p-0 ${!template.is_active ? 'opacity-60' : ''}`}>
{/* Template Header */}
<div className="p-5 border-b border-gray-800">
<div className="p-5 border-b border-border">
<div className="flex items-start justify-between mb-3">
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-gray-800 border border-gray-700 flex items-center justify-center rounded">
<TemplateIcon className="w-5 h-5 text-gray-400" />
<div className="w-10 h-10 bg-muted border border-border flex items-center justify-center rounded">
<TemplateIcon className="w-5 h-5 text-muted-foreground" />
</div>
<div>
<h3 className="font-bold text-base text-white uppercase">{template.name}</h3>
<p className="text-xs text-gray-500 line-clamp-1">{template.description}</p>
<h3 className="font-bold text-base text-foreground uppercase">{template.name}</h3>
<p className="text-xs text-muted-foreground line-clamp-1">{template.description}</p>
</div>
</div>
</div>
@ -301,7 +301,7 @@ export default function PromptManager() {
{/* Template Content Preview */}
<div className="p-4">
<div
className="text-xs text-emerald-400 line-clamp-3 bg-[#0a0a0f] p-3 border border-gray-800 font-mono mb-4 cursor-pointer hover:border-gray-700 transition-colors rounded"
className="text-xs text-emerald-400 line-clamp-3 cyber-bg-elevated p-3 border border-border font-mono mb-4 cursor-pointer hover:border-border transition-colors rounded"
onClick={() => openViewDialog(template)}
title="点击查看完整内容"
>
@ -344,9 +344,9 @@ export default function PromptManager() {
{/* Create/Edit Dialog */}
<Dialog open={showCreateDialog || showEditDialog} onOpenChange={(open) => { if (!open) { setShowCreateDialog(false); setShowEditDialog(false); } }}>
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,700px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<Terminal className="w-5 h-5 text-primary" />
</div>
@ -354,7 +354,7 @@ export default function PromptManager() {
<span className="text-base font-bold uppercase tracking-wider">
{showEditDialog ? '编辑模板' : '新建模板'}
</span>
<p className="text-xs text-gray-500 font-normal mt-0.5">
<p className="text-xs text-muted-foreground font-normal mt-0.5">
{showEditDialog ? 'Edit Template' : 'Create Template'}
</p>
</div>
@ -363,29 +363,29 @@ export default function PromptManager() {
<div className="flex-1 overflow-y-auto p-6 space-y-4">
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"> *</Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"> *</Label>
<Input value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} placeholder="如:安全专项审计" className="cyber-input" />
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={form.template_type} onValueChange={v => setForm({ ...form, template_type: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
{TEMPLATE_TYPES.map(t => <SelectItem key={t.value} value={t.value}>{t.label}</SelectItem>)}
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Input value={form.description} onChange={e => setForm({ ...form, description: e.target.value })} placeholder="模板用途描述" className="cyber-input" />
</div>
<Tabs defaultValue="zh" className="w-full">
<TabsList className="grid w-full grid-cols-2 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded">
<TabsTrigger value="zh" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsList className="grid w-full grid-cols-2 bg-muted border border-border p-1 h-auto gap-1 rounded">
<TabsTrigger value="zh" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
</TabsTrigger>
<TabsTrigger value="en" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="en" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
</TabsTrigger>
</TabsList>
@ -398,10 +398,10 @@ export default function PromptManager() {
</Tabs>
<div className="flex items-center gap-2">
<Switch checked={form.is_active} onCheckedChange={v => setForm({ ...form, is_active: v })} />
<Label className="text-xs font-bold text-gray-400 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
</div>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => { setShowCreateDialog(false); setShowEditDialog(false); }} className="cyber-btn-outline"></Button>
<Button onClick={showEditDialog ? handleUpdate : handleCreate} className="cyber-btn-primary">{showEditDialog ? '保存' : '创建'}</Button>
</DialogFooter>
@ -410,9 +410,9 @@ export default function PromptManager() {
{/* Test Dialog */}
<Dialog open={showTestDialog} onOpenChange={setShowTestDialog}>
<DialogContent className="!w-[min(95vw,1200px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(95vw,1200px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-violet-500/20 rounded border border-violet-500/30">
<Sparkles className="w-5 h-5 text-violet-400" />
</div>
@ -420,7 +420,7 @@ export default function PromptManager() {
<span className="text-base font-bold uppercase tracking-wider">
: {selectedTemplate?.name}
</span>
<p className="text-xs text-gray-500 font-normal mt-0.5">使</p>
<p className="text-xs text-muted-foreground font-normal mt-0.5">使</p>
</div>
</DialogTitle>
</DialogHeader>
@ -429,14 +429,14 @@ export default function PromptManager() {
<div className="space-y-4">
<div className="grid grid-cols-2 gap-3">
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={testForm.language} onValueChange={v => {
const templateCodes = selectedTemplate ? TEMPLATE_TEST_CODES[selectedTemplate.name] : null;
const code = templateCodes?.[v] || TEST_CODE_SAMPLES[v] || TEST_CODE_SAMPLES.python;
setTestForm({ ...testForm, language: v, code });
}}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="python">Python</SelectItem>
<SelectItem value="javascript">JavaScript</SelectItem>
<SelectItem value="java">Java</SelectItem>
@ -444,10 +444,10 @@ export default function PromptManager() {
</Select>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Select value={testForm.promptLang} onValueChange={(v: 'zh' | 'en') => setTestForm({ ...testForm, promptLang: v })}>
<SelectTrigger className="cyber-input"><SelectValue /></SelectTrigger>
<SelectContent className="bg-[#0c0c12] border-gray-700">
<SelectContent className="cyber-dialog border-border">
<SelectItem value="zh"></SelectItem>
<SelectItem value="en"></SelectItem>
</SelectContent>
@ -455,7 +455,7 @@ export default function PromptManager() {
</div>
</div>
<div className="space-y-2">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<Textarea value={testForm.code} onChange={e => setTestForm({ ...testForm, code: e.target.value })} rows={10} className="cyber-input font-mono text-sm text-emerald-400" />
</div>
<Button onClick={handleTest} disabled={testing} className="w-full cyber-btn-primary h-12">
@ -464,8 +464,8 @@ export default function PromptManager() {
</div>
{/* Right: Results */}
<div className="space-y-4">
<Label className="text-xs font-bold text-gray-500 uppercase"></Label>
<div className="border border-gray-800 h-[400px] overflow-auto bg-[#0a0a0f] rounded">
<Label className="text-xs font-bold text-muted-foreground uppercase"></Label>
<div className="border border-border h-[400px] overflow-auto cyber-bg-elevated rounded">
{testResult ? (
testResult.success ? (
<div className="flex flex-col h-full">
@ -482,15 +482,15 @@ export default function PromptManager() {
{/* Quality Score */}
{testResult.result?.quality_score !== undefined && (
<div className="p-3 bg-gray-900/50 border-b border-gray-800 flex items-center justify-between">
<span className="text-xs font-bold uppercase text-gray-500"></span>
<div className="p-3 bg-muted border-b border-border flex items-center justify-between">
<span className="text-xs font-bold uppercase text-muted-foreground"></span>
<div className="flex items-center gap-2">
<div className={`text-2xl font-bold ${testResult.result.quality_score >= 80 ? 'text-emerald-400' :
testResult.result.quality_score >= 60 ? 'text-amber-400' : 'text-rose-400'
}`}>
{testResult.result.quality_score}
</div>
<span className="text-xs text-gray-500">/ 100</span>
<span className="text-xs text-muted-foreground">/ 100</span>
</div>
</div>
)}
@ -500,14 +500,14 @@ export default function PromptManager() {
{testResult.result?.issues?.length > 0 ? (
<div className="space-y-3">
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-bold uppercase text-gray-500"></span>
<span className="text-xs font-bold uppercase text-muted-foreground"></span>
<Badge className="cyber-badge-danger">
{testResult.result.issues.length}
</Badge>
</div>
{testResult.result.issues.map((issue: any, idx: number) => (
<div key={idx} className="cyber-card p-0 overflow-hidden">
<div className={`px-3 py-2 border-b border-gray-800 flex items-center justify-between ${issue.severity === 'critical' ? 'bg-rose-500/20 text-rose-400' :
<div className={`px-3 py-2 border-b border-border flex items-center justify-between ${issue.severity === 'critical' ? 'bg-rose-500/20 text-rose-400' :
issue.severity === 'high' ? 'bg-orange-500/20 text-orange-400' :
issue.severity === 'medium' ? 'bg-amber-500/20 text-amber-400' : 'bg-sky-500/20 text-sky-400'
}`}>
@ -515,9 +515,9 @@ export default function PromptManager() {
{issue.line && <span className="text-xs opacity-80"> {issue.line}</span>}
</div>
<div className="p-3">
<h4 className="font-bold text-sm mb-1 text-gray-200">{issue.title}</h4>
<h4 className="font-bold text-sm mb-1 text-foreground">{issue.title}</h4>
{issue.description && (
<p className="text-xs text-gray-500 leading-relaxed">{issue.description}</p>
<p className="text-xs text-muted-foreground leading-relaxed">{issue.description}</p>
)}
{issue.suggestion && (
<div className="mt-2 p-2 bg-sky-500/10 border-l-2 border-sky-500 rounded-r">
@ -537,7 +537,7 @@ export default function PromptManager() {
<Check className="w-6 h-6 text-emerald-400" />
</div>
<p className="font-bold text-emerald-400 uppercase text-sm"></p>
<p className="text-xs text-gray-500 mt-1"></p>
<p className="text-xs text-muted-foreground mt-1"></p>
</div>
)}
</ScrollArea>
@ -567,8 +567,8 @@ export default function PromptManager() {
</div>
)
) : (
<div className="flex flex-col items-center justify-center h-full text-gray-500">
<div className="w-16 h-16 bg-gray-800 border border-gray-700 flex items-center justify-center mb-4 rounded">
<div className="flex flex-col items-center justify-center h-full text-muted-foreground">
<div className="w-16 h-16 bg-muted border border-border flex items-center justify-center mb-4 rounded">
<Play className="w-8 h-8 opacity-50" />
</div>
<p className="font-mono uppercase text-sm">"运行测试"</p>
@ -578,7 +578,7 @@ export default function PromptManager() {
</div>
</div>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => setShowTestDialog(false)} className="cyber-btn-outline"></Button>
</DialogFooter>
</DialogContent>
@ -586,9 +586,9 @@ export default function PromptManager() {
{/* View Dialog */}
<Dialog open={showViewDialog} onOpenChange={setShowViewDialog}>
<DialogContent className="!w-[min(90vw,800px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 bg-[#0c0c12] border border-gray-800 rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-gray-800 flex-shrink-0 bg-gray-900/50">
<DialogTitle className="flex items-center gap-3 font-mono text-white">
<DialogContent className="!w-[min(90vw,800px)] !max-w-none max-h-[85vh] flex flex-col p-0 gap-0 cyber-dialog border border-border rounded-lg">
<DialogHeader className="px-6 py-4 border-b border-border flex-shrink-0 bg-muted">
<DialogTitle className="flex items-center gap-3 font-mono text-foreground">
<div className="p-2 bg-primary/20 rounded border border-primary/30">
<FileText className="w-5 h-5 text-primary" />
</div>
@ -596,7 +596,7 @@ export default function PromptManager() {
<span className="text-base font-bold uppercase tracking-wider">
{viewTemplate?.name}
</span>
<p className="text-xs text-gray-500 font-normal mt-0.5">{viewTemplate?.description || 'View Template'}</p>
<p className="text-xs text-muted-foreground font-normal mt-0.5">{viewTemplate?.description || 'View Template'}</p>
</div>
</DialogTitle>
</DialogHeader>
@ -613,27 +613,27 @@ export default function PromptManager() {
</div>
<Tabs defaultValue="zh" className="w-full">
<TabsList className="grid w-full grid-cols-2 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded">
<TabsTrigger value="zh" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsList className="grid w-full grid-cols-2 bg-muted border border-border p-1 h-auto gap-1 rounded">
<TabsTrigger value="zh" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
</TabsTrigger>
<TabsTrigger value="en" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="en" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
</TabsTrigger>
</TabsList>
<TabsContent value="zh" className="mt-4">
<div className="bg-[#0a0a0f] text-emerald-400 p-4 border border-gray-800 font-mono text-sm whitespace-pre-wrap max-h-[500px] overflow-y-auto rounded">
<div className="cyber-bg-elevated text-emerald-400 p-4 border border-border font-mono text-sm whitespace-pre-wrap max-h-[500px] overflow-y-auto rounded">
{viewTemplate?.content_zh || '(无中文内容)'}
</div>
</TabsContent>
<TabsContent value="en" className="mt-4">
<div className="bg-[#0a0a0f] text-emerald-400 p-4 border border-gray-800 font-mono text-sm whitespace-pre-wrap max-h-[500px] overflow-y-auto rounded">
<div className="cyber-bg-elevated text-emerald-400 p-4 border border-border font-mono text-sm whitespace-pre-wrap max-h-[500px] overflow-y-auto rounded">
{viewTemplate?.content_en || '(No English content)'}
</div>
</TabsContent>
</Tabs>
</div>
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-gray-900/50 border-t border-gray-800">
<DialogFooter className="flex-shrink-0 flex justify-end gap-3 px-6 py-4 bg-muted border-t border-border">
<Button variant="outline" onClick={() => copyToClipboard(viewTemplate?.content_zh || viewTemplate?.content_en || '')} className="cyber-btn-outline">
<Copy className="w-4 h-4 mr-2" />

View File

@ -109,17 +109,17 @@ export default function RecycleBin() {
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen bg-[#0a0a0f]">
<div className="flex items-center justify-center min-h-screen cyber-bg-elevated">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
}
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -127,12 +127,12 @@ export default function RecycleBin() {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<Trash2 className="w-5 h-5 text-rose-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
<Badge className="ml-2 cyber-badge-muted">{deletedProjects.length} </Badge>
</div>
<div className="p-4">
<div className="relative">
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-500 w-4 h-4" />
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4" />
<Input
placeholder="搜索已删除的项目..."
value={searchTerm}
@ -147,20 +147,20 @@ export default function RecycleBin() {
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 relative z-10">
{filteredProjects.length > 0 ? (
filteredProjects.map((project) => (
<div key={project.id} className="cyber-card p-0 hover:border-gray-700 transition-all group">
<div key={project.id} className="cyber-card p-0 hover:border-border transition-all group">
{/* Project Header */}
<div className="p-4 border-b border-gray-800 bg-gray-900/30">
<div className="p-4 border-b border-border bg-muted/50">
<div className="flex items-start justify-between">
<div className="flex items-center space-x-3">
<div className="w-10 h-10 bg-gray-800 border border-gray-700 flex items-center justify-center text-lg rounded">
<div className="w-10 h-10 bg-muted border border-border flex items-center justify-center text-lg rounded">
{getRepositoryIcon(project.repository_type)}
</div>
<div>
<h3 className="text-base font-bold uppercase text-gray-200 truncate max-w-[150px] group-hover:text-primary transition-colors">
<h3 className="text-base font-bold uppercase text-foreground truncate max-w-[150px] group-hover:text-primary transition-colors">
{project.name}
</h3>
{project.description && (
<p className="text-xs text-gray-500 mt-1 line-clamp-1">
<p className="text-xs text-muted-foreground mt-1 line-clamp-1">
{project.description}
</p>
)}
@ -179,8 +179,8 @@ export default function RecycleBin() {
{/* Project Info */}
<div className="space-y-3">
{isRepositoryProject(project) && project.repository_url && (
<div className="flex items-center text-xs text-gray-500">
<GitBranch className="w-4 h-4 mr-2 flex-shrink-0 text-gray-600" />
<div className="flex items-center text-xs text-muted-foreground">
<GitBranch className="w-4 h-4 mr-2 flex-shrink-0 text-muted-foreground" />
<a
href={project.repository_url}
target="_blank"
@ -193,13 +193,13 @@ export default function RecycleBin() {
</div>
)}
<div className="flex items-center justify-between text-xs text-gray-500">
<div className="flex items-center justify-between text-xs text-muted-foreground">
<div className="flex items-center">
<Calendar className="w-4 h-4 mr-2 text-gray-600" />
<Calendar className="w-4 h-4 mr-2 text-muted-foreground" />
{formatDate(project.updated_at)}
</div>
<div className="flex items-center">
<Users className="w-4 h-4 mr-2 text-gray-600" />
<Users className="w-4 h-4 mr-2 text-muted-foreground" />
{project.owner?.full_name || '未知'}
</div>
</div>
@ -222,7 +222,7 @@ export default function RecycleBin() {
)}
{/* Action Buttons */}
<div className="flex gap-2 pt-3 border-t border-gray-800">
<div className="flex gap-2 pt-3 border-t border-border">
<Button
size="sm"
variant="outline"
@ -262,19 +262,19 @@ export default function RecycleBin() {
{/* Restore Dialog */}
<AlertDialog open={showRestoreDialog} onOpenChange={setShowRestoreDialog}>
<AlertDialogContent className="cyber-card p-0 bg-[#0c0c12] max-w-md !fixed">
<AlertDialogContent className="cyber-card p-0 cyber-dialog max-w-md !fixed">
<AlertDialogHeader className="cyber-card-header">
<RotateCcw className="w-5 h-5 text-emerald-400" />
<AlertDialogTitle className="text-lg font-bold uppercase tracking-wider text-white">
<AlertDialogTitle className="text-lg font-bold uppercase tracking-wider text-foreground">
</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogDescription className="p-6 text-gray-400">
<span className="font-bold text-white">"{selectedProject?.name}"</span>
<AlertDialogDescription className="p-6 text-muted-foreground">
<span className="font-bold text-foreground">"{selectedProject?.name}"</span>
<br /><br />
使
</AlertDialogDescription>
<AlertDialogFooter className="p-4 border-t border-gray-800 flex gap-3">
<AlertDialogFooter className="p-4 border-t border-border flex gap-3">
<AlertDialogCancel className="cyber-btn-outline"></AlertDialogCancel>
<AlertDialogAction
onClick={handleConfirmRestore}
@ -288,15 +288,15 @@ export default function RecycleBin() {
{/* Permanent Delete Dialog */}
<AlertDialog open={showPermanentDeleteDialog} onOpenChange={setShowPermanentDeleteDialog}>
<AlertDialogContent className="cyber-card p-0 bg-[#0c0c12] max-w-md !fixed">
<AlertDialogContent className="cyber-card p-0 cyber-dialog max-w-md !fixed">
<AlertDialogHeader className="p-4 border-b border-rose-500/30 bg-rose-500/10 flex flex-row items-center gap-2">
<AlertTriangle className="w-5 h-5 text-rose-400" />
<AlertDialogTitle className="text-lg font-bold uppercase tracking-wider text-rose-400">
</AlertDialogTitle>
</AlertDialogHeader>
<AlertDialogDescription className="p-6 text-gray-400">
<span className="font-bold text-rose-400 uppercase"></span> <span className="font-bold text-white">"{selectedProject?.name}"</span>
<AlertDialogDescription className="p-6 text-muted-foreground">
<span className="font-bold text-rose-400 uppercase"></span> <span className="font-bold text-foreground">"{selectedProject?.name}"</span>
<br /><br />
<div className="bg-rose-500/10 border border-rose-500/30 p-4 rounded">
<p className="text-rose-400 font-bold mb-2 uppercase flex items-center">
@ -310,7 +310,7 @@ export default function RecycleBin() {
</ul>
</div>
</AlertDialogDescription>
<AlertDialogFooter className="p-4 border-t border-gray-800 flex gap-3">
<AlertDialogFooter className="p-4 border-t border-border flex gap-3">
<AlertDialogCancel className="cyber-btn-outline"></AlertDialogCancel>
<AlertDialogAction
onClick={handleConfirmPermanentDelete}

View File

@ -47,7 +47,7 @@ export default function Register() {
};
return (
<div className="min-h-screen flex items-center justify-center bg-[#0a0a0f] relative overflow-hidden">
<div className="min-h-screen flex items-center justify-center cyber-bg-elevated relative overflow-hidden">
{/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20">
<div
@ -79,7 +79,7 @@ export default function Register() {
/>
{/* Corner Decorations */}
<div className="absolute top-4 left-4 text-[10px] font-mono text-gray-700 z-30 space-y-1">
<div className="absolute top-4 left-4 text-xs font-mono text-muted-foreground z-30 space-y-1">
<div className="flex items-center gap-2">
<Terminal className="w-3 h-3" />
<span>REG_MODULE: ACTIVE</span>
@ -94,17 +94,17 @@ export default function Register() {
</div>
</div>
<div className="absolute top-4 right-4 text-[10px] font-mono text-gray-700 text-right z-30 space-y-1">
<div className="absolute top-4 right-4 text-xs font-mono text-muted-foreground text-right z-30 space-y-1">
<div>SECURE_CONN: TRUE</div>
<div>VALIDATION: ENABLED</div>
<div>HASH: SHA-256</div>
</div>
<div className="absolute bottom-4 left-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 left-4 text-xs font-mono text-muted-foreground z-30">
DEEPAUDIT_REG_v3
</div>
<div className="absolute bottom-4 right-4 text-[10px] font-mono text-gray-700 z-30">
<div className="absolute bottom-4 right-4 text-xs font-mono text-muted-foreground z-30">
{new Date().toISOString().split("T")[0]}
</div>
@ -112,7 +112,7 @@ export default function Register() {
<div className="w-full max-w-md relative z-30 px-4">
{/* Logo & Title */}
<div className="text-center mb-8">
<div className="inline-flex items-center justify-center p-3 bg-[#0c0c12] border border-gray-800/60 rounded-lg mb-6"
<div className="inline-flex items-center justify-center p-3 cyber-dialog border border-border/60 rounded-lg mb-6"
style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}>
<img
src="/logo_deepaudit.png"
@ -125,24 +125,24 @@ export default function Register() {
style={{ textShadow: "0 0 30px rgba(255,107,44,0.5), 0 0 60px rgba(255,107,44,0.3)" }}
>
<span className="text-primary">DEEP</span>
<span className="text-white">AUDIT</span>
<span className="text-foreground">AUDIT</span>
</div>
<p className="text-sm font-mono text-gray-500">
<p className="text-sm font-mono text-muted-foreground">
// Create New Account
</p>
</div>
{/* Register Form Card */}
<div className="bg-[#0c0c12] border border-gray-800/60 rounded-lg overflow-hidden"
<div className="cyber-dialog border border-border/60 rounded-lg overflow-hidden"
style={{ boxShadow: '0 4px 30px rgba(0,0,0,0.5)' }}>
{/* Card Header */}
<div className="flex items-center gap-2 px-4 py-3 bg-[#0a0a0f] border-b border-gray-800/50">
<div className="flex items-center gap-2 px-4 py-3 cyber-bg-elevated border-b border-border">
<div className="flex items-center gap-1.5">
<div className="w-3 h-3 rounded-full bg-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-500/80" />
<div className="w-3 h-3 rounded-full bg-green-500/80" />
</div>
<span className="ml-2 font-mono text-[11px] text-gray-500 tracking-wider">
<span className="ml-2 font-mono text-xs text-muted-foreground tracking-wider">
register@deepaudit
</span>
</div>
@ -152,7 +152,7 @@ export default function Register() {
<div className="space-y-2">
<Label
htmlFor="fullName"
className="font-mono text-xs text-gray-400 uppercase tracking-wider"
className="font-mono text-xs text-muted-foreground uppercase tracking-wider"
>
</Label>
@ -163,16 +163,16 @@ export default function Register() {
value={fullName}
onChange={(e) => setFullName(e.target.value)}
required
className="h-12 pl-11 font-mono bg-[#0a0a0f] border-gray-700/50 text-gray-200 placeholder:text-gray-600 focus:border-primary/50 focus:ring-0"
className="h-12 pl-11 font-mono cyber-bg-elevated border-border/50 text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:ring-0"
/>
<User className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<User className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="email"
className="font-mono text-xs text-gray-400 uppercase tracking-wider"
className="font-mono text-xs text-muted-foreground uppercase tracking-wider"
>
</Label>
@ -184,16 +184,16 @@ export default function Register() {
value={email}
onChange={(e) => setEmail(e.target.value)}
required
className="h-12 pl-11 font-mono bg-[#0a0a0f] border-gray-700/50 text-gray-200 placeholder:text-gray-600 focus:border-primary/50 focus:ring-0"
className="h-12 pl-11 font-mono cyber-bg-elevated border-border/50 text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:ring-0"
/>
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
</div>
</div>
<div className="space-y-2">
<Label
htmlFor="password"
className="font-mono text-xs text-gray-400 uppercase tracking-wider"
className="font-mono text-xs text-muted-foreground uppercase tracking-wider"
>
</Label>
@ -205,15 +205,15 @@ export default function Register() {
value={password}
onChange={(e) => setPassword(e.target.value)}
required
className="h-12 pl-11 font-mono bg-[#0a0a0f] border-gray-700/50 text-gray-200 placeholder:text-gray-600 focus:border-primary/50 focus:ring-0"
className="h-12 pl-11 font-mono cyber-bg-elevated border-border/50 text-foreground placeholder:text-muted-foreground focus:border-primary/50 focus:ring-0"
/>
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-600" />
<Lock className="absolute left-4 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" />
</div>
</div>
<Button
type="submit"
className="w-full h-12 text-base font-bold uppercase tracking-wider bg-primary hover:bg-primary/90 text-white border border-primary/50 transition-all"
className="w-full h-12 text-base font-bold uppercase tracking-wider bg-primary hover:bg-primary/90 text-foreground border border-primary/50 transition-all"
style={{ boxShadow: '0 0 20px rgba(255,107,44,0.3)' }}
disabled={loading}
>
@ -229,8 +229,8 @@ export default function Register() {
</form>
{/* Footer */}
<div className="mt-6 pt-5 border-t border-gray-800/50 text-center">
<p className="text-sm font-mono text-gray-500">
<div className="mt-6 pt-5 border-t border-border text-center">
<p className="text-sm font-mono text-muted-foreground">
{" "}
<span
className="text-primary font-bold cursor-pointer hover:underline"
@ -245,7 +245,7 @@ export default function Register() {
{/* Version Info */}
<div className="mt-6 text-center">
<p className="font-mono text-[10px] text-gray-600 uppercase">
<p className="font-mono text-xs text-muted-foreground uppercase">
Version {version} · Secure Registration
</p>
</div>

View File

@ -81,7 +81,7 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
const lowIssues = issues.filter(issue => issue.severity === 'low');
const renderIssue = (issue: AuditIssue, index: number) => (
<div key={issue.id || index} className="cyber-card p-4 hover:border-gray-700 transition-all group">
<div key={issue.id || index} className="cyber-card p-4 hover:border-border transition-all group">
<div className="flex items-start justify-between mb-3">
<div className="flex items-start space-x-3">
<div className={`w-10 h-10 rounded-lg flex items-center justify-center ${
@ -93,13 +93,13 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
{getTypeIcon(issue.issue_type)}
</div>
<div className="flex-1">
<h4 className="font-bold text-base text-gray-200 mb-1 group-hover:text-primary transition-colors uppercase">{issue.title}</h4>
<div className="flex items-center space-x-1 text-xs text-gray-500 font-mono">
<h4 className="font-bold text-base text-foreground mb-1 group-hover:text-primary transition-colors uppercase">{issue.title}</h4>
<div className="flex items-center space-x-1 text-xs text-muted-foreground font-mono">
<FileText className="w-3 h-3" />
<span className="bg-gray-800 px-2 py-0.5 rounded border border-gray-700">{issue.file_path}</span>
<span className="bg-muted px-2 py-0.5 rounded border border-border">{issue.file_path}</span>
</div>
{issue.line_number && (
<div className="flex items-center space-x-1 text-xs text-gray-500 mt-1 font-mono">
<div className="flex items-center space-x-1 text-xs text-muted-foreground mt-1 font-mono">
<span className="text-primary">&gt;</span>
<span>LINE: {issue.line_number}</span>
{issue.column_number && <span>, COL: {issue.column_number}</span>}
@ -107,7 +107,7 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
)}
</div>
</div>
<Badge className={`${getSeverityClasses(issue.severity)} font-bold uppercase px-2 py-1 rounded text-[10px]`}>
<Badge className={`${getSeverityClasses(issue.severity)} font-bold uppercase px-2 py-1 rounded text-xs`}>
{issue.severity === 'critical' ? '严重' :
issue.severity === 'high' ? '高' :
issue.severity === 'medium' ? '中等' : '低'}
@ -115,31 +115,31 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
</div>
{issue.description && (
<div className="bg-gray-900/50 border border-gray-800 p-3 mb-3 rounded font-mono">
<div className="flex items-center mb-1 border-b border-gray-800 pb-1">
<Info className="w-3 h-3 text-gray-500 mr-1" />
<span className="font-bold text-gray-400 text-xs uppercase"></span>
<div className="bg-muted border border-border p-3 mb-3 rounded font-mono">
<div className="flex items-center mb-1 border-b border-border pb-1">
<Info className="w-3 h-3 text-muted-foreground mr-1" />
<span className="font-bold text-muted-foreground text-xs uppercase"></span>
</div>
<p className="text-gray-300 text-xs leading-relaxed mt-1">
<p className="text-foreground text-xs leading-relaxed mt-1">
{issue.description}
</p>
</div>
)}
{issue.code_snippet && (
<div className="bg-[#0a0a0f] p-3 mb-3 border border-gray-800 rounded">
<div className="flex items-center justify-between mb-2 border-b border-gray-800 pb-1">
<div className="cyber-bg-elevated p-3 mb-3 border border-border rounded">
<div className="flex items-center justify-between mb-2 border-b border-border pb-1">
<div className="flex items-center space-x-1">
<div className="w-4 h-4 bg-primary rounded flex items-center justify-center">
<Code className="w-2 h-2 text-white" />
<Code className="w-2 h-2 text-foreground" />
</div>
<span className="text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
</div>
{issue.line_number && (
<span className="text-gray-500 text-xs font-mono">LINE: {issue.line_number}</span>
<span className="text-muted-foreground text-xs font-mono">LINE: {issue.line_number}</span>
)}
</div>
<div className="bg-black/40 p-2 border border-gray-800 rounded">
<div className="bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
<code>{issue.code_snippet}</code>
</pre>
@ -177,21 +177,21 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
{parsedExplanation.what && (
<div className="border-l-2 border-rose-500 pl-2">
<span className="font-bold text-rose-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.what}</span>
<span className="text-foreground ml-1">{parsedExplanation.what}</span>
</div>
)}
{parsedExplanation.why && (
<div className="border-l-2 border-amber-500 pl-2">
<span className="font-bold text-amber-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.why}</span>
<span className="text-foreground ml-1">{parsedExplanation.why}</span>
</div>
)}
{parsedExplanation.how && (
<div className="border-l-2 border-emerald-500 pl-2">
<span className="font-bold text-emerald-400 uppercase"></span>
<span className="text-gray-300 ml-1">{parsedExplanation.how}</span>
<span className="text-foreground ml-1">{parsedExplanation.how}</span>
</div>
)}
@ -218,7 +218,7 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
<Zap className="w-4 h-4 text-violet-400 mr-2" />
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
</div>
<p className="text-gray-300 text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
<p className="text-foreground text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
</div>
);
}
@ -244,20 +244,20 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
return (
<Tabs defaultValue="all" className="w-full">
<TabsList className="grid w-full grid-cols-5 bg-gray-900/50 border border-gray-800 p-1 h-auto gap-1 rounded">
<TabsTrigger value="all" className="data-[state=active]:bg-primary data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsList className="grid w-full grid-cols-5 bg-muted border border-border p-1 h-auto gap-1 rounded">
<TabsTrigger value="all" className="data-[state=active]:bg-primary data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({issues.length})
</TabsTrigger>
<TabsTrigger value="critical" className="data-[state=active]:bg-rose-500 data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="critical" className="data-[state=active]:bg-rose-500 data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({criticalIssues.length})
</TabsTrigger>
<TabsTrigger value="high" className="data-[state=active]:bg-orange-500 data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="high" className="data-[state=active]:bg-orange-500 data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({highIssues.length})
</TabsTrigger>
<TabsTrigger value="medium" className="data-[state=active]:bg-amber-500 data-[state=active]:text-black font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="medium" className="data-[state=active]:bg-amber-500 data-[state=active]:text-background font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({mediumIssues.length})
</TabsTrigger>
<TabsTrigger value="low" className="data-[state=active]:bg-sky-500 data-[state=active]:text-white font-mono font-bold uppercase py-2 text-gray-400 transition-all rounded-sm text-xs">
<TabsTrigger value="low" className="data-[state=active]:bg-sky-500 data-[state=active]:text-foreground font-mono font-bold uppercase py-2 text-muted-foreground transition-all rounded-sm text-xs">
({lowIssues.length})
</TabsTrigger>
</TabsList>
@ -272,8 +272,8 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
) : (
<div className="cyber-card p-12 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 uppercase mb-2"></h3>
<p className="text-gray-500 font-mono"></p>
<h3 className="text-lg font-bold text-foreground uppercase mb-2"></h3>
<p className="text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -284,8 +284,8 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
) : (
<div className="cyber-card p-12 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 uppercase mb-2"></h3>
<p className="text-gray-500 font-mono"></p>
<h3 className="text-lg font-bold text-foreground uppercase mb-2"></h3>
<p className="text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -296,8 +296,8 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
) : (
<div className="cyber-card p-12 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 uppercase mb-2"></h3>
<p className="text-gray-500 font-mono"></p>
<h3 className="text-lg font-bold text-foreground uppercase mb-2"></h3>
<p className="text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -308,8 +308,8 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
) : (
<div className="cyber-card p-12 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-lg font-bold text-gray-300 uppercase mb-2"></h3>
<p className="text-gray-500 font-mono"></p>
<h3 className="text-lg font-bold text-foreground uppercase mb-2"></h3>
<p className="text-muted-foreground font-mono"></p>
</div>
)}
</TabsContent>
@ -450,8 +450,8 @@ export default function TaskDetail() {
case 'completed': return <CheckCircle className="w-4 h-4 text-emerald-400" />;
case 'running': return <Activity className="w-4 h-4 text-sky-400" />;
case 'failed': return <AlertTriangle className="w-4 h-4 text-rose-400" />;
case 'cancelled': return <XCircle className="w-4 h-4 text-gray-400" />;
default: return <Clock className="w-4 h-4 text-gray-400" />;
case 'cancelled': return <XCircle className="w-4 h-4 text-muted-foreground" />;
default: return <Clock className="w-4 h-4 text-muted-foreground" />;
}
};
@ -470,7 +470,7 @@ export default function TaskDetail() {
<div className="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4">
<div className="loading-spinner mx-auto" />
<p className="text-gray-500 font-mono text-sm uppercase tracking-wider">...</p>
<p className="text-muted-foreground font-mono text-sm uppercase tracking-wider">...</p>
</div>
</div>
);
@ -478,7 +478,7 @@ export default function TaskDetail() {
if (!task) {
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono">
<div className="flex items-center space-x-4">
<Link to="/audit-tasks">
<Button variant="outline" size="sm" className="cyber-btn-ghost h-10 w-10 p-0">
@ -488,8 +488,8 @@ export default function TaskDetail() {
</div>
<div className="cyber-card p-16 text-center">
<AlertTriangle className="w-16 h-16 text-rose-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-white uppercase mb-2"></h3>
<p className="text-gray-500 font-mono">ID是否正确</p>
<h3 className="text-xl font-bold text-foreground uppercase mb-2"></h3>
<p className="text-muted-foreground font-mono">ID是否正确</p>
</div>
</div>
);
@ -498,7 +498,7 @@ export default function TaskDetail() {
const progressPercentage = calculateTaskProgress(task.scanned_files, task.total_files);
return (
<div className="space-y-6 p-6 bg-[#0a0a0f] min-h-screen font-mono relative">
<div className="space-y-6 p-6 cyber-bg-elevated min-h-screen font-mono relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" />
@ -516,7 +516,7 @@ export default function TaskDetail() {
{(task.status === 'running' || task.status === 'pending') && (
<Button
size="sm"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-white hover:bg-rose-500 h-10"
className="cyber-btn bg-rose-500/90 border-rose-500/50 text-foreground hover:bg-rose-500 h-10"
onClick={handleCancelTask}
disabled={cancelling}
>
@ -545,7 +545,7 @@ export default function TaskDetail() {
<div className="w-full">
<p className="stat-label"></p>
<p className="stat-value mb-2">{progressPercentage}%</p>
<Progress value={progressPercentage} className="h-2 bg-gray-800 [&>div]:bg-primary" />
<Progress value={progressPercentage} className="h-2 bg-muted [&>div]:bg-primary" />
</div>
<div className="stat-icon text-primary ml-4">
<Activity className="w-6 h-6" />
@ -596,34 +596,34 @@ export default function TaskDetail() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<Shield className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6 space-y-4 font-mono">
<div className="grid grid-cols-2 gap-4">
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200">
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground">
{task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'}
</p>
</div>
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200 flex items-center">
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground flex items-center">
<GitBranch className="w-4 h-4 mr-1" />
{task.branch_name || '默认分支'}
</p>
</div>
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200 flex items-center">
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground flex items-center">
<Calendar className="w-4 h-4 mr-1" />
{formatDate(task.created_at)}
</p>
</div>
{task.completed_at && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200 flex items-center">
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground flex items-center">
<CheckCircle className="w-4 h-4 mr-1" />
{formatDate(task.completed_at)}
</p>
@ -633,7 +633,7 @@ export default function TaskDetail() {
{task.exclude_patterns && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-2"></p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-2"></p>
<div className="flex flex-wrap gap-2">
{JSON.parse(task.exclude_patterns).map((pattern: string) => (
<Badge key={pattern} className="cyber-badge-muted">
@ -646,8 +646,8 @@ export default function TaskDetail() {
{task.scan_config && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-2"></p>
<div className="bg-[#0a0a0f] border border-gray-800 p-3 rounded">
<p className="text-xs font-bold text-muted-foreground uppercase mb-2"></p>
<div className="cyber-bg-elevated border border-border p-3 rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
{JSON.stringify(JSON.parse(task.scan_config), null, 2)}
</pre>
@ -662,36 +662,36 @@ export default function TaskDetail() {
<div className="cyber-card p-0">
<div className="cyber-card-header">
<FileText className="w-5 h-5 text-primary" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"></h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"></h3>
</div>
<div className="p-6 space-y-4 font-mono">
{task.project ? (
<>
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<Link to={`/projects/${task.project.id}`} className="text-base font-bold text-primary hover:underline">
{task.project.name}
</Link>
</div>
{task.project.description && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-sm text-gray-300">{task.project.description}</p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-sm text-foreground">{task.project.description}</p>
</div>
)}
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200">{getSourceTypeLabel(task.project.source_type)}</p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground">{getSourceTypeLabel(task.project.source_type)}</p>
</div>
{isRepositoryProject(task.project) && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-1"></p>
<p className="text-base font-bold text-gray-200">{task.project.repository_type?.toUpperCase() || 'OTHER'}</p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-1"></p>
<p className="text-base font-bold text-foreground">{task.project.repository_type?.toUpperCase() || 'OTHER'}</p>
</div>
)}
{task.project.programming_languages && (
<div>
<p className="text-xs font-bold text-gray-500 uppercase mb-2"></p>
<p className="text-xs font-bold text-muted-foreground uppercase mb-2"></p>
<div className="flex flex-wrap gap-1">
{JSON.parse(task.project.programming_languages).map((lang: string) => (
<Badge key={lang} className="cyber-badge-primary">
@ -703,7 +703,7 @@ export default function TaskDetail() {
)}
</>
) : (
<p className="text-gray-500 font-bold"></p>
<p className="text-muted-foreground font-bold"></p>
)}
</div>
</div>
@ -715,7 +715,7 @@ export default function TaskDetail() {
<div className="cyber-card p-0 relative z-10">
<div className="cyber-card-header">
<Bug className="w-5 h-5 text-amber-400" />
<h3 className="text-lg font-bold uppercase tracking-wider text-white"> ({issues.length})</h3>
<h3 className="text-lg font-bold uppercase tracking-wider text-foreground"> ({issues.length})</h3>
</div>
<div className="p-6">
<IssuesList issues={issues} />

View File

@ -56,7 +56,7 @@ export const PLATFORM_COLORS: Record<RepositoryPlatform, {
bg: string;
text: string;
}> = {
github: { bg: 'bg-gray-800', text: 'text-white' },
github: { bg: 'bg-foreground', text: 'text-background' },
gitlab: { bg: 'bg-orange-500', text: 'text-white' },
other: { bg: 'bg-gray-500', text: 'text-white' }
other: { bg: 'bg-muted-foreground', text: 'text-background' }
};

View File

@ -25,13 +25,14 @@ export default {
display: ['"Orbitron"', '"Rajdhani"', 'sans-serif'],
},
fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem', letterSpacing: '0.01em' }],
'sm': ['0.875rem', { lineHeight: '1.25rem', letterSpacing: '0.01em' }],
'base': ['1rem', { lineHeight: '1.5rem', letterSpacing: '0' }],
'lg': ['1.125rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }],
'xl': ['1.25rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }],
'2xl': ['1.5rem', { lineHeight: '2rem', letterSpacing: '-0.02em' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem', letterSpacing: '-0.02em' }],
'xs': ['0.8125rem', { lineHeight: '1.125rem', letterSpacing: '0.01em' }], // 13px
'sm': ['0.9375rem', { lineHeight: '1.375rem', letterSpacing: '0.01em' }], // 15px
'base': ['1rem', { lineHeight: '1.5rem', letterSpacing: '0' }], // 16px
'lg': ['1.125rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }], // 18px
'xl': ['1.375rem', { lineHeight: '1.875rem', letterSpacing: '-0.01em' }], // 22px
'2xl': ['1.625rem', { lineHeight: '2.125rem', letterSpacing: '-0.02em' }], // 26px
'3xl': ['2rem', { lineHeight: '2.5rem', letterSpacing: '-0.02em' }], // 32px
'4xl': ['2.5rem', { lineHeight: '3rem', letterSpacing: '-0.02em' }], // 40px
},
// Extended Color System
colors: {