feat(ui): 为暗黑模式添加亮度调整并优化颜色对比度

添加暗黑模式下的亮度调整,优化颜色对比度以提高可读性
更新多个组件的颜色变量以支持亮色和暗色主题
添加可折叠的扫描配置区域以改善用户体验
This commit is contained in:
lintsinghua 2025-12-18 22:55:05 +08:00
parent 46f7a46f22
commit cb1cdb77b8
5 changed files with 138 additions and 95 deletions

View File

@ -453,6 +453,12 @@
/* ============ Severity Badges ============ */
.severity-critical {
background: rgba(220, 38, 38, 0.15);
color: #b91c1c;
border: 1px solid rgba(220, 38, 38, 0.4);
}
.dark .severity-critical {
background: rgba(220, 38, 38, 0.2);
color: #fca5a5;
border: 1px solid rgba(220, 38, 38, 0.5);
@ -460,6 +466,12 @@
}
.severity-high {
background: rgba(234, 88, 12, 0.15);
color: #c2410c;
border: 1px solid rgba(234, 88, 12, 0.4);
}
.dark .severity-high {
background: rgba(234, 88, 12, 0.2);
color: #fdba74;
border: 1px solid rgba(234, 88, 12, 0.5);
@ -467,6 +479,12 @@
}
.severity-medium {
background: rgba(245, 158, 11, 0.15);
color: #b45309;
border: 1px solid rgba(245, 158, 11, 0.4);
}
.dark .severity-medium {
background: rgba(245, 158, 11, 0.2);
color: #fcd34d;
border: 1px solid rgba(245, 158, 11, 0.5);
@ -474,6 +492,12 @@
}
.severity-low {
background: rgba(14, 181, 196, 0.15);
color: #0e7490;
border: 1px solid rgba(14, 181, 196, 0.4);
}
.dark .severity-low {
background: rgba(14, 181, 196, 0.2);
color: #67e8f9;
border: 1px solid rgba(14, 181, 196, 0.5);
@ -481,6 +505,12 @@
}
.severity-info {
background: rgba(100, 116, 139, 0.15);
color: #475569;
border: 1px solid rgba(100, 116, 139, 0.4);
}
.dark .severity-info {
background: rgba(100, 116, 139, 0.2);
color: #cbd5e1;
border: 1px solid rgba(100, 116, 139, 0.5);

View File

@ -419,11 +419,11 @@ export default function TerminalProgressDialog({
const getLogColor = (type: LogEntry["type"]) => {
switch (type) {
case "success":
return "text-emerald-400";
return "text-emerald-600 dark:text-emerald-400";
case "error":
return "text-rose-400";
return "text-rose-600 dark:text-rose-400";
case "warning":
return "text-amber-400";
return "text-amber-600 dark:text-amber-400";
default:
return "text-muted-foreground";
}
@ -432,13 +432,13 @@ export default function TerminalProgressDialog({
return (
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogPortal>
<DialogOverlay className="bg-black/85 backdrop-blur-md" />
<DialogOverlay className="bg-black/50 dark:bg-black/85 backdrop-blur-md" />
<DialogPrimitive.Content
className={cn(
"fixed left-[50%] top-[50%] z-50 translate-x-[-50%] translate-y-[-50%]",
"w-[95vw] max-w-[1000px] h-[85vh] max-h-[700px]",
"bg-[#08090d] border border-[#1a2535] rounded overflow-hidden",
"shadow-[0_0_60px_rgba(0,0,0,0.8),inset_0_1px_0_rgba(255,255,255,0.02)]",
"bg-white dark:bg-[#08090d] border border-slate-200 dark:border-[#1a2535] rounded overflow-hidden",
"shadow-xl dark:shadow-[0_0_60px_rgba(0,0,0,0.8),inset_0_1px_0_rgba(255,255,255,0.02)]",
"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",
@ -454,44 +454,43 @@ export default function TerminalProgressDialog({
</DialogPrimitive.Description>
</VisuallyHidden.Root>
{/* Scanline overlay */}
<div className="absolute inset-0 pointer-events-none z-20 opacity-30"
{/* Scanline overlay - only in dark mode */}
<div className="absolute inset-0 pointer-events-none z-20 opacity-0 dark:opacity-30"
style={{
backgroundImage: "repeating-linear-gradient(0deg, transparent, transparent 2px, rgba(0,0,0,0.1) 2px, rgba(0,0,0,0.1) 4px)",
}}
/>
{/* Header */}
<div className="flex items-center justify-between px-4 py-3 cyber-bg-elevated border-b border-[#1a2535]"
style={{ backgroundImage: "linear-gradient(90deg, rgba(255, 95, 31, 0.05) 0%, transparent 50%, rgba(14, 181, 196, 0.05) 100%)" }}>
<div className="flex items-center justify-between px-4 py-3 bg-slate-50 dark:cyber-bg-elevated border-b border-slate-200 dark:border-[#1a2535]">
<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" />
<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-xs text-[#5a6577] ml-2 tracking-wider">v3.0</span>
<span className="text-lg font-bold uppercase tracking-[0.15em] text-slate-800 dark:text-[#f0e6d3]">AUDIT_TERMINAL</span>
<span className="text-xs text-slate-500 dark:text-[#5a6577] ml-2 tracking-wider">v3.0</span>
</div>
</div>
<div className="flex items-center gap-4">
{/* 状态指示灯 */}
<div className="flex items-center gap-2.5 px-3 py-1.5 bg-[#060810] rounded border border-[#1a2535]">
<div className="flex items-center gap-2.5 px-3 py-1.5 bg-slate-100 dark:bg-[#060810] rounded border border-slate-200 dark:border-[#1a2535]">
<div className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${!isCompleted && !isFailed && !isCancelled
? 'bg-[#3dd68c] shadow-[0_0_10px_rgba(61,214,140,0.7)] animate-pulse'
: 'bg-[#3a4555]'}`} />
? 'bg-emerald-500 dark:bg-[#3dd68c] shadow-[0_0_10px_rgba(61,214,140,0.7)] animate-pulse'
: 'bg-slate-300 dark:bg-[#3a4555]'}`} />
<div className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${isFailed
? 'bg-[#f87171] shadow-[0_0_10px_rgba(248,113,113,0.7)]'
: 'bg-[#3a4555]'}`} />
? 'bg-rose-500 dark:bg-[#f87171] shadow-[0_0_10px_rgba(248,113,113,0.7)]'
: 'bg-slate-300 dark:bg-[#3a4555]'}`} />
<div className={`w-2.5 h-2.5 rounded-full transition-all duration-300 ${isCompleted
? 'bg-[#22d3ee] shadow-[0_0_10px_rgba(34,211,238,0.7)]'
: 'bg-[#3a4555]'}`} />
? 'bg-cyan-500 dark:bg-[#22d3ee] shadow-[0_0_10px_rgba(34,211,238,0.7)]'
: 'bg-slate-300 dark:bg-[#3a4555]'}`} />
</div>
<button
type="button"
className="w-8 h-8 flex items-center justify-center hover:bg-[#e53935]/20 rounded transition-all duration-200 group"
className="w-8 h-8 flex items-center justify-center hover:bg-rose-100 dark:hover:bg-[#e53935]/20 rounded transition-all duration-200 group"
onClick={() => onOpenChange(false)}
>
<XIcon className="w-5 h-5 text-[#6a7587] group-hover:text-[#f87171] transition-colors" />
<XIcon className="w-5 h-5 text-slate-500 dark:text-[#6a7587] group-hover:text-rose-500 dark:group-hover:text-[#f87171] transition-colors" />
</button>
</div>
</div>
@ -499,22 +498,21 @@ export default function TerminalProgressDialog({
{/* Main Content */}
<div className="flex h-[calc(100%-56px)]">
{/* 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-slate-200 dark:border-[#1a2535] bg-slate-50 dark:bg-[#060810] flex flex-col gap-4">
<div className="space-y-1.5">
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Task ID</div>
<div className="text-xs font-mono text-primary truncate cyber-bg-elevated p-2.5 rounded border border-[#1a2535]"
style={{ textShadow: "0 0 10px rgba(255, 95, 31, 0.3)" }}>
<div className="text-xs font-bold text-slate-500 dark:text-[#5a6577] uppercase tracking-[0.15em]">Task ID</div>
<div className="text-xs font-mono text-primary truncate bg-white dark:cyber-bg-elevated p-2.5 rounded border border-slate-200 dark:border-[#1a2535]">
{taskId?.slice(0, 8)}...
</div>
</div>
<div className="space-y-1.5">
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Type</div>
<div className="flex items-center gap-2 cyber-bg-elevated p-2.5 rounded border border-[#1a2535]">
<div className="text-xs font-bold text-slate-500 dark:text-[#5a6577] uppercase tracking-[0.15em]">Type</div>
<div className="flex items-center gap-2 bg-white dark:cyber-bg-elevated p-2.5 rounded border border-slate-200 dark:border-[#1a2535]">
{taskType === 'repository'
? <Cpu className="w-3.5 h-3.5 text-[#22d3ee]" style={{ filter: "drop-shadow(0 0 6px rgba(34, 211, 238, 0.5))" }} />
: <HardDrive className="w-3.5 h-3.5 text-[#fbbf24]" style={{ filter: "drop-shadow(0 0 6px rgba(251, 191, 36, 0.5))" }} />}
<span className="text-xs font-bold text-[#d0d8e8] uppercase tracking-wider">{taskType}</span>
? <Cpu className="w-3.5 h-3.5 text-cyan-600 dark:text-[#22d3ee]" />
: <HardDrive className="w-3.5 h-3.5 text-amber-600 dark:text-[#fbbf24]" />}
<span className="text-xs font-bold text-slate-700 dark:text-[#d0d8e8] uppercase tracking-wider">{taskType}</span>
</div>
</div>
@ -522,7 +520,7 @@ export default function TerminalProgressDialog({
{/* Status Badge */}
<div className="space-y-2">
<div className="text-xs font-bold text-[#5a6577] uppercase tracking-[0.15em]">Status</div>
<div className="text-xs font-bold text-slate-500 dark:text-[#5a6577] uppercase tracking-[0.15em]">Status</div>
{isCancelled ? (
<Badge className="w-full justify-center cyber-badge-warning">CANCELLED</Badge>
) : isCompleted ? (
@ -538,18 +536,17 @@ export default function TerminalProgressDialog({
{/* Terminal Screen */}
<div className="flex-1 flex flex-col">
{/* Terminal Output */}
<div className="flex-1 bg-[#050608] p-4 overflow-y-auto font-mono text-sm custom-scrollbar relative">
{/* Grid background */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none opacity-40" />
<div className="flex-1 bg-slate-100 dark:bg-[#050608] p-4 overflow-y-auto font-mono text-sm custom-scrollbar relative">
{/* Grid background - only in dark mode */}
<div className="absolute inset-0 cyber-grid-subtle pointer-events-none opacity-0 dark:opacity-40" />
<div className="relative z-10 space-y-0.5 pb-10">
{logs.map((log) => (
<div key={log.id} className="flex items-start gap-3 hover:bg-[#ffffff]/[0.03] px-2 py-0.5 transition-colors group rounded">
<span className="text-[#4a5565] text-xs flex-shrink-0 w-20 font-mono">
<div key={log.id} className="flex items-start gap-3 hover:bg-slate-200/50 dark:hover:bg-[#ffffff]/[0.03] px-2 py-0.5 transition-colors group rounded">
<span className="text-slate-500 dark:text-[#4a5565] text-xs flex-shrink-0 w-20 font-mono">
{log.timestamp}
</span>
<span className={`${getLogColor(log.type)} flex-1 font-mono text-sm`}
style={{ textShadow: log.type === 'success' ? '0 0 8px rgba(61, 214, 140, 0.3)' : log.type === 'error' ? '0 0 8px rgba(248, 113, 113, 0.3)' : log.type === 'warning' ? '0 0 8px rgba(251, 191, 36, 0.3)' : 'none' }}>
<span className={`${getLogColor(log.type)} flex-1 font-mono text-sm`}>
{log.message}
</span>
</div>
@ -557,8 +554,8 @@ export default function TerminalProgressDialog({
{!isCompleted && !isFailed && !isCancelled && (
<div className="flex items-center gap-3 mt-4 px-2">
<span className="text-[#4a5565] text-xs w-20 font-mono">{currentTime}</span>
<span className="text-primary animate-pulse font-bold" style={{ textShadow: "0 0 10px rgba(255, 95, 31, 0.5)" }}>_</span>
<span className="text-slate-500 dark:text-[#4a5565] text-xs w-20 font-mono">{currentTime}</span>
<span className="text-primary animate-pulse font-bold">_</span>
</div>
)}
<div ref={logsEndRef} />
@ -566,8 +563,8 @@ export default function TerminalProgressDialog({
</div>
{/* Bottom Controls */}
<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="h-14 px-4 border-t border-slate-200 dark:border-[#1a2535] bg-slate-50 dark:cyber-bg-elevated/90 flex items-center justify-between">
<div className="flex items-center gap-2 text-xs text-slate-600 dark:text-[#6a7587] font-mono tracking-wide">
<Activity className="w-3.5 h-3.5" />
<span>
{isCompleted ? "TASK COMPLETED" : isFailed ? "TASK FAILED" : isCancelled ? "TASK CANCELLED" : "EXECUTING..."}
@ -580,7 +577,7 @@ export default function TerminalProgressDialog({
size="sm"
variant="outline"
onClick={handleCancel}
className="h-8 bg-transparent border-[#fbbf24]/40 text-[#fbbf24] hover:bg-[#fbbf24]/10 hover:border-[#fbbf24]/60 font-mono uppercase tracking-wider text-xs"
className="h-8 bg-transparent border-amber-500/40 text-amber-600 dark:text-[#fbbf24] hover:bg-amber-50 dark:hover:bg-[#fbbf24]/10 hover:border-amber-500/60 font-mono uppercase tracking-wider text-xs"
>
<AlertTriangle className="w-3 h-3 mr-1.5" />
@ -592,7 +589,7 @@ export default function TerminalProgressDialog({
size="sm"
variant="outline"
onClick={() => window.open('/logs', '_blank')}
className="h-8 bg-transparent border-[#6a7587]/40 text-[#a8b0c0] hover:bg-[#1a2030]/50 hover:border-[#6a7587]/60 font-mono uppercase tracking-wider text-xs"
className="h-8 bg-transparent border-slate-300 dark:border-[#6a7587]/40 text-slate-600 dark:text-[#a8b0c0] hover:bg-slate-100 dark:hover:bg-[#1a2030]/50 hover:border-slate-400 dark:hover:border-[#6a7587]/60 font-mono uppercase tracking-wider text-xs"
>
<Activity className="w-3 h-3 mr-1.5" />

View File

@ -390,12 +390,12 @@ public class Example {
<div className="w-4 h-4 bg-primary rounded flex items-center justify-center">
<Code className="w-2 h-2 text-foreground" />
</div>
<span className="text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
<span className="text-emerald-600 dark:text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
</div>
<span className="text-muted-foreground text-xs font-mono">LINE: {issue.line}</span>
</div>
<div className="bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
<div className="bg-slate-100 dark:bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-700 dark:text-emerald-400 font-mono overflow-x-auto">
<code>{issue.code_snippet}</code>
</pre>
</div>
@ -407,11 +407,11 @@ public class Example {
<div className="bg-sky-500/10 border border-sky-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-sky-500/20 pb-1">
<div className="w-5 h-5 bg-sky-500/20 border border-sky-500/40 rounded flex items-center justify-center mr-2">
<Lightbulb className="w-3 h-3 text-sky-400" />
<Lightbulb className="w-3 h-3 text-sky-600 dark:text-sky-400" />
</div>
<span className="font-bold text-sky-300 text-sm uppercase"></span>
<span className="font-bold text-sky-700 dark:text-sky-300 text-sm uppercase"></span>
</div>
<p className="text-sky-200/80 text-xs leading-relaxed font-mono">{issue.suggestion}</p>
<p className="text-sky-800 dark:text-sky-200/80 text-xs leading-relaxed font-mono">{issue.suggestion}</p>
</div>
)}
@ -423,37 +423,37 @@ public class Example {
<div className="bg-violet-500/10 border border-violet-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-violet-500/20 pb-1">
<div className="w-5 h-5 bg-violet-500/20 border border-violet-500/40 rounded flex items-center justify-center mr-2">
<Zap className="w-3 h-3 text-violet-400" />
<Zap className="w-3 h-3 text-violet-600 dark:text-violet-400" />
</div>
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
<span className="font-bold text-violet-700 dark:text-violet-300 text-sm uppercase">AI </span>
</div>
<div className="space-y-2 text-xs font-mono">
{parsedExplanation.what && (
<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-600 dark:text-rose-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.what}</span>
</div>
)}
{parsedExplanation.why && (
<div className="border-l-2 border-amber-500 pl-2">
<span className="font-bold text-amber-400 uppercase"></span>
<span className="font-bold text-amber-600 dark:text-amber-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.why}</span>
</div>
)}
{parsedExplanation.how && (
<div className="border-l-2 border-emerald-500 pl-2">
<span className="font-bold text-emerald-400 uppercase"></span>
<span className="font-bold text-emerald-600 dark:text-emerald-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.how}</span>
</div>
)}
{parsedExplanation.learn_more && (
<div className="border-l-2 border-sky-500 pl-2">
<span className="font-bold text-sky-400 uppercase"></span>
<span className="font-bold text-sky-600 dark:text-sky-400 uppercase"></span>
<a
href={parsedExplanation.learn_more}
target="_blank"
rel="noopener noreferrer"
className="text-sky-400 hover:text-sky-300 hover:underline ml-1 font-bold"
className="text-sky-600 dark:text-sky-400 hover:text-sky-500 dark:hover:text-sky-300 hover:underline ml-1 font-bold"
>
{parsedExplanation.learn_more}
</a>
@ -466,8 +466,8 @@ public class Example {
return (
<div className="bg-violet-500/10 border border-violet-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-violet-500/20 pb-1">
<Zap className="w-4 h-4 text-violet-400 mr-2" />
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
<Zap className="w-4 h-4 text-violet-600 dark:text-violet-400 mr-2" />
<span className="font-bold text-violet-700 dark:text-violet-300 text-sm uppercase">AI </span>
</div>
<p className="text-foreground text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
</div>
@ -855,11 +855,11 @@ public class Example {
</Tabs>
) : (
<div className="cyber-card p-16 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-emerald-300 mb-2 uppercase"></h3>
<p className="text-emerald-400/80 mb-4 font-mono"></p>
<CheckCircle className="w-16 h-16 text-emerald-600 dark:text-emerald-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-emerald-700 dark:text-emerald-300 mb-2 uppercase"></h3>
<p className="text-emerald-600 dark:text-emerald-400/80 mb-4 font-mono"></p>
<div className="bg-emerald-500/10 border border-emerald-500/30 p-4 max-w-md mx-auto rounded">
<p className="text-emerald-300/80 text-sm font-mono">
<p className="text-emerald-700 dark:text-emerald-300/80 text-sm font-mono">
</p>
</div>

View File

@ -677,10 +677,10 @@ export default function ProjectDetail() {
<div className="flex items-start justify-between">
<div className="flex items-start space-x-3">
<div className={`w-8 h-8 rounded-lg flex items-center justify-center ${
issue.severity === 'critical' ? 'bg-rose-500/20 text-rose-400' :
issue.severity === 'high' ? 'bg-orange-500/20 text-orange-400' :
issue.severity === 'medium' ? 'bg-amber-500/20 text-amber-400' :
'bg-sky-500/20 text-sky-400'
issue.severity === 'critical' ? 'bg-rose-500/20 text-rose-600 dark:text-rose-400' :
issue.severity === 'high' ? 'bg-orange-500/20 text-orange-600 dark:text-orange-400' :
issue.severity === 'medium' ? 'bg-amber-500/20 text-amber-600 dark:text-amber-400' :
'bg-sky-500/20 text-sky-600 dark:text-sky-400'
}`}>
<AlertTriangle className="w-4 h-4" />
</div>
@ -712,7 +712,7 @@ export default function ProjectDetail() {
</div>
) : (
<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-600 dark:text-emerald-500 mx-auto mb-4" />
<h3 className="text-lg font-bold text-foreground mb-2 uppercase"></h3>
<p className="text-sm text-muted-foreground font-mono"></p>
</div>

View File

@ -27,7 +27,9 @@ import {
Info,
Zap,
XCircle,
Terminal
Terminal,
ChevronDown,
ChevronRight
} from "lucide-react";
import { api } from "@/shared/config/database";
import type { AuditTask, AuditIssue } from "@/shared/types";
@ -133,14 +135,14 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
<div className="w-4 h-4 bg-primary rounded flex items-center justify-center">
<Code className="w-2 h-2 text-foreground" />
</div>
<span className="text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
<span className="text-emerald-600 dark:text-emerald-400 text-xs font-bold font-mono uppercase">CODE_SNIPPET</span>
</div>
{issue.line_number && (
<span className="text-muted-foreground text-xs font-mono">LINE: {issue.line_number}</span>
)}
</div>
<div className="bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
<div className="bg-slate-100 dark:bg-black/40 p-2 border border-border rounded">
<pre className="text-xs text-emerald-700 dark:text-emerald-400 font-mono overflow-x-auto">
<code>{issue.code_snippet}</code>
</pre>
</div>
@ -152,11 +154,11 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
<div className="bg-sky-500/10 border border-sky-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-sky-500/20 pb-1">
<div className="w-5 h-5 bg-sky-500/20 border border-sky-500/40 rounded flex items-center justify-center mr-2">
<Lightbulb className="w-3 h-3 text-sky-400" />
<Lightbulb className="w-3 h-3 text-sky-600 dark:text-sky-400" />
</div>
<span className="font-bold text-sky-300 text-sm uppercase"></span>
<span className="font-bold text-sky-700 dark:text-sky-300 text-sm uppercase"></span>
</div>
<p className="text-sky-200/80 text-xs leading-relaxed font-mono">{issue.suggestion}</p>
<p className="text-sky-800 dark:text-sky-200/80 text-xs leading-relaxed font-mono">{issue.suggestion}</p>
</div>
)}
@ -168,41 +170,41 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
<div className="bg-violet-500/10 border border-violet-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-violet-500/20 pb-1">
<div className="w-5 h-5 bg-violet-500/20 border border-violet-500/40 rounded flex items-center justify-center mr-2">
<Zap className="w-3 h-3 text-violet-400" />
<Zap className="w-3 h-3 text-violet-600 dark:text-violet-400" />
</div>
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
<span className="font-bold text-violet-700 dark:text-violet-300 text-sm uppercase">AI </span>
</div>
<div className="space-y-2 text-xs font-mono">
{parsedExplanation.what && (
<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-600 dark:text-rose-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.what}</span>
</div>
)}
{parsedExplanation.why && (
<div className="border-l-2 border-amber-500 pl-2">
<span className="font-bold text-amber-400 uppercase"></span>
<span className="font-bold text-amber-600 dark:text-amber-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.why}</span>
</div>
)}
{parsedExplanation.how && (
<div className="border-l-2 border-emerald-500 pl-2">
<span className="font-bold text-emerald-400 uppercase"></span>
<span className="font-bold text-emerald-600 dark:text-emerald-400 uppercase"></span>
<span className="text-foreground ml-1">{parsedExplanation.how}</span>
</div>
)}
{parsedExplanation.learn_more && (
<div className="border-l-2 border-sky-500 pl-2">
<span className="font-bold text-sky-400 uppercase"></span>
<span className="font-bold text-sky-600 dark:text-sky-400 uppercase"></span>
<a
href={parsedExplanation.learn_more}
target="_blank"
rel="noopener noreferrer"
className="text-sky-400 hover:text-sky-300 hover:underline ml-1 font-bold"
className="text-sky-600 dark:text-sky-400 hover:text-sky-500 dark:hover:text-sky-300 hover:underline ml-1 font-bold"
>
{parsedExplanation.learn_more}
</a>
@ -215,8 +217,8 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
return (
<div className="bg-violet-500/10 border border-violet-500/30 p-3 rounded">
<div className="flex items-center mb-2 border-b border-violet-500/20 pb-1">
<Zap className="w-4 h-4 text-violet-400 mr-2" />
<span className="font-bold text-violet-300 text-sm uppercase">AI </span>
<Zap className="w-4 h-4 text-violet-600 dark:text-violet-400 mr-2" />
<span className="font-bold text-violet-700 dark:text-violet-300 text-sm uppercase">AI </span>
</div>
<p className="text-foreground text-xs leading-relaxed font-mono">{issue.ai_explanation}</p>
</div>
@ -230,11 +232,11 @@ function IssuesList({ issues }: { issues: AuditIssue[] }) {
if (issues.length === 0) {
return (
<div className="cyber-card p-16 text-center border-dashed">
<CheckCircle className="w-16 h-16 text-emerald-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-emerald-300 mb-2 uppercase"></h3>
<p className="text-emerald-400/80 mb-4 font-mono"></p>
<CheckCircle className="w-16 h-16 text-emerald-600 dark:text-emerald-400 mx-auto mb-4" />
<h3 className="text-xl font-bold text-emerald-700 dark:text-emerald-300 mb-2 uppercase"></h3>
<p className="text-emerald-600 dark:text-emerald-400/80 mb-4 font-mono"></p>
<div className="bg-emerald-500/10 border border-emerald-500/30 p-4 max-w-md mx-auto rounded">
<p className="text-emerald-300/80 text-sm font-mono">
<p className="text-emerald-700 dark:text-emerald-300/80 text-sm font-mono">
</p>
</div>
@ -324,6 +326,7 @@ export default function TaskDetail() {
const [loading, setLoading] = useState(true);
const [exportDialogOpen, setExportDialogOpen] = useState(false);
const [cancelling, setCancelling] = useState(false);
const [scanConfigExpanded, setScanConfigExpanded] = useState(false);
// Zombie task detection
const [lastProgressTime, setLastProgressTime] = useState<number>(Date.now());
@ -646,12 +649,25 @@ export default function TaskDetail() {
{task.scan_config && (
<div>
<p className="text-xs font-bold text-muted-foreground uppercase mb-2"></p>
<div className="cyber-bg-elevated border border-border p-3 rounded">
<pre className="text-xs text-emerald-400 font-mono overflow-x-auto">
{JSON.stringify(JSON.parse(task.scan_config), null, 2)}
</pre>
</div>
<button
type="button"
onClick={() => setScanConfigExpanded(!scanConfigExpanded)}
className="flex items-center gap-2 text-xs font-bold text-muted-foreground uppercase mb-2 hover:text-foreground transition-colors"
>
{scanConfigExpanded ? (
<ChevronDown className="w-4 h-4" />
) : (
<ChevronRight className="w-4 h-4" />
)}
</button>
{scanConfigExpanded && (
<div className="cyber-bg-elevated border border-border p-3 rounded">
<pre className="text-xs text-emerald-700 dark:text-emerald-400 font-mono overflow-x-auto">
{JSON.stringify(JSON.parse(task.scan_config), null, 2)}
</pre>
</div>
)}
</div>
)}
</div>