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 { StrictMode } from "react";
import { createRoot } from "react-dom/client"; import { createRoot } from "react-dom/client";
import { ThemeProvider } from "next-themes";
import "@/assets/styles/globals.css"; import "@/assets/styles/globals.css";
import App from "./App.tsx"; import App from "./App.tsx";
import { AppWrapper } from "@/components/layout/PageMeta"; import { AppWrapper } from "@/components/layout/PageMeta";
@ -9,9 +10,16 @@ import "@/shared/utils/fetchWrapper"; // 初始化fetch拦截器
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<StrictMode> <StrictMode>
<ErrorBoundary> <ErrorBoundary>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange={false}
>
<AppWrapper> <AppWrapper>
<App /> <App />
</AppWrapper> </AppWrapper>
</ThemeProvider>
</ErrorBoundary> </ErrorBoundary>
</StrictMode> </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="space-y-3">
<div className="flex items-center gap-2 mb-2"> <div className="flex items-center gap-2 mb-2">
<Shield className="w-4 h-4 text-violet-400" /> <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> </span>
</div> </div>
@ -35,7 +35,7 @@ export default function AgentModeSelector({
"relative flex flex-col p-4 border cursor-pointer transition-all rounded", "relative flex flex-col p-4 border cursor-pointer transition-all rounded",
value === "fast" value === "fast"
? "border-amber-500/50 bg-amber-950/30" ? "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" disabled && "opacity-50 cursor-not-allowed"
)} )}
> >
@ -54,16 +54,16 @@ export default function AgentModeSelector({
"p-1.5 rounded border", "p-1.5 rounded border",
value === "fast" value === "fast"
? "bg-amber-500/20 border-amber-500/50" ? "bg-amber-500/20 border-amber-500/50"
: "bg-gray-800 border-gray-700" : "bg-muted border-border"
)}> )}>
<Zap className={cn( <Zap className={cn(
"w-4 h-4", "w-4 h-4",
value === "fast" ? "text-amber-400" : "text-gray-500" value === "fast" ? "text-amber-400" : "text-muted-foreground"
)} /> )} />
</div> </div>
<span className={cn( <span className={cn(
"font-bold text-sm font-mono uppercase", "font-bold text-sm font-mono uppercase",
value === "fast" ? "text-amber-300" : "text-gray-400" value === "fast" ? "text-amber-300" : "text-muted-foreground"
)}> )}>
</span> </span>
@ -72,7 +72,7 @@ export default function AgentModeSelector({
)} )}
</div> </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"> <li className="flex items-center gap-1">
<Clock className="w-3 h-3" /> <Clock className="w-3 h-3" />
@ -81,14 +81,14 @@ export default function AgentModeSelector({
<Code className="w-3 h-3" /> <Code className="w-3 h-3" />
LLM LLM
</li> </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" /> <Shield className="w-3 h-3" />
</li> </li>
</ul> </ul>
<div className="mt-auto pt-2 border-t border-gray-800"> <div className="mt-auto pt-2 border-t border-border">
<span className="text-[10px] uppercase tracking-wider text-gray-600 font-bold font-mono"> <span className="text-xs uppercase tracking-wider text-muted-foreground font-bold font-mono">
适合: CI/CD 适合: CI/CD
</span> </span>
</div> </div>
@ -100,7 +100,7 @@ export default function AgentModeSelector({
"relative flex flex-col p-4 border cursor-pointer transition-all rounded", "relative flex flex-col p-4 border cursor-pointer transition-all rounded",
value === "agent" value === "agent"
? "border-violet-500/50 bg-violet-950/30" ? "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" 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> </div>
@ -124,16 +124,16 @@ export default function AgentModeSelector({
"p-1.5 rounded border", "p-1.5 rounded border",
value === "agent" value === "agent"
? "bg-violet-500/20 border-violet-500/50" ? "bg-violet-500/20 border-violet-500/50"
: "bg-gray-800 border-gray-700" : "bg-muted border-border"
)}> )}>
<Bot className={cn( <Bot className={cn(
"w-4 h-4", "w-4 h-4",
value === "agent" ? "text-violet-400" : "text-gray-500" value === "agent" ? "text-violet-400" : "text-muted-foreground"
)} /> )} />
</div> </div>
<span className={cn( <span className={cn(
"font-bold text-sm font-mono uppercase", "font-bold text-sm font-mono uppercase",
value === "agent" ? "text-violet-300" : "text-gray-400" value === "agent" ? "text-violet-300" : "text-muted-foreground"
)}> )}>
Agent Agent
</span> </span>
@ -142,7 +142,7 @@ export default function AgentModeSelector({
)} )}
</div> </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"> <li className="flex items-center gap-1">
<Bot className="w-3 h-3" /> <Bot className="w-3 h-3" />
AI Agent AI Agent
@ -153,15 +153,15 @@ export default function AgentModeSelector({
</li> </li>
<li className={cn( <li className={cn(
"flex items-center gap-1", "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" /> <Shield className="w-3 h-3" />
</li> </li>
</ul> </ul>
<div className="mt-auto pt-2 border-t border-gray-800"> <div className="mt-auto pt-2 border-t border-border">
<span className="text-[10px] uppercase tracking-wider text-gray-600 font-bold font-mono"> <span className="text-xs uppercase tracking-wider text-muted-foreground font-bold font-mono">
适合: 发版前审计 适合: 发版前审计
</span> </span>
</div> </div>

View File

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

View File

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

View File

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

View File

@ -72,7 +72,7 @@ const getFileIcon = (path: string) => {
if (configExts.includes(ext)) { if (configExts.includes(ext)) {
return <FileJson className="w-4 h-4 text-amber-400" />; 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( items.push(
<div key={`folder-${folder.path}`}> <div key={`folder-${folder.path}`}>
<div <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` }} style={{ paddingLeft: `${depth * 16 + 8}px` }}
> >
<button <button
@ -334,12 +334,12 @@ export default function FileSelectionDialog({
e.stopPropagation(); e.stopPropagation();
handleExpandFolder(folder.path); handleExpandFolder(folder.path);
}} }}
className="p-0.5 hover:bg-gray-700 rounded" className="p-0.5 hover:bg-muted rounded"
> >
{isExpanded ? ( {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> </button>
<div onClick={(e) => e.stopPropagation()}> <div onClick={(e) => e.stopPropagation()}>
@ -352,7 +352,7 @@ export default function FileSelectionDialog({
} }
}} }}
onCheckedChange={() => handleToggleFolder(folder.path)} 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> </div>
{isExpanded ? ( {isExpanded ? (
@ -361,12 +361,12 @@ export default function FileSelectionDialog({
<Folder className="w-4 h-4 text-amber-400" /> <Folder className="w-4 h-4 text-amber-400" />
)} )}
<span <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)} onClick={() => handleExpandFolder(folder.path)}
> >
{folder.name} {folder.name}
</span> </span>
<Badge className="cyber-badge-muted font-mono text-[10px]"> <Badge className="cyber-badge-muted font-mono text-xs">
{ {
filteredFiles.filter((f) => filteredFiles.filter((f) =>
f.path.startsWith(folder.path + "/") f.path.startsWith(folder.path + "/")
@ -387,7 +387,7 @@ export default function FileSelectionDialog({
items.push( items.push(
<div <div
key={`file-${file.path}`} 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` }} style={{ paddingLeft: `${depth * 16 + 32}px` }}
onClick={() => handleToggleFile(file.path)} onClick={() => handleToggleFile(file.path)}
> >
@ -395,18 +395,18 @@ export default function FileSelectionDialog({
<Checkbox <Checkbox
checked={selectedFiles.has(file.path)} checked={selectedFiles.has(file.path)}
onCheckedChange={() => handleToggleFile(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> </div>
{getFileIcon(file.path)} {getFileIcon(file.path)}
<span <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} title={file.path}
> >
{fileName} {fileName}
</span> </span>
{file.size > 0 && ( {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)} {formatSize(file.size)}
</Badge> </Badge>
)} )}
@ -422,24 +422,24 @@ export default function FileSelectionDialog({
return filteredFiles.map((file) => ( return filteredFiles.map((file) => (
<div <div
key={file.path} 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)} onClick={() => handleToggleFile(file.path)}
> >
<div onClick={(e) => e.stopPropagation()}> <div onClick={(e) => e.stopPropagation()}>
<Checkbox <Checkbox
checked={selectedFiles.has(file.path)} checked={selectedFiles.has(file.path)}
onCheckedChange={() => handleToggleFile(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> </div>
{getFileIcon(file.path)} {getFileIcon(file.path)}
<div className="flex-1 min-w-0"> <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} {file.path}
</p> </p>
</div> </div>
{file.size > 0 && ( {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)} {formatSize(file.size)}
</Badge> </Badge>
)} )}
@ -449,11 +449,11 @@ export default function FileSelectionDialog({
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <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"> <DialogHeader className="cyber-card-header flex-shrink-0">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<FolderOpen className="w-5 h-5 text-primary" /> <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> </DialogTitle>
</div> </div>
@ -469,7 +469,7 @@ export default function FileSelectionDialog({
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
{/* 搜索框 */} {/* 搜索框 */}
<div className="relative flex-1 min-w-[200px]"> <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 <Input
placeholder="搜索文件..." placeholder="搜索文件..."
value={searchTerm} value={searchTerm}
@ -481,11 +481,11 @@ export default function FileSelectionDialog({
{/* 文件类型筛选 */} {/* 文件类型筛选 */}
{fileTypes.length > 0 && ( {fileTypes.length > 0 && (
<div className="flex items-center gap-1"> <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 <select
value={filterType} value={filterType}
onChange={(e) => setFilterType(e.target.value)} 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> <option value=""></option>
{fileTypes.slice(0, 10).map(([ext, count]) => ( {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 <button
onClick={() => setViewMode("tree")} 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>
<button <button
onClick={() => setViewMode("flat")} 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> </button>
@ -552,14 +552,14 @@ export default function FileSelectionDialog({
setSearchTerm(""); setSearchTerm("");
setFilterType(""); 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" /> <RotateCcw className="w-3 h-3 mr-1" />
</Button> </Button>
)} )}
</div> </div>
<div className="text-sm font-mono text-gray-500"> <div className="text-sm font-mono text-muted-foreground">
{searchTerm || filterType ? ( {searchTerm || filterType ? (
<span> <span>
: {filteredFiles.length}/{files.length} : {filteredFiles.length}/{files.length}
@ -574,7 +574,7 @@ export default function FileSelectionDialog({
</div> </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 ? ( {loading ? (
<div className="absolute inset-0 flex items-center justify-center"> <div className="absolute inset-0 flex items-center justify-center">
<div className="loading-spinner" /> <div className="loading-spinner" />
@ -588,7 +588,7 @@ export default function FileSelectionDialog({
</div> </div>
</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" /> <FileText className="w-12 h-12 mb-2 opacity-20" />
<p className="font-mono text-sm"> <p className="font-mono text-sm">
{searchTerm || filterType {searchTerm || filterType
@ -600,8 +600,8 @@ export default function FileSelectionDialog({
</div> </div>
</div> </div>
<DialogFooter className="p-5 border-t border-gray-800 bg-gray-900/50 flex-shrink-0 flex justify-between"> <DialogFooter className="p-5 border-t border-border bg-muted flex-shrink-0 flex justify-between">
<div className="text-xs font-mono text-gray-600 flex items-center gap-2"> <div className="text-xs font-mono text-muted-foreground flex items-center gap-2">
<Terminal className="w-3 h-3" /> <Terminal className="w-3 h-3" />
/ /
</div> </div>

View File

@ -425,7 +425,7 @@ export default function TerminalProgressDialog({
case "warning": case "warning":
return "text-amber-400"; return "text-amber-400";
default: default:
return "text-gray-400"; return "text-muted-foreground";
} }
}; };
@ -462,13 +462,13 @@ export default function TerminalProgressDialog({
/> />
{/* Header */} {/* 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%)" }}> 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"> <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))" }} /> <Terminal className="w-5 h-5 text-primary" style={{ filter: "drop-shadow(0 0 8px rgba(255, 95, 31, 0.5))" }} />
<div> <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-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>
</div> </div>
@ -501,16 +501,16 @@ export default function TerminalProgressDialog({
{/* Left Sidebar - Task Info */} {/* Left Sidebar - Task Info */}
<div className="w-48 p-4 border-r border-[#1a2535] bg-[#060810] flex flex-col gap-4"> <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="space-y-1.5">
<div className="text-[9px] font-bold text-[#5a6577] uppercase tracking-[0.15em]">Task ID</div> <div className="text-xs 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-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)" }}> style={{ textShadow: "0 0 10px rgba(255, 95, 31, 0.3)" }}>
{taskId?.slice(0, 8)}... {taskId?.slice(0, 8)}...
</div> </div>
</div> </div>
<div className="space-y-1.5"> <div className="space-y-1.5">
<div className="text-[9px] font-bold text-[#5a6577] uppercase tracking-[0.15em]">Type</div> <div className="text-xs 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="flex items-center gap-2 cyber-bg-elevated p-2.5 rounded border border-[#1a2535]">
{taskType === 'repository' {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))" }} /> ? <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))" }} />} : <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 */} {/* Status Badge */}
<div className="space-y-2"> <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 ? ( {isCancelled ? (
<Badge className="w-full justify-center cyber-badge-warning">CANCELLED</Badge> <Badge className="w-full justify-center cyber-badge-warning">CANCELLED</Badge>
) : isCompleted ? ( ) : isCompleted ? (
@ -566,7 +566,7 @@ export default function TerminalProgressDialog({
</div> </div>
{/* Bottom Controls */} {/* 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"> <div className="flex items-center gap-2 text-xs text-[#6a7587] font-mono tracking-wide">
<Activity className="w-3.5 h-3.5" /> <Activity className="w-3.5 h-3.5" />
<span> <span>
@ -580,7 +580,7 @@ export default function TerminalProgressDialog({
size="sm" size="sm"
variant="outline" variant="outline"
onClick={handleCancel} 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" /> <AlertTriangle className="w-3 h-3 mr-1.5" />
@ -592,7 +592,7 @@ export default function TerminalProgressDialog({
size="sm" size="sm"
variant="outline" variant="outline"
onClick={() => window.open('/logs', '_blank')} 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" /> <Activity className="w-3 h-3 mr-1.5" />
@ -603,7 +603,7 @@ export default function TerminalProgressDialog({
<Button <Button
size="sm" size="sm"
onClick={() => onOpenChange(false)} 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" /> <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 className="space-y-6">
<div> <div>
<Label className="text-base font-bold uppercase"></Label> <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> </p>
</div> </div>
@ -83,11 +83,11 @@ export default function AdvancedOptions({
> >
<SelectTrigger <SelectTrigger
id="analysis_depth" 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 /> <SelectValue />
</SelectTrigger> </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 value="basic" className="font-mono">
() ()
</SelectItem> </SelectItem>
@ -104,16 +104,16 @@ export default function AdvancedOptions({
</div> </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> <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> <div>
<p className="text-sm font-bold uppercase"> <p className="text-sm font-bold uppercase">
{hasSelectedFiles {hasSelectedFiles
? `已选择 ${scanConfig.file_paths!.length} 个文件` ? `已选择 ${scanConfig.file_paths!.length} 个文件`
: "全量扫描 (所有文件)"} : "全量扫描 (所有文件)"}
</p> </p>
<p className="text-xs text-gray-500 font-bold"> <p className="text-xs text-muted-foreground font-bold">
{hasSelectedFiles {hasSelectedFiles
? "仅分析选中的文件" ? "仅分析选中的文件"
: "分析项目中的所有代码文件"} : "分析项目中的所有代码文件"}
@ -126,7 +126,7 @@ export default function AdvancedOptions({
variant="outline" variant="outline"
size="sm" size="sm"
onClick={() => onUpdate({ file_paths: undefined })} 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> </Button>
@ -136,7 +136,7 @@ export default function AdvancedOptions({
variant="outline" variant="outline"
size="sm" size="sm"
onClick={onOpenFileSelection} 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 ? "修改选择" : "选择文件"} {hasSelectedFiles ? "修改选择" : "选择文件"}
</Button> </Button>
@ -162,15 +162,15 @@ function CheckboxOption({
description: string; description: string;
}) { }) {
return ( 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 <Checkbox
checked={checked} checked={checked}
onCheckedChange={(c) => onChange(!!c)} 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> <div>
<p className="text-sm font-bold uppercase">{label}</p> <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>
</div> </div>
); );
@ -178,7 +178,7 @@ function CheckboxOption({
function DepthExplanation() { function DepthExplanation() {
return ( 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"> <div className="flex items-start space-x-3">
<AlertCircle className="w-5 h-5 text-amber-600 mt-0.5" /> <AlertCircle className="w-5 h-5 text-amber-600 mt-0.5" />
<div className="text-sm font-mono"> <div className="text-sm font-mono">

View File

@ -36,7 +36,7 @@ export default function ExcludePatterns({
<div className="space-y-4"> <div className="space-y-4">
<div> <div>
<Label className="text-base font-bold uppercase"></Label> <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> </p>
</div> </div>
@ -46,16 +46,16 @@ export default function ExcludePatterns({
{COMMON_EXCLUDE_PATTERNS.map((pattern) => ( {COMMON_EXCLUDE_PATTERNS.map((pattern) => (
<div <div
key={pattern.value} 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 <Checkbox
checked={patterns.includes(pattern.value)} checked={patterns.includes(pattern.value)}
onCheckedChange={() => onToggle(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"> <div className="flex-1">
<p className="text-sm font-bold uppercase">{pattern.label}</p> <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} {pattern.description}
</p> </p>
</div> </div>
@ -103,7 +103,7 @@ function CustomPatternInput({ onAdd }: { onAdd: (pattern: string) => void }) {
.previousElementSibling as HTMLInputElement; .previousElementSibling as HTMLInputElement;
handleAdd(input); handleAdd(input);
}} }}
className="retro-btn bg-white text-black h-10" className="retro-btn bg-background text-foreground h-10"
> >
</Button> </Button>
@ -127,7 +127,7 @@ function SelectedPatterns({
<Badge <Badge
key={pattern} key={pattern}
variant="secondary" 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)} onClick={() => onRemove(pattern)}
> >
{pattern} × {pattern} ×

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -33,13 +33,13 @@ function AccordionTrigger({
<AccordionPrimitive.Trigger <AccordionPrimitive.Trigger
data-slot="accordion-trigger" data-slot="accordion-trigger"
className={cn( 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 className
)} )}
{...props} {...props}
> >
{children} {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.Trigger>
</AccordionPrimitive.Header> </AccordionPrimitive.Header>
); );
@ -53,7 +53,7 @@ function AccordionContent({
return ( return (
<AccordionPrimitive.Content <AccordionPrimitive.Content
data-slot="accordion-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} {...props}
> >
<div className={cn("pt-0 pb-4", className)}>{children}</div> <div className={cn("pt-0 pb-4", className)}>{children}</div>

View File

@ -52,7 +52,7 @@ function AlertDialogContent({
<AlertDialogPrimitive.Content <AlertDialogPrimitive.Content
data-slot="alert-dialog-content" data-slot="alert-dialog-content"
className={cn( 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 className
)} )}
{...props} {...props}
@ -68,7 +68,7 @@ function AlertDialogHeader({
return ( return (
<div <div
data-slot="alert-dialog-header" 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} {...props}
/> />
); );
@ -82,7 +82,7 @@ function AlertDialogFooter({
<div <div
data-slot="alert-dialog-footer" data-slot="alert-dialog-footer"
className={cn( 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 className
)} )}
{...props} {...props}
@ -97,7 +97,7 @@ function AlertDialogTitle({
return ( return (
<AlertDialogPrimitive.Title <AlertDialogPrimitive.Title
data-slot="alert-dialog-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} {...props}
/> />
); );
@ -110,7 +110,7 @@ function AlertDialogDescription({
return ( return (
<AlertDialogPrimitive.Description <AlertDialogPrimitive.Description
data-slot="alert-dialog-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} {...props}
/> />
); );

View File

@ -4,7 +4,7 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/shared/utils/utils" import { cn } from "@/shared/utils/utils"
const alertVariants = cva( 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: { variants: {
variant: { variant: {
@ -39,7 +39,7 @@ function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
<div <div
data-slot="alert-title" data-slot="alert-title"
className={cn( 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 className
)} )}
{...props} {...props}
@ -55,7 +55,7 @@ function AlertDescription({
<div <div
data-slot="alert-description" data-slot="alert-description"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/utils/utils"; import { cn } from "@/shared/utils/utils";
const badgeVariants = cva( 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: { variants: {
variant: { variant: {
@ -14,7 +14,7 @@ const badgeVariants = cva(
secondary: secondary:
"border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
destructive: 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: outline:
"text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", "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"; import { cn } from "@/shared/utils/utils";
const buttonVariants = cva( 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: { variants: {
variant: { variant: {
@ -21,10 +21,10 @@ const buttonVariants = cva(
link: "text-primary underline-offset-4 hover:underline", link: "text-primary underline-offset-4 hover:underline",
}, },
size: { size: {
default: "h-9 px-4 py-2", default: "h-11 px-5 py-2.5",
sm: "h-8 rounded-sm px-3 text-xs", sm: "h-9 rounded-sm px-4 text-sm",
lg: "h-10 rounded-sm px-8", lg: "h-13 rounded-sm px-8 text-lg",
icon: "h-9 w-9", icon: "h-11 w-11",
}, },
}, },
defaultVariants: { defaultVariants: {

View File

@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
<div <div
data-slot="card" data-slot="card"
className={cn( 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 className
)} )}
{...props} {...props}
@ -20,7 +20,7 @@ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
<div <div
data-slot="card-header" data-slot="card-header"
className={cn( 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 className
)} )}
{...props} {...props}
@ -32,7 +32,7 @@ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-title" 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} {...props}
/> />
); );
@ -42,7 +42,7 @@ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-description" data-slot="card-description"
className={cn("text-muted-foreground text-sm", className)} className={cn("text-base text-foreground/70 font-mono", className)}
{...props} {...props}
/> />
); );
@ -65,7 +65,7 @@ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-content" data-slot="card-content"
className={cn("px-6", className)} className={cn("py-2", className)}
{...props} {...props}
/> />
); );
@ -75,7 +75,7 @@ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
return ( return (
<div <div
data-slot="card-footer" 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} {...props}
/> />
); );

View File

@ -12,7 +12,7 @@ function Checkbox({
<CheckboxPrimitive.Root <CheckboxPrimitive.Root
data-slot="checkbox" data-slot="checkbox"
className={cn( 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 className
)} )}
{...props} {...props}
@ -21,7 +21,7 @@ function Checkbox({
data-slot="checkbox-indicator" data-slot="checkbox-indicator"
className="flex items-center justify-center text-current transition-none" className="flex items-center justify-center text-current transition-none"
> >
<CheckIcon className="size-3.5" /> <CheckIcon className="size-4" />
</CheckboxPrimitive.Indicator> </CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
); );

View File

@ -19,7 +19,7 @@ function Command({
<CommandPrimitive <CommandPrimitive
data-slot="command" data-slot="command"
className={cn( 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 className
)} )}
{...props} {...props}
@ -64,7 +64,7 @@ function CommandInput({
<CommandPrimitive.Input <CommandPrimitive.Input
data-slot="command-input" data-slot="command-input"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -38,7 +38,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content <DialogPrimitive.Content
ref={ref} ref={ref}
className={cn( 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 className
)} )}
{...props} {...props}
@ -59,7 +59,7 @@ const DialogHeader = ({
}: React.HTMLAttributes<HTMLDivElement>) => ( }: React.HTMLAttributes<HTMLDivElement>) => (
<div <div
className={cn( 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 className
)} )}
{...props} {...props}
@ -73,7 +73,7 @@ const DialogFooter = ({
}: React.HTMLAttributes<HTMLDivElement>) => ( }: React.HTMLAttributes<HTMLDivElement>) => (
<div <div
className={cn( 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 className
)} )}
{...props} {...props}
@ -88,7 +88,7 @@ const DialogTitle = React.forwardRef<
<DialogPrimitive.Title <DialogPrimitive.Title
ref={ref} ref={ref}
className={cn( className={cn(
"text-lg font-semibold leading-none tracking-tight", "text-xl font-mono font-bold uppercase tracking-wider text-foreground",
className className
)} )}
{...props} {...props}
@ -102,7 +102,7 @@ const DialogDescription = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<DialogPrimitive.Description <DialogPrimitive.Description
ref={ref} ref={ref}
className={cn("text-sm text-muted-foreground", className)} className={cn("text-base text-foreground/70 font-mono", className)}
{...props} {...props}
/> />
)) ))

View File

@ -27,7 +27,7 @@ const DropdownMenuSubTrigger = React.forwardRef<
<DropdownMenuPrimitive.SubTrigger <DropdownMenuPrimitive.SubTrigger
ref={ref} ref={ref}
className={cn( 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", inset && "pl-8",
className className
)} )}
@ -65,7 +65,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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]", "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 className
)} )}
@ -84,7 +84,7 @@ const DropdownMenuItem = React.forwardRef<
<DropdownMenuPrimitive.Item <DropdownMenuPrimitive.Item
ref={ref} ref={ref}
className={cn( 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", inset && "pl-8",
className className
)} )}
@ -148,7 +148,7 @@ const DropdownMenuLabel = React.forwardRef<
<DropdownMenuPrimitive.Label <DropdownMenuPrimitive.Label
ref={ref} ref={ref}
className={cn( className={cn(
"px-2 py-1.5 text-sm font-semibold", "px-3 py-2 text-base font-semibold",
inset && "pl-8", inset && "pl-8",
className className
)} )}

View File

@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type} type={type}
data-slot="input" data-slot="input"
className={cn( 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", "focus:border-primary focus:shadow-focus",
"aria-invalid:border-secondary", "aria-invalid:border-secondary",
className className

View File

@ -13,7 +13,7 @@ function Label({
<LabelPrimitive.Root <LabelPrimitive.Root
data-slot="label" data-slot="label"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -12,7 +12,7 @@ function Menubar({
<MenubarPrimitive.Root <MenubarPrimitive.Root
data-slot="menubar" data-slot="menubar"
className={cn( 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 className
)} )}
{...props} {...props}
@ -77,7 +77,7 @@ function MenubarContent({
alignOffset={alignOffset} alignOffset={alignOffset}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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 className
)} )}
{...props} {...props}
@ -246,7 +246,7 @@ function MenubarSubContent({
<MenubarPrimitive.SubContent <MenubarPrimitive.SubContent
data-slot="menubar-sub-content" data-slot="menubar-sub-content"
className={cn( 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 className
)} )}
{...props} {...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 z-20 inline-block w-full" ref={containerRef}>
<div className="relative flex flex-col items-center"> <div className="relative flex flex-col items-center">
<div onClick={toggleDropdown} className="w-full"> <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"> <div className="flex flex-wrap flex-auto gap-2">
{selectedValuesText.length > 0 ? ( {selectedValuesText.length > 0 ? (
selectedValuesText.map((text, index) => ( selectedValuesText.map((text, index) => (
<div <div
key={index} 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> <span className="flex-initial max-w-full">{text}</span>
<div className="flex flex-row-reverse flex-auto"> <div className="flex flex-row-reverse flex-auto">
@ -104,7 +104,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
e.stopPropagation(); e.stopPropagation();
removeOption(selectedOptions[index]); 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 <svg
className="fill-current" className="fill-current"
@ -127,7 +127,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
) : ( ) : (
<input <input
placeholder="请选择选项..." 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 readOnly
value="请选择选项..." value="请选择选项..."
/> />
@ -137,7 +137,7 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
<button <button
type="button" type="button"
onClick={toggleDropdown} 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 <svg
className={`stroke-current ${isOpen ? "rotate-180" : ""}`} className={`stroke-current ${isOpen ? "rotate-180" : ""}`}
@ -162,14 +162,14 @@ const MultiSelect: React.FC<MultiSelectProps> = ({
{isOpen && ( {isOpen && (
<div <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()} onClick={(e) => e.stopPropagation()}
> >
<div className="flex flex-col"> <div className="flex flex-col">
{options.map((option, index) => ( {options.map((option, index) => (
<div <div
key={index} 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)} onClick={() => handleSelect(option.value)}
> >
<div <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} {option.label}
</div> </div>
</div> </div>

View File

@ -59,7 +59,7 @@ function NavigationMenuItem({
} }
const navigationMenuTriggerStyle = cva( 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({ function NavigationMenuTrigger({
@ -91,7 +91,7 @@ function NavigationMenuContent({
data-slot="navigation-menu-content" data-slot="navigation-menu-content"
className={cn( 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", "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 className
)} )}
{...props} {...props}
@ -112,7 +112,7 @@ function NavigationMenuViewport({
<NavigationMenuPrimitive.Viewport <NavigationMenuPrimitive.Viewport
data-slot="navigation-menu-viewport" data-slot="navigation-menu-viewport"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -28,7 +28,7 @@ function PopoverContent({
align={align} align={align}
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -12,7 +12,7 @@ function Progress({
<ProgressPrimitive.Root <ProgressPrimitive.Root
data-slot="progress" data-slot="progress"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -19,7 +19,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger <SelectPrimitive.Trigger
ref={ref} ref={ref}
className={cn( 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 className
)} )}
{...props} {...props}
@ -75,7 +75,7 @@ const SelectContent = React.forwardRef<
<SelectPrimitive.Content <SelectPrimitive.Content
ref={ref} ref={ref}
className={cn( 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" && 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", "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 className
@ -118,7 +118,7 @@ const SelectItem = React.forwardRef<
<SelectPrimitive.Item <SelectPrimitive.Item
ref={ref} ref={ref}
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -31,7 +31,7 @@ const SheetOverlay = React.forwardRef<
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName; SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva( 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: { variants: {
side: { side: {
@ -108,7 +108,7 @@ const SheetTitle = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<SheetPrimitive.Title <SheetPrimitive.Title
ref={ref} 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} {...props}
/> />
)); ));
@ -120,7 +120,7 @@ const SheetDescription = React.forwardRef<
>(({ className, ...props }, ref) => ( >(({ className, ...props }, ref) => (
<SheetPrimitive.Description <SheetPrimitive.Description
ref={ref} ref={ref}
className={cn("text-sm text-muted-foreground", className)} className={cn("text-base text-foreground/70 font-mono", className)}
{...props} {...props}
/> />
)); ));

View File

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

View File

@ -11,7 +11,7 @@ function Switch({
<SwitchPrimitive.Root <SwitchPrimitive.Root
data-slot="switch" data-slot="switch"
className={cn( 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 className
)} )}
{...props} {...props}
@ -19,7 +19,7 @@ function Switch({
<SwitchPrimitive.Thumb <SwitchPrimitive.Thumb
data-slot="switch-thumb" data-slot="switch-thumb"
className={cn( 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> </SwitchPrimitive.Root>

View File

@ -6,11 +6,11 @@ function Table({ className, ...props }: React.ComponentProps<"table">) {
return ( return (
<div <div
data-slot="table-container" data-slot="table-container"
className="relative w-full overflow-x-auto" className="relative w-full overflow-x-auto rounded-sm border border-border"
> >
<table <table
data-slot="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} {...props}
/> />
</div> </div>
@ -21,7 +21,7 @@ function TableHeader({ className, ...props }: React.ComponentProps<"thead">) {
return ( return (
<thead <thead
data-slot="table-header" data-slot="table-header"
className={cn("[&_tr]:border-b", className)} className={cn("bg-muted/50 [&_tr]:border-b border-border", className)}
{...props} {...props}
/> />
); );
@ -55,7 +55,7 @@ function TableRow({ className, ...props }: React.ComponentProps<"tr">) {
<tr <tr
data-slot="table-row" data-slot="table-row"
className={cn( 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 className
)} )}
{...props} {...props}
@ -68,7 +68,7 @@ function TableHead({ className, ...props }: React.ComponentProps<"th">) {
<th <th
data-slot="table-head" data-slot="table-head"
className={cn( 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 className
)} )}
{...props} {...props}
@ -81,7 +81,7 @@ function TableCell({ className, ...props }: React.ComponentProps<"td">) {
<td <td
data-slot="table-cell" data-slot="table-cell"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -24,7 +24,7 @@ function TabsList({
<TabsPrimitive.List <TabsPrimitive.List
data-slot="tabs-list" data-slot="tabs-list"
className={cn( 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 className
)} )}
{...props} {...props}
@ -40,7 +40,7 @@ function TabsTrigger({
<TabsPrimitive.Trigger <TabsPrimitive.Trigger
data-slot="tabs-trigger" data-slot="tabs-trigger"
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -7,7 +7,7 @@ export function Textarea({ className, ...props }: React.ComponentProps<"textarea
<textarea <textarea
data-slot="textarea" data-slot="textarea"
className={cn( 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 className
)} )}
{...props} {...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-variant={variant}
data-size={size} data-size={size}
className={cn( 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 className
)} )}
{...props} {...props}

View File

@ -5,7 +5,7 @@ import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/shared/utils/utils"; import { cn } from "@/shared/utils/utils";
const toggleVariants = cva( 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: { variants: {
variant: { variant: {

View File

@ -46,13 +46,13 @@ function TooltipContent({
data-slot="tooltip-content" data-slot="tooltip-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( 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 className
)} )}
{...props} {...props}
> >
{children} {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.Content>
</TooltipPrimitive.Portal> </TooltipPrimitive.Portal>
); );

View File

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

View File

@ -10,7 +10,7 @@ import { Settings, Database, Terminal } from "lucide-react";
export default function AdminDashboard() { export default function AdminDashboard() {
return ( 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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" /> <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 p-0">
<div className="cyber-card-header"> <div className="cyber-card-header">
<Terminal className="w-5 h-5 text-primary" /> <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> </div>
</div> </div>
{/* Main Content Tabs */} {/* Main Content Tabs */}
<Tabs defaultValue="config" className="w-full relative z-10"> <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 <TabsTrigger
value="config" 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" /> <Settings className="w-4 h-4" />
</TabsTrigger> </TabsTrigger>
<TabsTrigger <TabsTrigger
value="data" 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" /> <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" /> <div className="absolute top-0 left-0 right-0 h-px bg-gradient-to-r from-transparent via-primary/50 to-transparent" />
{/* Header */} {/* 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"> <div className="flex items-center gap-2.5">
{/* Agent type icon with color */} {/* Agent type icon with color */}
<div className={`text-${typeConfig.color}-400`}> <div className={`text-${typeConfig.color}-400`}>
@ -62,22 +62,22 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Agent name */} {/* Agent name */}
<div> <div>
<span className="text-sm font-medium text-white block">{agent.agent_name}</span> <span className="text-sm font-medium text-foreground block">{agent.agent_name}</span>
<span className="text-[10px] text-gray-500 uppercase tracking-wider">{typeConfig.label}</span> <span className="text-xs text-muted-foreground uppercase tracking-wider">{typeConfig.label}</span>
</div> </div>
</div> </div>
{/* Close button */} {/* Close button */}
<button <button
onClick={onClose} 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" /> <X className="w-4 h-4" />
</button> </button>
</div> </div>
{/* Status indicator */} {/* 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="flex items-center gap-2">
<div className="relative"> <div className="relative">
<div className={` <div className={`
@ -86,7 +86,7 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
${agent.status === 'completed' ? 'bg-green-500' : ''} ${agent.status === 'completed' ? 'bg-green-500' : ''}
${agent.status === 'failed' ? 'bg-red-400' : ''} ${agent.status === 'failed' ? 'bg-red-400' : ''}
${agent.status === 'waiting' ? 'bg-yellow-400' : ''} ${agent.status === 'waiting' ? 'bg-yellow-400' : ''}
${agent.status === 'created' ? 'bg-gray-500' : ''} ${agent.status === 'created' ? 'bg-background0' : ''}
`} /> `} />
{isRunning && ( {isRunning && (
<div className="absolute inset-0 w-2.5 h-2.5 rounded-full bg-green-400 animate-ping opacity-30" /> <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 */} {/* Metrics grid */}
<div className="p-3 grid grid-cols-2 gap-2"> <div className="p-3 grid grid-cols-2 gap-2">
{/* Iterations */} {/* 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" /> <Repeat className="w-3.5 h-3.5 text-cyan-400/70" />
<div> <div>
<div className="text-[9px] text-gray-600 uppercase">Iterations</div> <div className="text-xs text-muted-foreground uppercase">Iterations</div>
<div className="text-sm text-white font-mono">{agent.iterations || 0}</div> <div className="text-sm text-foreground font-mono">{agent.iterations || 0}</div>
</div> </div>
</div> </div>
{/* Tool Calls */} {/* 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" /> <Zap className="w-3.5 h-3.5 text-amber-400/70" />
<div> <div>
<div className="text-[9px] text-gray-600 uppercase">Tool Calls</div> <div className="text-xs text-muted-foreground uppercase">Tool Calls</div>
<div className="text-sm text-white font-mono">{agent.tool_calls || 0}</div> <div className="text-sm text-foreground font-mono">{agent.tool_calls || 0}</div>
</div> </div>
</div> </div>
{/* Findings - Only show for Orchestrator (root agent with no parent) */} {/* Findings - Only show for Orchestrator (root agent with no parent) */}
{!agent.parent_agent_id && ( {!agent.parent_agent_id && (
<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">
<Bug className={`w-3.5 h-3.5 ${agent.findings_count > 0 ? 'text-red-400/70' : 'text-gray-500/70'}`} /> <Bug className={`w-3.5 h-3.5 ${agent.findings_count > 0 ? 'text-red-400/70' : 'text-muted-foreground/70'}`} />
<div> <div>
<div className="text-[9px] text-gray-600 uppercase">Findings</div> <div className="text-xs text-muted-foreground uppercase">Findings</div>
<div className={`text-sm font-mono ${agent.findings_count > 0 ? 'text-red-400' : 'text-white'}`}> <div className={`text-sm font-mono ${agent.findings_count > 0 ? 'text-red-400' : 'text-foreground'}`}>
{agent.findings_count} {agent.findings_count}
</div> </div>
</div> </div>
@ -133,13 +133,13 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Duration/Status - Show for sub-agents instead of Findings */} {/* Duration/Status - Show for sub-agents instead of Findings */}
{agent.parent_agent_id && ( {agent.parent_agent_id && (
<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">
<Clock className="w-3.5 h-3.5 text-slate-400/70" /> <Clock className="w-3.5 h-3.5 text-muted-foreground/70" />
<div> <div>
<div className="text-[9px] text-gray-600 uppercase"> <div className="text-xs text-muted-foreground uppercase">
{agent.duration_ms ? "Duration" : "Status"} {agent.duration_ms ? "Duration" : "Status"}
</div> </div>
<div className="text-sm text-white font-mono"> <div className="text-sm text-foreground font-mono">
{agent.duration_ms {agent.duration_ms
? `${(agent.duration_ms / 1000).toFixed(1)}s` ? `${(agent.duration_ms / 1000).toFixed(1)}s`
: (AGENT_STATUS_CONFIG[agent.status]?.text || agent.status) : (AGENT_STATUS_CONFIG[agent.status]?.text || agent.status)
@ -150,11 +150,11 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
)} )}
{/* Tokens */} {/* 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" /> <FileCode className="w-3.5 h-3.5 text-purple-400/70" />
<div> <div>
<div className="text-[9px] text-gray-600 uppercase">Tokens</div> <div className="text-xs text-muted-foreground uppercase">Tokens</div>
<div className="text-sm text-white font-mono"> <div className="text-sm text-foreground font-mono">
{((agent.tokens_used || 0) / 1000).toFixed(1)}k {((agent.tokens_used || 0) / 1000).toFixed(1)}k
</div> </div>
</div> </div>
@ -164,12 +164,12 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Task description */} {/* Task description */}
{agent.task_description && ( {agent.task_description && (
<div className="px-3 pb-3"> <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"> <div className="flex items-center gap-1.5 mb-1.5">
<Clock className="w-3 h-3 text-gray-500" /> <Clock className="w-3 h-3 text-muted-foreground" />
<span className="text-[9px] text-gray-500 uppercase tracking-wider">Current Task</span> <span className="text-xs text-muted-foreground uppercase tracking-wider">Current Task</span>
</div> </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} {agent.task_description}
</p> </p>
</div> </div>
@ -179,7 +179,7 @@ export const AgentDetailPanel = memo(function AgentDetailPanel({ agentId, treeNo
{/* Sub-agents indicator */} {/* Sub-agents indicator */}
{agent.children && agent.children.length > 0 && ( {agent.children && agent.children.length > 0 && (
<div className="px-3 pb-3"> <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" /> <Network className="w-3 h-3" />
<span className="uppercase tracking-wider"> <span className="uppercase tracking-wider">
{agent.children.length} Sub-agent{agent.children.length > 1 ? 's' : ''} {agent.children.length} Sub-agent{agent.children.length > 1 ? 's' : ''}

View File

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

View File

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

View File

@ -24,8 +24,8 @@ const STATUS_CONFIG: Record<ConnectionState, {
disconnected: { disconnected: {
icon: WifiOff, icon: WifiOff,
label: 'Disconnected', label: 'Disconnected',
color: 'text-gray-400', color: 'text-muted-foreground',
bgColor: 'bg-gray-400/10', bgColor: 'bg-muted/30',
}, },
connecting: { connecting: {
icon: RefreshCw, icon: RefreshCw,
@ -67,7 +67,7 @@ export function ConnectionStatus({
return ( return (
<div className={cn('flex items-center gap-1.5', className)}> <div className={cn('flex items-center gap-1.5', className)}>
<div className={cn( <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.bgColor,
config.color config.color
)}> )}>

View File

@ -18,21 +18,21 @@ export function Header({
onNewAudit onNewAudit
}: HeaderProps) { }: HeaderProps) {
return ( 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 */} {/* 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" /> <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 */} {/* Left side - Brand and task info */}
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
{/* Logo section */} {/* 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"> <div className="relative">
<Cpu className="w-5 h-5 text-primary" /> <Cpu className="w-5 h-5 text-primary" />
{isRunning && ( {isRunning && (
<span className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-green-400 rounded-full animate-pulse" /> <span className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-green-400 rounded-full animate-pulse" />
)} )}
</div> </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> DEEP<span className="text-primary">AUDIT</span>
</span> </span>
</div> </div>
@ -40,11 +40,11 @@ export function Header({
{/* Task info */} {/* Task info */}
{task && ( {task && (
<div className="flex items-center gap-3"> <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" /> <Radio className="w-3 h-3" />
<span className="text-xs font-mono uppercase tracking-wider">Task</span> <span className="text-xs font-mono uppercase tracking-wider">Task</span>
</div> </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)} {task.name || task.id.slice(0, 8)}
</span> </span>
<StatusBadge status={task.status} /> <StatusBadge status={task.status} />
@ -76,7 +76,7 @@ export function Header({
</Button> </Button>
)} )}
<div className="h-6 w-px bg-gray-800/50 mx-1" /> <div className="h-6 w-px bg-muted mx-1" />
<Button <Button
variant="ghost" variant="ghost"

View File

@ -93,8 +93,8 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
<div className={` <div className={`
relative rounded border-l-2 overflow-hidden relative rounded border-l-2 overflow-hidden
${config.borderColor} ${config.borderColor}
${isExpanded ? 'bg-gray-900/60' : 'bg-gray-900/30'} ${isExpanded ? 'bg-card/60' : 'bg-muted/50'}
${isCollapsible ? 'hover:bg-gray-900/50' : ''} ${isCollapsible ? 'hover:bg-muted' : ''}
${isFinding ? 'border-r border-r-red-900/30' : ''} ${isFinding ? 'border-r border-r-red-900/30' : ''}
${isError ? 'border-r border-r-red-900/30' : ''} ${isError ? 'border-r border-r-red-900/30' : ''}
transition-all duration-200 transition-all duration-200
@ -120,35 +120,35 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Type label */} {/* Type label */}
<span className={` <span className={`
text-[9px] font-mono font-bold uppercase tracking-wider px-1.5 py-0.5 rounded text-sm font-mono font-bold uppercase tracking-wider px-2.5 py-1 rounded
${isThinking ? 'bg-violet-500/25 text-violet-300' : ''} ${isThinking ? 'bg-violet-500/30 text-violet-700 dark:text-violet-300' : ''}
${isTool ? 'bg-amber-500/25 text-amber-300' : ''} ${isTool ? 'bg-amber-500/30 text-amber-700 dark:text-amber-300' : ''}
${isFinding ? 'bg-rose-500/25 text-rose-300' : ''} ${isFinding ? 'bg-rose-500/30 text-rose-700 dark:text-rose-300' : ''}
${isError ? 'bg-red-500/25 text-red-300' : ''} ${isError ? 'bg-red-500/30 text-red-700 dark:text-red-300' : ''}
${isInfo ? 'bg-slate-500/25 text-slate-300' : ''} ${isInfo ? 'bg-muted text-foreground' : ''}
${isProgress ? 'bg-cyan-500/25 text-cyan-300' : ''} ${isProgress ? 'bg-cyan-500/30 text-cyan-700 dark:text-cyan-300' : ''}
${item.type === 'dispatch' ? 'bg-sky-500/25 text-sky-300' : ''} ${item.type === 'dispatch' ? 'bg-sky-500/30 text-sky-700 dark:text-sky-300' : ''}
${item.type === 'phase' ? 'bg-teal-500/25 text-teal-300' : ''} ${item.type === 'phase' ? 'bg-teal-500/30 text-teal-700 dark:text-teal-300' : ''}
${item.type === 'user' ? 'bg-indigo-500/25 text-indigo-300' : ''} ${item.type === 'user' ? 'bg-indigo-500/30 text-indigo-700 dark:text-indigo-300' : ''}
flex-shrink-0 flex-shrink-0
`}> `}>
{LOG_TYPE_LABELS[item.type] || 'LOG'} {LOG_TYPE_LABELS[item.type] || 'LOG'}
</span> </span>
{/* Timestamp */} {/* 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} {item.time}
</span> </span>
{/* Separator */} {/* 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 */} {/* Status icon for info messages */}
{statusIcon && <span className="flex-shrink-0">{statusIcon}</span>} {statusIcon && <span className="flex-shrink-0">{statusIcon}</span>}
{/* Title - for non-thinking types */} {/* Title - for non-thinking types */}
{!isThinking && ( {!isThinking && (
<span className="text-sm text-gray-300 truncate flex-1"> <span className="text-base text-foreground font-medium truncate flex-1">
{formattedTitle} {formattedTitle}
</span> </span>
)} )}
@ -162,7 +162,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.tool?.status === 'running' && ( {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"> <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" /> <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> </div>
)} )}
@ -176,7 +176,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.agentName && ( {item.agentName && (
<Badge <Badge
variant="outline" 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} {item.agentName}
</Badge> </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"> <div className="flex items-center gap-2 flex-shrink-0 ml-auto">
{/* Duration badge */} {/* Duration badge */}
{item.tool?.duration !== undefined && ( {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 {item.tool.duration}ms
</span> </span>
)} )}
@ -195,7 +195,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{item.severity && ( {item.severity && (
<Badge <Badge
className={` 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} ${SEVERITY_COLORS[item.severity] || SEVERITY_COLORS.info}
`} `}
> >
@ -205,11 +205,11 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Expand indicator */} {/* Expand indicator */}
{isCollapsible && ( {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 ? ( {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> </div>
)} )}
@ -220,7 +220,7 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{isThinking && item.content && ( {isThinking && item.content && (
<div className="mt-2.5 relative"> <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="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} {item.content}
</div> </div>
</div> </div>
@ -229,24 +229,24 @@ export const LogEntry = memo(function LogEntry({ item, isExpanded, onToggle }: L
{/* Collapsible content */} {/* Collapsible content */}
{!isThinking && showContent && item.content && ( {!isThinking && showContent && item.content && (
<div className="mt-2.5 overflow-hidden"> <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 */} {/* 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"> <div className="flex items-center gap-2">
<Square className="w-2.5 h-2.5 text-gray-600" /> <Square className="w-2.5 h-2.5 text-muted-foreground" />
<span className="text-[9px] text-gray-500 font-mono uppercase tracking-wider"> <span className="text-xs text-muted-foreground font-mono uppercase tracking-wider">
{isTool ? 'Output' : 'Details'} {isTool ? 'Output' : 'Details'}
</span> </span>
</div> </div>
{item.tool?.status === 'completed' && ( {item.tool?.status === 'completed' && (
<div className="flex items-center gap-1"> <div className="flex items-center gap-1">
<CheckCircle2 className="w-3 h-3 text-green-500/70" /> <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>
)} )}
</div> </div>
{/* Content */} {/* 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} {item.content}
</pre> </pre>
</div> </div>

View File

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

View File

@ -151,7 +151,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
}; };
return ( 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 */} {/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20"> <div className="absolute inset-0 pointer-events-none z-20">
<div <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)" }} 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-primary">DEEP</span>
<span className="text-white">AUDIT</span> <span className="text-foreground">AUDIT</span>
</div> </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 Autonomous Security Agent
</div> </div>
</div> </div>
{/* Terminal window */} {/* Terminal window */}
<div <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} onClick={handleTerminalClick}
> >
{/* Terminal header */} {/* 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="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-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-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 className="w-3 h-3 rounded-full bg-green-500/80" />
</div> </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 deepaudit@terminal
</span> </span>
</div> </div>
@ -228,7 +228,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
className={`mb-1 ${ className={`mb-1 ${
log.includes("[READY]") ? "text-green-400" : log.includes("[READY]") ? "text-green-400" :
log.includes("[INIT]") ? "text-primary" : log.includes("[INIT]") ? "text-primary" :
"text-gray-500" "text-muted-foreground"
}`} }`}
style={{ style={{
animation: "fadeSlideIn 0.2s ease-out", animation: "fadeSlideIn 0.2s ease-out",
@ -236,17 +236,17 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
animationDelay: `${i * 0.05}s` animationDelay: `${i * 0.05}s`
}} }}
> >
<span className="text-gray-600 mr-2">&gt;</span> <span className="text-muted-foreground mr-2">&gt;</span>
{log} {log}
</div> </div>
))} ))}
{/* Welcome message */} {/* Welcome message */}
{bootComplete && ( {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-primary mb-1">Welcome to DeepAudit Agent Terminal</div>
<div className="text-gray-500 text-xs"> <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-gray-400">'help'</span> for commands. 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>
</div> </div>
)} )}
@ -254,13 +254,13 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
{/* Command history */} {/* Command history */}
{commandHistory.map((entry, i) => ( {commandHistory.map((entry, i) => (
<div key={`cmd-${i}`} className="mb-2"> <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 className="text-emerald-500">$</span>
<span>{entry.input}</span> <span>{entry.input}</span>
</div> </div>
{entry.output && ( {entry.output && (
<div className={`ml-4 mt-1 whitespace-pre-wrap text-xs ${ <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} {entry.output}
</div> </div>
@ -270,7 +270,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
{/* Current input line */} {/* Current input line */}
{bootComplete && ( {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> <span className="text-emerald-500">$</span>
<div className="flex-1 relative"> <div className="flex-1 relative">
<input <input
@ -285,7 +285,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
autoComplete="off" autoComplete="off"
autoFocus autoFocus
/> />
<span className="text-gray-200">{currentInput}</span> <span className="text-foreground">{currentInput}</span>
<span <span
className={`inline-block w-2 h-4 bg-emerald-400 ml-0.5 align-middle transition-opacity ${ className={`inline-block w-2 h-4 bg-emerald-400 ml-0.5 align-middle transition-opacity ${
cursorBlink ? "opacity-100" : "opacity-0" 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={`mt-4 text-center transition-all duration-500 ${bootComplete ? "opacity-100" : "opacity-0"}`}>
<div className="flex items-center justify-center gap-3"> <div className="flex items-center justify-center gap-3">
<div className="h-px w-8 bg-gradient-to-r from-transparent to-gray-700" /> <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 className="h-px w-8 bg-gradient-to-l from-transparent to-gray-700" />
</div> </div>
</div> </div>
@ -309,18 +309,18 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
</div> </div>
{/* Corner decorations */} {/* 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>SYS.VERSION: 3.0.0</div>
<div>MODE: INTERACTIVE</div> <div>MODE: INTERACTIVE</div>
</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>MEM: 16384MB</div>
<div>STATUS: READY</div> <div>STATUS: READY</div>
</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 DEEPAUDIT_AGENT_v3
</div> </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]} {new Date().toISOString().split("T")[0]}
</div> </div>

View File

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

View File

@ -24,48 +24,48 @@ const STATUS_CONFIG: Record<string, {
pending: { pending: {
icon: <Clock className="w-3.5 h-3.5" />, icon: <Clock className="w-3.5 h-3.5" />,
iconSm: <Clock className="w-3 h-3" />, iconSm: <Clock className="w-3 h-3" />,
bg: "bg-gray-800/80 border-gray-600/50", bg: "bg-muted border-border",
text: "text-gray-300", text: "text-foreground",
label: "PENDING", label: "PENDING",
}, },
running: { running: {
icon: <Loader2 className="w-3.5 h-3.5 animate-spin" />, icon: <Loader2 className="w-3.5 h-3.5 animate-spin" />,
iconSm: <Loader2 className="w-3 h-3 animate-spin" />, iconSm: <Loader2 className="w-3 h-3 animate-spin" />,
bg: "bg-green-950/80 border-green-500/50", bg: "bg-green-100 dark:bg-green-950/80 border-green-500/50",
text: "text-green-400", text: "text-green-700 dark:text-green-400",
label: "RUNNING", 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, animate: true,
}, },
completed: { completed: {
icon: <CheckCircle2 className="w-3.5 h-3.5" />, icon: <CheckCircle2 className="w-3.5 h-3.5" />,
iconSm: <CheckCircle2 className="w-3 h-3" />, iconSm: <CheckCircle2 className="w-3 h-3" />,
bg: "bg-green-950/60 border-green-600/50", bg: "bg-green-100 dark:bg-green-950/60 border-green-600/50",
text: "text-green-400", text: "text-green-700 dark:text-green-400",
label: "COMPLETED", label: "COMPLETED",
}, },
failed: { failed: {
icon: <XCircle className="w-3.5 h-3.5" />, icon: <XCircle className="w-3.5 h-3.5" />,
iconSm: <XCircle className="w-3 h-3" />, iconSm: <XCircle className="w-3 h-3" />,
bg: "bg-red-950/60 border-red-600/50", bg: "bg-red-100 dark:bg-red-950/60 border-red-600/50",
text: "text-red-400", text: "text-red-700 dark:text-red-400",
label: "FAILED", 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: { cancelled: {
icon: <Square className="w-3.5 h-3.5" />, icon: <Square className="w-3.5 h-3.5" />,
iconSm: <Square className="w-3 h-3" />, iconSm: <Square className="w-3 h-3" />,
bg: "bg-yellow-950/60 border-yellow-600/50", bg: "bg-yellow-100 dark:bg-yellow-950/60 border-yellow-600/50",
text: "text-yellow-400", text: "text-yellow-700 dark:text-yellow-400",
label: "CANCELLED", label: "CANCELLED",
}, },
error: { error: {
icon: <AlertCircle className="w-3.5 h-3.5" />, icon: <AlertCircle className="w-3.5 h-3.5" />,
iconSm: <AlertCircle className="w-3 h-3" />, iconSm: <AlertCircle className="w-3 h-3" />,
bg: "bg-red-950/60 border-red-600/50", bg: "bg-red-100 dark:bg-red-950/60 border-red-600/50",
text: "text-red-400", text: "text-red-700 dark:text-red-400",
label: "ERROR", 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.bg}
${config.text} ${config.text}
${config.glow || ''} ${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} {isSmall ? config.iconSm : config.icon}

View File

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

View File

@ -757,12 +757,12 @@ function AgentAuditPageContent() {
if (isLoading && !task) { if (isLoading && !task) {
return ( 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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid opacity-30" /> <div className="absolute inset-0 cyber-grid opacity-30" />
{/* Vignette */} {/* Vignette */}
<div className="absolute inset-0 vignette pointer-events-none" /> <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" /> <Loader2 className="w-5 h-5 animate-spin text-primary" />
<span className="font-mono text-sm tracking-wide">LOADING AUDIT TASK...</span> <span className="font-mono text-sm tracking-wide">LOADING AUDIT TASK...</span>
</div> </div>
@ -771,7 +771,7 @@ function AgentAuditPageContent() {
} }
return ( 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 */} {/* Subtle grid background */}
<div className="absolute inset-0 cyber-grid-subtle opacity-40 pointer-events-none" /> <div className="absolute inset-0 cyber-grid-subtle opacity-40 pointer-events-none" />
{/* Scanline effect */} {/* Scanline effect */}
@ -790,24 +790,24 @@ function AgentAuditPageContent() {
{/* Main content */} {/* Main content */}
<div className="flex-1 flex overflow-hidden relative"> <div className="flex-1 flex overflow-hidden relative">
{/* Left Panel - Activity Log */} {/* 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 */} {/* 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-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-[#8a95a5]"> <div className="flex items-center gap-3 text-xs text-muted-foreground">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Terminal className="w-4 h-4 text-[#5a6577]" /> <Terminal className="w-4 h-4 text-muted-foreground" />
<span className="uppercase font-bold tracking-[0.15em] text-[#d0d8e8]">Activity Log</span> <span className="uppercase font-bold tracking-[0.15em] text-foreground">Activity Log</span>
</div> </div>
{isConnected && ( {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="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="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-[#3dd68c] shadow-[0_0_8px_rgba(61,214,140,0.5)]"></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>
<span className="text-[10px] font-mono uppercase tracking-wider">Live</span> <span className="text-xs font-mono uppercase tracking-wider">Live</span>
</div> </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}` : ''} {filteredLogs.length}{!showAllLogs && logs.length !== filteredLogs.length ? ` / ${logs.length}` : ''}
</Badge> </Badge>
</div> </div>
@ -815,11 +815,11 @@ function AgentAuditPageContent() {
<button <button
onClick={() => setAutoScroll(!isAutoScroll)} onClick={() => setAutoScroll(!isAutoScroll)}
className={` 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 transition-all duration-200
${isAutoScroll ${isAutoScroll
? 'bg-primary/15 text-primary border border-primary/40 shadow-[0_0_10px_rgba(255,95,31,0.15)]' ? '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> </div>
{/* Log content */} {/* 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 */} {/* Filter indicator */}
{selectedAgentId && !showAllLogs && ( {selectedAgentId && !showAllLogs && (
<div className="mb-3 px-3 py-2 bg-primary/8 border border-primary/25 rounded flex items-center justify-between"> <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> </div>
<button <button
onClick={() => selectAgent(null)} 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 Clear
</button> </button>
@ -849,10 +849,10 @@ function AgentAuditPageContent() {
{/* Logs */} {/* Logs */}
{filteredLogs.length === 0 ? ( {filteredLogs.length === 0 ? (
<div className="h-full flex items-center justify-center"> <div className="h-full flex items-center justify-center">
<div className="text-center text-[#4a5565]"> <div className="text-center text-muted-foreground">
{isRunning ? ( {isRunning ? (
<div className="flex flex-col items-center gap-3"> <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"> <span className="text-sm font-mono tracking-wide">
{selectedAgentId && !showAllLogs {selectedAgentId && !showAllLogs
? 'WAITING FOR ACTIVITY FROM SELECTED AGENT...' ? 'WAITING FOR ACTIVITY FROM SELECTED AGENT...'
@ -885,36 +885,36 @@ function AgentAuditPageContent() {
{/* Status bar */} {/* Status bar */}
{task && ( {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> <span>
{isRunning ? ( {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="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="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-[#3dd68c] shadow-[0_0_6px_rgba(61,214,140,0.5)]"></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>
<span className="font-mono tracking-wide">{statusVerb}{'.'.repeat(statusDots)}</span> <span className="font-mono tracking-wide">{statusVerb}{'.'.repeat(statusDots)}</span>
</span> </span>
) : isComplete ? ( ) : 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> </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>
<span className="text-primary text-glow-primary">{task.progress_percentage?.toFixed(0) || 0}</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>
<span className="text-[#2a3545]"></span> <span className="text-border"></span>
<span> <span>
<span className="text-[#a8b0c0]">{task.analyzed_files}</span> <span className="text-foreground">{task.analyzed_files}</span>
<span className="text-[#4a5565]">/{task.total_files} files</span> <span className="text-muted-foreground">/{task.total_files} files</span>
</span> </span>
<span className="text-[#2a3545]"></span> <span className="text-border"></span>
<span> <span>
<span className="text-[#a8b0c0]">{task.tool_calls_count || 0}</span> <span className="text-foreground">{task.tool_calls_count || 0}</span>
<span className="text-[#4a5565]"> tools</span> <span className="text-muted-foreground"> tools</span>
</span> </span>
</div> </div>
</div> </div>
@ -922,16 +922,16 @@ function AgentAuditPageContent() {
</div> </div>
{/* Right Panel - Agent Tree + Stats */} {/* 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 */} {/* 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 */} {/* 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-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-[#8a95a5]"> <div className="flex items-center gap-2 text-xs text-muted-foreground">
<Bot className="w-4 h-4 text-[#5a6577]" /> <Bot className="w-4 h-4 text-muted-foreground" />
<span className="uppercase font-bold tracking-[0.15em] text-[#d0d8e8]">Agent Tree</span> <span className="uppercase font-bold tracking-[0.15em] text-foreground">Agent Tree</span>
{agentTree && ( {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} {agentTree.total_agents}
</Badge> </Badge>
)} )}
@ -940,25 +940,25 @@ function AgentAuditPageContent() {
{selectedAgentId && !showAllLogs && ( {selectedAgentId && !showAllLogs && (
<button <button
onClick={() => selectAgent(null)} 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 Show All
</button> </button>
)} )}
{agentTree && agentTree.running_agents > 0 && ( {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="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="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-[#3dd68c] shadow-[0_0_6px_rgba(61,214,140,0.5)]"></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>
<span className="text-[10px] font-mono">{agentTree.running_agents}</span> <span className="text-xs font-mono">{agentTree.running_agents}</span>
</div> </div>
)} )}
</div> </div>
</div> </div>
{/* Tree content */} {/* 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.length > 0 ? (
treeNodes.map(node => ( treeNodes.map(node => (
<AgentTreeNodeItem <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 ? ( {isRunning ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Loader2 className="w-3 h-3 animate-spin" /> <Loader2 className="w-3 h-3 animate-spin" />
@ -984,7 +984,7 @@ function AgentAuditPageContent() {
</div> </div>
{/* Bottom section - Details + Stats */} {/* 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 */} {/* Agent detail panel */}
{selectedAgentId && !showAllLogs && ( {selectedAgentId && !showAllLogs && (
<AgentDetailPanel <AgentDetailPanel

View File

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

View File

@ -239,8 +239,8 @@ export default function AuditTasks() {
case 'completed': return <CheckCircle className="w-4 h-4 text-emerald-400" />; 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 'running': return <Activity className="w-4 h-4 text-sky-400" />;
case 'failed': return <AlertTriangle className="w-4 h-4 text-rose-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" />; case 'cancelled': return <XCircle className="w-4 h-4 text-muted-foreground" />;
default: return <Clock className="w-4 h-4 text-gray-400" />; 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="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4"> <div className="text-center space-y-4">
<div className="loading-spinner mx-auto" /> <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>
</div> </div>
); );
} }
return ( 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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" /> <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 transition-all duration-300 border-2 overflow-hidden
${activeTab === "agent" ${activeTab === "agent"
? "bg-gradient-to-br from-primary/20 via-primary/10 to-transparent border-primary shadow-lg shadow-primary/20" ? "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 transition-all duration-300
${activeTab === "agent" ${activeTab === "agent"
? "bg-primary/30 shadow-lg shadow-primary/30" ? "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>
{/* 内容区域 */} {/* 内容区域 */}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1"> <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 Agent
</h3> </h3>
{agentStats.running > 0 && ( {agentStats.running > 0 && (
@ -345,20 +345,20 @@ export default function AuditTasks() {
</span> </span>
)} )}
{activeTab === "agent" && ( {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> </span>
)} )}
</div> </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 LLM Agent
</p> </p>
{/* 统计数据 */} {/* 统计数据 */}
<div className="flex items-center gap-4 mt-3 text-xs"> <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={`transition-colors duration-300 ${activeTab === "agent" ? "text-muted-foreground" : "text-muted-foreground"}`}>
<span className="font-bold text-white">{agentStats.total}</span> <span className="font-bold text-foreground">{agentStats.total}</span>
</span> </span>
<span className="text-emerald-400"> <span className="text-emerald-400">
<CheckCircle className="w-3 h-3 inline mr-1" /> <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 transition-all duration-300 border-2 overflow-hidden
${activeTab === "regular" ${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-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 transition-all duration-300
${activeTab === "regular" ${activeTab === "regular"
? "bg-cyan-500/30 shadow-lg shadow-cyan-500/30" ? "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>
{/* 内容区域 */} {/* 内容区域 */}
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1"> <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> </h3>
{regularStats.running > 0 && ( {regularStats.running > 0 && (
@ -422,20 +422,20 @@ export default function AuditTasks() {
</span> </span>
)} )}
{activeTab === "regular" && ( {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> </span>
)} )}
</div> </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> </p>
{/* 统计数据 */} {/* 统计数据 */}
<div className="flex items-center gap-4 mt-3 text-xs"> <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={`transition-colors duration-300 ${activeTab === "regular" ? "text-muted-foreground" : "text-muted-foreground"}`}>
<span className="font-bold text-white">{regularStats.total}</span> <span className="font-bold text-foreground">{regularStats.total}</span>
</span> </span>
<span className="text-emerald-400"> <span className="text-emerald-400">
<CheckCircle className="w-3 h-3 inline mr-1" /> <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="cyber-card p-4 relative z-10">
<div className="flex flex-col md:flex-row items-center gap-4"> <div className="flex flex-col md:flex-row items-center gap-4">
<div className="flex-1 relative w-full"> <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 <Input
placeholder={activeTab === "agent" ? "搜索Agent任务名称..." : "搜索项目名称或任务类型..."} placeholder={activeTab === "agent" ? "搜索Agent任务名称..." : "搜索项目名称或任务类型..."}
value={searchTerm} value={searchTerm}
@ -544,21 +544,21 @@ export default function AuditTasks() {
<Button <Button
size="sm" size="sm"
onClick={() => setStatusFilter("running")} 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>
<Button <Button
size="sm" size="sm"
onClick={() => setStatusFilter("completed")} 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>
<Button <Button
size="sm" size="sm"
onClick={() => setStatusFilter("failed")} 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> </Button>
@ -574,24 +574,24 @@ export default function AuditTasks() {
{filteredAgentTasks.map((task) => ( {filteredAgentTasks.map((task) => (
<div key={task.id} className="cyber-card p-6"> <div key={task.id} className="cyber-card p-6">
{/* Task Header */} {/* 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="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' : <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 === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-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' : <Bot className={`w-6 h-6 ${task.status === 'completed' ? 'text-emerald-400' :
task.status === 'running' ? 'text-sky-400' : task.status === 'running' ? 'text-sky-400' :
task.status === 'failed' ? 'text-rose-400' : task.status === 'failed' ? 'text-rose-400' :
'text-gray-400' 'text-muted-foreground'
}`} /> }`} />
</div> </div>
<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审计任务'} {task.name || 'Agent审计任务'}
</h3> </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} {task.current_phase || task.task_type}
</p> </p>
</div> </div>
@ -611,25 +611,25 @@ export default function AuditTasks() {
{/* Stats Grid */} {/* Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-4 font-mono"> <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"> <div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-white">{task.total_files}</p> <p className="text-2xl font-bold text-foreground">{task.total_files}</p>
<p className="text-xs text-gray-500 uppercase"></p> <p className="text-xs text-muted-foreground uppercase"></p>
</div> </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-white">{task.analyzed_files}</p> <p className="text-2xl font-bold text-foreground">{task.analyzed_files}</p>
<p className="text-xs text-gray-500 uppercase"></p> <p className="text-xs text-muted-foreground uppercase"></p>
</div> </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-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>
<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-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>
<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-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>
</div> </div>
@ -654,25 +654,25 @@ export default function AuditTasks() {
{/* Progress Bar */} {/* Progress Bar */}
<div className="mb-4 font-mono"> <div className="mb-4 font-mono">
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<span className="text-sm font-bold text-gray-400 uppercase"></span> <span className="text-sm font-bold text-muted-foreground uppercase"></span>
<span className="text-sm text-gray-500"> <span className="text-sm text-muted-foreground">
{task.analyzed_files || 0} / {task.total_files || 0} {task.analyzed_files || 0} / {task.total_files || 0}
</span> </span>
</div> </div>
<Progress <Progress
value={task.progress_percentage || 0} 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"> <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)}% {(task.progress_percentage || 0).toFixed(0)}%
</span> </span>
</div> </div>
</div> </div>
{/* Task Footer */} {/* Task Footer */}
<div className="flex items-center justify-between pt-4 border-t border-gray-800"> <div className="flex items-center justify-between pt-4 border-t border-border">
<div className="flex items-center space-x-6 text-sm text-gray-500 font-mono"> <div className="flex items-center space-x-6 text-sm text-muted-foreground font-mono">
<div className="flex items-center"> <div className="flex items-center">
<Calendar className="w-4 h-4 mr-2" /> <Calendar className="w-4 h-4 mr-2" />
{formatDate(task.created_at)} {formatDate(task.created_at)}
@ -684,7 +684,7 @@ export default function AuditTasks() {
</div> </div>
)} )}
{task.tokens_used > 0 && ( {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> <span>{task.tokens_used.toLocaleString()} tokens</span>
</div> </div>
)} )}
@ -695,14 +695,14 @@ export default function AuditTasks() {
<> <>
{/* 🔥 查看终端实时流按钮 */} {/* 🔥 查看终端实时流按钮 */}
<Link to={`/agent-audit/${task.id}`}> <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" /> <Terminal className="w-4 h-4 mr-2" />
</Button> </Button>
</Link> </Link>
<Button <Button
size="sm" 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)} onClick={() => handleCancelAgentTask(task.id)}
disabled={cancellingAgentTaskId === task.id} disabled={cancellingAgentTaskId === task.id}
> >
@ -725,11 +725,11 @@ export default function AuditTasks() {
</div> </div>
) : ( ) : (
<div className="cyber-card p-16 text-center relative z-10 border-dashed"> <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" /> <Bot className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-xl font-bold text-gray-300 mb-2 uppercase"> <h3 className="text-xl font-bold text-foreground mb-2 uppercase">
{searchTerm || statusFilter !== "all" ? '未找到匹配的Agent任务' : '暂无Agent审计任务'} {searchTerm || statusFilter !== "all" ? '未找到匹配的Agent任务' : '暂无Agent审计任务'}
</h3> </h3>
<p className="text-gray-500 mb-6 font-mono"> <p className="text-muted-foreground mb-6 font-mono">
{searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个Agent审计任务开始智能安全审计'} {searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个Agent审计任务开始智能安全审计'}
</p> </p>
{!searchTerm && statusFilter === "all" && ( {!searchTerm && statusFilter === "all" && (
@ -751,20 +751,20 @@ export default function AuditTasks() {
{filteredTasks.map((task) => ( {filteredTasks.map((task) => (
<div key={task.id} className="cyber-card p-6"> <div key={task.id} className="cyber-card p-6">
{/* Task Header */} {/* 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="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' : <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 === 'running' ? 'bg-sky-500/20' :
task.status === 'failed' ? 'bg-rose-500/20' : task.status === 'failed' ? 'bg-rose-500/20' :
'bg-gray-800/50' 'bg-muted'
}`}> }`}>
{getStatusIcon(task.status)} {getStatusIcon(task.status)}
</div> </div>
<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 || '未知项目'} {task.project?.name || '未知项目'}
</h3> </h3>
<p className="text-sm text-gray-500 font-mono"> <p className="text-sm text-muted-foreground font-mono">
{task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'} {task.task_type === 'repository' ? '仓库审计任务' : '即时分析任务'}
</p> </p>
</div> </div>
@ -774,46 +774,46 @@ export default function AuditTasks() {
{/* Stats Grid */} {/* Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-4 font-mono"> <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"> <div className="text-center p-3 bg-muted rounded-lg border border-border">
<p className="text-2xl font-bold text-white">{task.total_files}</p> <p className="text-2xl font-bold text-foreground">{task.total_files}</p>
<p className="text-xs text-gray-500 uppercase"></p> <p className="text-xs text-muted-foreground uppercase"></p>
</div> </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-white">{task.total_lines.toLocaleString()}</p> <p className="text-2xl font-bold text-foreground">{task.total_lines.toLocaleString()}</p>
<p className="text-xs text-gray-500 uppercase"></p> <p className="text-xs text-muted-foreground uppercase"></p>
</div> </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-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>
<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-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>
</div> </div>
{/* Progress Bar */} {/* Progress Bar */}
<div className="mb-4 font-mono"> <div className="mb-4 font-mono">
<div className="flex items-center justify-between mb-2"> <div className="flex items-center justify-between mb-2">
<span className="text-sm font-bold text-gray-400 uppercase"></span> <span className="text-sm font-bold text-muted-foreground uppercase"></span>
<span className="text-sm text-gray-500"> <span className="text-sm text-muted-foreground">
{task.scanned_files || 0} / {task.total_files || 0} {task.scanned_files || 0} / {task.total_files || 0}
</span> </span>
</div> </div>
<Progress <Progress
value={calculateTaskProgress(task.scanned_files, task.total_files)} 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"> <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)}% {calculateTaskProgress(task.scanned_files, task.total_files)}%
</span> </span>
</div> </div>
</div> </div>
{/* Task Footer */} {/* Task Footer */}
<div className="flex items-center justify-between pt-4 border-t border-gray-800"> <div className="flex items-center justify-between pt-4 border-t border-border">
<div className="flex items-center space-x-6 text-sm text-gray-500 font-mono"> <div className="flex items-center space-x-6 text-sm text-muted-foreground font-mono">
<div className="flex items-center"> <div className="flex items-center">
<Calendar className="w-4 h-4 mr-2" /> <Calendar className="w-4 h-4 mr-2" />
{formatDate(task.created_at)} {formatDate(task.created_at)}
@ -830,7 +830,7 @@ export default function AuditTasks() {
{(task.status === 'running' || task.status === 'pending') && ( {(task.status === 'running' || task.status === 'pending') && (
<Button <Button
size="sm" 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)} onClick={() => handleCancelTask(task.id)}
disabled={cancellingTaskId === task.id} disabled={cancellingTaskId === task.id}
> >
@ -859,11 +859,11 @@ export default function AuditTasks() {
</div> </div>
) : ( ) : (
<div className="cyber-card p-16 text-center relative z-10 border-dashed"> <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" /> <Activity className="w-16 h-16 text-muted-foreground mx-auto mb-4" />
<h3 className="text-xl font-bold text-gray-300 mb-2 uppercase"> <h3 className="text-xl font-bold text-foreground mb-2 uppercase">
{searchTerm || statusFilter !== "all" ? '未找到匹配的任务' : '暂无审计任务'} {searchTerm || statusFilter !== "all" ? '未找到匹配的任务' : '暂无审计任务'}
</h3> </h3>
<p className="text-gray-500 mb-6 font-mono"> <p className="text-muted-foreground mb-6 font-mono">
{searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个审计任务开始代码质量分析'} {searchTerm || statusFilter !== "all" ? '尝试调整搜索条件或筛选器' : '创建第一个审计任务开始代码质量分析'}
</p> </p>
{!searchTerm && statusFilter === "all" && ( {!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="flex items-center justify-center min-h-[60vh]">
<div className="text-center space-y-4"> <div className="text-center space-y-4">
<div className="loading-spinner mx-auto" /> <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>
</div> </div>
); );
} }
return ( 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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" /> <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="relative z-10 cyber-card p-4 border-amber-500/30 bg-amber-500/5">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<AlertTriangle className="w-5 h-5 text-amber-400 mt-0.5" /> <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> 使<span className="text-amber-400 font-bold"></span>
<Link to="/admin" className="ml-2 text-primary font-bold hover:underline"> <Link to="/admin" className="ml-2 text-primary font-bold hover:underline">
@ -200,8 +200,8 @@ export default function Dashboard() {
<div> <div>
<p className="stat-label"></p> <p className="stat-label"></p>
<p className="stat-value">{stats?.total_projects || 0}</p> <p className="stat-value">{stats?.total_projects || 0}</p>
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1"> <p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" /> <span className="w-2 h-2 rounded-full bg-emerald-400" />
: {stats?.active_projects || 0} : {stats?.active_projects || 0}
</p> </p>
</div> </div>
@ -217,8 +217,8 @@ export default function Dashboard() {
<div> <div>
<p className="stat-label"></p> <p className="stat-label"></p>
<p className="stat-value">{stats?.total_tasks || 0}</p> <p className="stat-value">{stats?.total_tasks || 0}</p>
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1"> <p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-400" /> <span className="w-2 h-2 rounded-full bg-emerald-400" />
: {stats?.completed_tasks || 0} : {stats?.completed_tasks || 0}
</p> </p>
</div> </div>
@ -234,8 +234,8 @@ export default function Dashboard() {
<div> <div>
<p className="stat-label"></p> <p className="stat-label"></p>
<p className="stat-value">{stats?.total_issues || 0}</p> <p className="stat-value">{stats?.total_issues || 0}</p>
<p className="text-xs text-amber-400 mt-1 flex items-center gap-1"> <p className="text-sm text-amber-400 mt-1 flex items-center gap-1">
<span className="w-1.5 h-1.5 rounded-full bg-amber-400" /> <span className="w-2 h-2 rounded-full bg-amber-400" />
: {stats?.resolved_issues || 0} : {stats?.resolved_issues || 0}
</p> </p>
</div> </div>
@ -254,12 +254,12 @@ export default function Dashboard() {
{stats?.avg_quality_score ? stats.avg_quality_score.toFixed(1) : '0.0'} {stats?.avg_quality_score ? stats.avg_quality_score.toFixed(1) : '0.0'}
</p> </p>
{stats?.avg_quality_score ? ( {stats?.avg_quality_score ? (
<p className="text-xs text-emerald-400 mt-1 flex items-center gap-1"> <p className="text-sm text-emerald-400 mt-1 flex items-center gap-1">
<TrendingUp className="w-3 h-3" /> <TrendingUp className="w-4 h-4" />
</p> </p>
) : ( ) : (
<p className="text-xs text-gray-500 mt-1"></p> <p className="text-sm text-muted-foreground mt-1"></p>
)} )}
</div> </div>
<div className="stat-icon text-violet-400"> <div className="stat-icon text-violet-400">
@ -284,25 +284,26 @@ export default function Dashboard() {
{qualityTrendData.length > 0 ? ( {qualityTrendData.length > 0 ? (
<ResponsiveContainer width="100%" height={220}> <ResponsiveContainer width="100%" height={220}>
<LineChart data={qualityTrendData}> <LineChart data={qualityTrendData}>
<CartesianGrid strokeDasharray="3 3" stroke="#1f1f2e" /> <CartesianGrid strokeDasharray="3 3" stroke="var(--cyber-border)" />
<XAxis dataKey="date" stroke="#6b7280" fontSize={11} tick={{ fontFamily: 'monospace' }} /> <XAxis dataKey="date" stroke="var(--cyber-text-muted)" fontSize={11} tick={{ fontFamily: 'monospace' }} />
<YAxis stroke="#6b7280" fontSize={11} domain={[0, 100]} tick={{ fontFamily: 'monospace' }} /> <YAxis stroke="var(--cyber-text-muted)" fontSize={11} domain={[0, 100]} tick={{ fontFamily: 'monospace' }} />
<Tooltip <Tooltip
contentStyle={{ contentStyle={{
backgroundColor: '#0c0c12', backgroundColor: 'var(--cyber-bg-elevated)',
border: '1px solid #2a2a35', border: '1px solid var(--cyber-border)',
borderRadius: '4px', borderRadius: '4px',
fontFamily: 'monospace', fontFamily: 'monospace',
fontSize: '12px' fontSize: '12px',
color: 'var(--cyber-text)'
}} }}
/> />
<Line <Line
type="monotone" type="monotone"
dataKey="score" dataKey="score"
stroke="#FF6B2C" stroke="hsl(var(--primary))"
strokeWidth={2} strokeWidth={2}
dot={{ fill: '#FF6B2C', stroke: '#0c0c12', strokeWidth: 2, r: 4 }} dot={{ fill: 'hsl(var(--primary))', stroke: 'var(--cyber-bg)', strokeWidth: 2, r: 4 }}
activeDot={{ r: 6, fill: '#FF6B2C' }} activeDot={{ r: 6, fill: 'hsl(var(--primary))' }}
/> />
</LineChart> </LineChart>
</ResponsiveContainer> </ResponsiveContainer>
@ -331,7 +332,7 @@ export default function Dashboard() {
label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`} label={({ name, percent }) => `${name} ${(percent * 100).toFixed(0)}%`}
outerRadius={70} outerRadius={70}
dataKey="value" dataKey="value"
stroke="#0c0c12" stroke="var(--cyber-bg)"
strokeWidth={2} strokeWidth={2}
> >
{issueTypeData.map((entry) => ( {issueTypeData.map((entry) => (
@ -340,11 +341,12 @@ export default function Dashboard() {
</Pie> </Pie>
<Tooltip <Tooltip
contentStyle={{ contentStyle={{
backgroundColor: '#0c0c12', backgroundColor: 'var(--cyber-bg-elevated)',
border: '1px solid #2a2a35', border: '1px solid var(--cyber-border)',
borderRadius: '4px', borderRadius: '4px',
fontFamily: 'monospace', fontFamily: 'monospace',
fontSize: '12px' fontSize: '12px',
color: 'var(--cyber-text)'
}} }}
/> />
</PieChart> </PieChart>
@ -370,21 +372,33 @@ export default function Dashboard() {
<Link <Link
key={project.id} key={project.id}
to={`/projects/${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"> <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} {project.name}
</h4> </h4>
<Badge className={`ml-2 flex-shrink-0 ${project.is_active ? 'cyber-badge-success' : 'cyber-badge-muted'}`}> <Badge className={`ml-2 flex-shrink-0 ${project.is_active ? 'cyber-badge-success' : 'cyber-badge-muted'}`}>
{project.is_active ? '活跃' : '暂停'} {project.is_active ? '活跃' : '暂停'}
</Badge> </Badge>
</div> </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 || '暂无描述'} {project.description || '暂无描述'}
</p> </p>
<div className="flex items-center text-xs text-gray-600"> <div className="flex items-center text-sm text-muted-foreground">
<Calendar className="w-3 h-3 mr-1" /> <Calendar className="w-4 h-4 mr-1" />
{new Date(project.created_at).toLocaleDateString('zh-CN')} {new Date(project.created_at).toLocaleDateString('zh-CN')}
</div> </div>
</Link> </Link>
@ -405,7 +419,7 @@ export default function Dashboard() {
<Clock className="w-5 h-5 text-emerald-400" /> <Clock className="w-5 h-5 text-emerald-400" />
<h3 className="section-title"></h3> <h3 className="section-title"></h3>
<Link to="/audit-tasks" className="ml-auto"> <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" /> <ArrowUpRight className="w-3 h-3 ml-1" />
</Button> </Button>
</Link> </Link>
@ -416,7 +430,16 @@ export default function Dashboard() {
<Link <Link
key={task.id} key={task.id}
to={`/tasks/${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="flex items-center gap-3">
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${ <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" />} <AlertTriangle className="w-4 h-4" />}
</div> </div>
<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 || '未知项目'} {task.project?.name || '未知项目'}
</p> </p>
<p className="text-xs text-gray-500"> <p className="text-sm text-muted-foreground">
: <span className="text-white">{task.quality_score?.toFixed(1) || '0.0'}</span> : <span className="text-foreground">{task.quality_score?.toFixed(1) || '0.0'}</span>
</p> </p>
</div> </div>
</div> </div>
@ -494,7 +517,7 @@ export default function Dashboard() {
</div> </div>
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between"> <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={` <Badge className={`
${dbMode === 'api' ? 'cyber-badge-primary' : ${dbMode === 'api' ? 'cyber-badge-primary' :
dbMode === 'local' ? 'cyber-badge-info' : dbMode === 'local' ? 'cyber-badge-info' :
@ -505,36 +528,36 @@ export default function Dashboard() {
</Badge> </Badge>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span> <span className="text-base text-muted-foreground"></span>
<span className="text-sm font-bold text-white">{stats?.active_projects || 0}</span> <span className="text-base font-bold text-foreground">{stats?.active_projects || 0}</span>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span> <span className="text-base text-muted-foreground"></span>
<span className="text-sm font-bold text-sky-400"> <span className="text-base font-bold text-sky-400">
{recentTasks.filter(t => t.status === 'running').length} {recentTasks.filter(t => t.status === 'running').length}
</span> </span>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm text-gray-400"></span> <span className="text-base text-muted-foreground"></span>
<span className="text-sm font-bold text-amber-400"> <span className="text-base font-bold text-amber-400">
{stats ? stats.total_issues - stats.resolved_issues : 0} {stats ? stats.total_issues - stats.resolved_issues : 0}
</span> </span>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm text-gray-400 flex items-center gap-1"> <span className="text-base text-muted-foreground flex items-center gap-1">
<Shield className="w-3 h-3" /> <Shield className="w-4 h-4" />
</span> </span>
<span className="text-sm font-bold text-violet-400"> <span className="text-base font-bold text-violet-400">
{ruleStats.enabled}/{ruleStats.total} {ruleStats.enabled}/{ruleStats.total}
</span> </span>
</div> </div>
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<span className="text-sm text-gray-400 flex items-center gap-1"> <span className="text-base text-muted-foreground flex items-center gap-1">
<MessageSquare className="w-3 h-3" /> <MessageSquare className="w-4 h-4" />
</span> </span>
<span className="text-sm font-bold text-emerald-400"> <span className="text-base font-bold text-emerald-400">
{templateStats.active}/{templateStats.total} {templateStats.active}/{templateStats.total}
</span> </span>
</div> </div>
@ -572,28 +595,28 @@ export default function Dashboard() {
<Link <Link
key={task.id} key={task.id}
to={`/tasks/${task.id}`} to={`/tasks/${task.id}`}
className={`block p-3 rounded-lg border transition-all hover:border-gray-700 ${ className={`block p-3 rounded-lg border transition-all ${
task.status === 'completed' ? 'bg-emerald-500/5 border-emerald-500/20' : 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' : 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' : task.status === 'failed' ? 'bg-rose-500/5 border-rose-500/20 hover:border-rose-500/40' :
'bg-gray-800/30 border-gray-800/50' 'bg-muted/30 border-border hover:border-border'
}`} }`}
> >
<p className="text-sm font-medium text-gray-200">{statusText}</p> <p className="text-base font-medium text-foreground">{statusText}</p>
<p className="text-xs text-gray-500 mt-1 line-clamp-1"> <p className="text-sm text-muted-foreground mt-1 line-clamp-1">
"{task.project?.name || '未知项目'}" "{task.project?.name || '未知项目'}"
{task.status === 'completed' && task.issues_count > 0 && {task.status === 'completed' && task.issues_count > 0 &&
` - 发现 ${task.issues_count} 个问题` ` - 发现 ${task.issues_count} 个问题`
} }
</p> </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> </Link>
); );
}) })
) : ( ) : (
<div className="empty-state py-6"> <div className="empty-state py-6">
<Clock className="w-8 h-8 text-gray-600 mb-2" /> <Clock className="w-10 h-10 text-muted-foreground mb-2" />
<p className="text-sm text-gray-500"></p> <p className="text-base text-muted-foreground"></p>
</div> </div>
)} )}
</div> </div>

View File

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

View File

@ -78,7 +78,7 @@ export default function Login() {
}; };
return ( 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 */} {/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20"> <div className="absolute inset-0 pointer-events-none z-20">
<div <div
@ -110,32 +110,32 @@ export default function Login() {
/> />
{/* Corner Decorations */} {/* 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"> <div className="flex items-center gap-2">
<Terminal className="w-3 h-3" /> <Terminal className="w-4 h-4" />
<span>SYS_ID: 0x84F2</span> <span>SYS_ID: 0x84F2</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Shield className="w-3 h-3" /> <Shield className="w-4 h-4" />
<span>ENCRYPT: AES-256</span> <span>ENCRYPT: AES-256</span>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Fingerprint className="w-3 h-3" /> <Fingerprint className="w-4 h-4" />
<span>AUTH: READY</span> <span>AUTH: READY</span>
</div> </div>
</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>SECURE_CONN: TRUE</div>
<div>PORT: 443</div> <div>PORT: 443</div>
<div>TLS: 1.3</div> <div>TLS: 1.3</div>
</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 DEEPAUDIT_AUTH_v3
</div> </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]} {new Date().toISOString().split("T")[0]}
</div> </div>
@ -143,7 +143,7 @@ export default function Login() {
<div className="w-full max-w-md relative z-30 px-4"> <div className="w-full max-w-md relative z-30 px-4">
{/* Logo & Title */} {/* Logo & Title */}
<div className="text-center mb-8"> <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)' }}> style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}>
<img <img
src="/logo_deepaudit.png" 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)" }} 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-primary">DEEP</span>
<span className="text-white">AUDIT</span> <span className="text-foreground">AUDIT</span>
</div> </div>
<p className="text-sm font-mono text-gray-500"> <p className="text-base font-mono text-muted-foreground">
// Autonomous Security Agent // Autonomous Security Agent
</p> </p>
</div> </div>
{/* Login Form Card */} {/* 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)' }}> style={{ boxShadow: '0 4px 30px rgba(0,0,0,0.5)' }}>
{/* Card Header */} {/* 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="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-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-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 className="w-3 h-3 rounded-full bg-green-500/80" />
</div> </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 authentication@deepaudit
</span> </span>
</div> </div>
@ -183,7 +183,7 @@ export default function Login() {
<div className="space-y-2"> <div className="space-y-2">
<Label <Label
htmlFor="email" 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> </Label>
@ -195,16 +195,16 @@ export default function Login() {
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
required 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> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label <Label
htmlFor="password" 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> </Label>
@ -216,9 +216,9 @@ export default function Login() {
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
required 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>
</div> </div>
@ -230,11 +230,11 @@ export default function Login() {
onCheckedChange={(checked) => onCheckedChange={(checked) =>
setRememberMe(checked as boolean) 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 <Label
htmlFor="remember" htmlFor="remember"
className="text-sm font-mono text-gray-500 cursor-pointer" className="text-base font-mono text-muted-foreground cursor-pointer"
> >
</Label> </Label>
@ -243,7 +243,7 @@ export default function Login() {
<Button <Button
type="submit" 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)' }} style={{ boxShadow: '0 0 20px rgba(255,107,44,0.3)' }}
disabled={loading} disabled={loading}
> >
@ -259,8 +259,8 @@ export default function Login() {
</form> </form>
{/* Footer */} {/* Footer */}
<div className="mt-6 pt-5 border-t border-gray-800/50 text-center"> <div className="mt-6 pt-5 border-t border-border text-center">
<p className="text-sm font-mono text-gray-500"> <p className="text-base font-mono text-muted-foreground">
{" "} {" "}
<span <span
className="text-primary font-bold cursor-pointer hover:underline" className="text-primary font-bold cursor-pointer hover:underline"
@ -275,7 +275,7 @@ export default function Login() {
{/* Version Info */} {/* Version Info */}
<div className="mt-6 text-center"> <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 Version {version} · Secure Connection
</p> </p>
</div> </div>

View File

@ -12,7 +12,7 @@ export default function NotFound() {
return ( return (
<> <>
<PageMeta title="页面未找到" description="" /> <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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" /> <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 p-0 mb-8">
<div className="cyber-card-header"> <div className="cyber-card-header">
<Terminal className="w-4 h-4 text-primary" /> <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>
<div className="p-4 text-left"> <div className="p-4 text-left">
<div className="text-emerald-400 text-sm"> <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>
<div className="text-rose-400 text-sm mt-1"> <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>
<div className="text-amber-400 text-sm mt-1"> <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>
<div className="text-gray-400 text-sm mt-1"> <div className="text-muted-foreground text-sm mt-1">
<span className="text-gray-500">MESSAGE:</span> <span className="text-muted-foreground">MESSAGE:</span>
</div> </div>
</div> </div>
</div> </div>
{/* Description */} {/* Description */}
<p className="text-gray-400 mb-8 text-sm"> <p className="text-muted-foreground mb-8 text-sm">
</p> </p>
@ -76,7 +76,7 @@ export default function NotFound() {
</div> </div>
{/* Footer */} {/* 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 &copy; {new Date().getFullYear()} DeepAudit
</p> </p>
</div> </div>

View File

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

View File

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

View File

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

View File

@ -109,17 +109,17 @@ export default function RecycleBin() {
if (loading) { if (loading) {
return ( 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="text-center space-y-4">
<div className="loading-spinner mx-auto" /> <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>
</div> </div>
); );
} }
return ( 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 */} {/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none" /> <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 p-0 relative z-10">
<div className="cyber-card-header"> <div className="cyber-card-header">
<Trash2 className="w-5 h-5 text-rose-400" /> <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> <Badge className="ml-2 cyber-badge-muted">{deletedProjects.length} </Badge>
</div> </div>
<div className="p-4"> <div className="p-4">
<div className="relative"> <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 <Input
placeholder="搜索已删除的项目..." placeholder="搜索已删除的项目..."
value={searchTerm} 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"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 relative z-10">
{filteredProjects.length > 0 ? ( {filteredProjects.length > 0 ? (
filteredProjects.map((project) => ( 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 */} {/* 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-start justify-between">
<div className="flex items-center space-x-3"> <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)} {getRepositoryIcon(project.repository_type)}
</div> </div>
<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} {project.name}
</h3> </h3>
{project.description && ( {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} {project.description}
</p> </p>
)} )}
@ -179,8 +179,8 @@ export default function RecycleBin() {
{/* Project Info */} {/* Project Info */}
<div className="space-y-3"> <div className="space-y-3">
{isRepositoryProject(project) && project.repository_url && ( {isRepositoryProject(project) && project.repository_url && (
<div className="flex items-center text-xs text-gray-500"> <div className="flex items-center text-xs text-muted-foreground">
<GitBranch className="w-4 h-4 mr-2 flex-shrink-0 text-gray-600" /> <GitBranch className="w-4 h-4 mr-2 flex-shrink-0 text-muted-foreground" />
<a <a
href={project.repository_url} href={project.repository_url}
target="_blank" target="_blank"
@ -193,13 +193,13 @@ export default function RecycleBin() {
</div> </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"> <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)} {formatDate(project.updated_at)}
</div> </div>
<div className="flex items-center"> <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 || '未知'} {project.owner?.full_name || '未知'}
</div> </div>
</div> </div>
@ -222,7 +222,7 @@ export default function RecycleBin() {
)} )}
{/* Action Buttons */} {/* 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 <Button
size="sm" size="sm"
variant="outline" variant="outline"
@ -262,19 +262,19 @@ export default function RecycleBin() {
{/* Restore Dialog */} {/* Restore Dialog */}
<AlertDialog open={showRestoreDialog} onOpenChange={setShowRestoreDialog}> <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"> <AlertDialogHeader className="cyber-card-header">
<RotateCcw className="w-5 h-5 text-emerald-400" /> <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> </AlertDialogTitle>
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogDescription className="p-6 text-gray-400"> <AlertDialogDescription className="p-6 text-muted-foreground">
<span className="font-bold text-white">"{selectedProject?.name}"</span> <span className="font-bold text-foreground">"{selectedProject?.name}"</span>
<br /><br /> <br /><br />
使 使
</AlertDialogDescription> </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> <AlertDialogCancel className="cyber-btn-outline"></AlertDialogCancel>
<AlertDialogAction <AlertDialogAction
onClick={handleConfirmRestore} onClick={handleConfirmRestore}
@ -288,15 +288,15 @@ export default function RecycleBin() {
{/* Permanent Delete Dialog */} {/* Permanent Delete Dialog */}
<AlertDialog open={showPermanentDeleteDialog} onOpenChange={setShowPermanentDeleteDialog}> <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"> <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" /> <AlertTriangle className="w-5 h-5 text-rose-400" />
<AlertDialogTitle className="text-lg font-bold uppercase tracking-wider text-rose-400"> <AlertDialogTitle className="text-lg font-bold uppercase tracking-wider text-rose-400">
</AlertDialogTitle> </AlertDialogTitle>
</AlertDialogHeader> </AlertDialogHeader>
<AlertDialogDescription className="p-6 text-gray-400"> <AlertDialogDescription className="p-6 text-muted-foreground">
<span className="font-bold text-rose-400 uppercase"></span> <span className="font-bold text-white">"{selectedProject?.name}"</span> <span className="font-bold text-rose-400 uppercase"></span> <span className="font-bold text-foreground">"{selectedProject?.name}"</span>
<br /><br /> <br /><br />
<div className="bg-rose-500/10 border border-rose-500/30 p-4 rounded"> <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"> <p className="text-rose-400 font-bold mb-2 uppercase flex items-center">
@ -310,7 +310,7 @@ export default function RecycleBin() {
</ul> </ul>
</div> </div>
</AlertDialogDescription> </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> <AlertDialogCancel className="cyber-btn-outline"></AlertDialogCancel>
<AlertDialogAction <AlertDialogAction
onClick={handleConfirmPermanentDelete} onClick={handleConfirmPermanentDelete}

View File

@ -47,7 +47,7 @@ export default function Register() {
}; };
return ( 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 */} {/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20"> <div className="absolute inset-0 pointer-events-none z-20">
<div <div
@ -79,7 +79,7 @@ export default function Register() {
/> />
{/* Corner Decorations */} {/* 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"> <div className="flex items-center gap-2">
<Terminal className="w-3 h-3" /> <Terminal className="w-3 h-3" />
<span>REG_MODULE: ACTIVE</span> <span>REG_MODULE: ACTIVE</span>
@ -94,17 +94,17 @@ export default function Register() {
</div> </div>
</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>SECURE_CONN: TRUE</div>
<div>VALIDATION: ENABLED</div> <div>VALIDATION: ENABLED</div>
<div>HASH: SHA-256</div> <div>HASH: SHA-256</div>
</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 DEEPAUDIT_REG_v3
</div> </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]} {new Date().toISOString().split("T")[0]}
</div> </div>
@ -112,7 +112,7 @@ export default function Register() {
<div className="w-full max-w-md relative z-30 px-4"> <div className="w-full max-w-md relative z-30 px-4">
{/* Logo & Title */} {/* Logo & Title */}
<div className="text-center mb-8"> <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)' }}> style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}>
<img <img
src="/logo_deepaudit.png" 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)" }} 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-primary">DEEP</span>
<span className="text-white">AUDIT</span> <span className="text-foreground">AUDIT</span>
</div> </div>
<p className="text-sm font-mono text-gray-500"> <p className="text-sm font-mono text-muted-foreground">
// Create New Account // Create New Account
</p> </p>
</div> </div>
{/* Register Form Card */} {/* 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)' }}> style={{ boxShadow: '0 4px 30px rgba(0,0,0,0.5)' }}>
{/* Card Header */} {/* 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="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-red-500/80" />
<div className="w-3 h-3 rounded-full bg-yellow-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 className="w-3 h-3 rounded-full bg-green-500/80" />
</div> </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 register@deepaudit
</span> </span>
</div> </div>
@ -152,7 +152,7 @@ export default function Register() {
<div className="space-y-2"> <div className="space-y-2">
<Label <Label
htmlFor="fullName" 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> </Label>
@ -163,16 +163,16 @@ export default function Register() {
value={fullName} value={fullName}
onChange={(e) => setFullName(e.target.value)} onChange={(e) => setFullName(e.target.value)}
required 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> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label <Label
htmlFor="email" 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> </Label>
@ -184,16 +184,16 @@ export default function Register() {
value={email} value={email}
onChange={(e) => setEmail(e.target.value)} onChange={(e) => setEmail(e.target.value)}
required 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> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label <Label
htmlFor="password" 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> </Label>
@ -205,15 +205,15 @@ export default function Register() {
value={password} value={password}
onChange={(e) => setPassword(e.target.value)} onChange={(e) => setPassword(e.target.value)}
required 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>
</div> </div>
<Button <Button
type="submit" 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)' }} style={{ boxShadow: '0 0 20px rgba(255,107,44,0.3)' }}
disabled={loading} disabled={loading}
> >
@ -229,8 +229,8 @@ export default function Register() {
</form> </form>
{/* Footer */} {/* Footer */}
<div className="mt-6 pt-5 border-t border-gray-800/50 text-center"> <div className="mt-6 pt-5 border-t border-border text-center">
<p className="text-sm font-mono text-gray-500"> <p className="text-sm font-mono text-muted-foreground">
{" "} {" "}
<span <span
className="text-primary font-bold cursor-pointer hover:underline" className="text-primary font-bold cursor-pointer hover:underline"
@ -245,7 +245,7 @@ export default function Register() {
{/* Version Info */} {/* Version Info */}
<div className="mt-6 text-center"> <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 Version {version} · Secure Registration
</p> </p>
</div> </div>

View File

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

View File

@ -56,7 +56,7 @@ export const PLATFORM_COLORS: Record<RepositoryPlatform, {
bg: string; bg: string;
text: 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' }, 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'], display: ['"Orbitron"', '"Rajdhani"', 'sans-serif'],
}, },
fontSize: { fontSize: {
'xs': ['0.75rem', { lineHeight: '1rem', letterSpacing: '0.01em' }], 'xs': ['0.8125rem', { lineHeight: '1.125rem', letterSpacing: '0.01em' }], // 13px
'sm': ['0.875rem', { lineHeight: '1.25rem', letterSpacing: '0.01em' }], 'sm': ['0.9375rem', { lineHeight: '1.375rem', letterSpacing: '0.01em' }], // 15px
'base': ['1rem', { lineHeight: '1.5rem', letterSpacing: '0' }], 'base': ['1rem', { lineHeight: '1.5rem', letterSpacing: '0' }], // 16px
'lg': ['1.125rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }], 'lg': ['1.125rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }], // 18px
'xl': ['1.25rem', { lineHeight: '1.75rem', letterSpacing: '-0.01em' }], 'xl': ['1.375rem', { lineHeight: '1.875rem', letterSpacing: '-0.01em' }], // 22px
'2xl': ['1.5rem', { lineHeight: '2rem', letterSpacing: '-0.02em' }], '2xl': ['1.625rem', { lineHeight: '2.125rem', letterSpacing: '-0.02em' }], // 26px
'3xl': ['1.875rem', { lineHeight: '2.25rem', letterSpacing: '-0.02em' }], '3xl': ['2rem', { lineHeight: '2.5rem', letterSpacing: '-0.02em' }], // 32px
'4xl': ['2.5rem', { lineHeight: '3rem', letterSpacing: '-0.02em' }], // 40px
}, },
// Extended Color System // Extended Color System
colors: { colors: {