feat: Introduce reusable AppLogo component and update project activity timestamp to UTC.

This commit is contained in:
vinland100 2026-01-05 09:50:51 +08:00
parent a29f57d119
commit 7a3bb08d48
9 changed files with 334 additions and 245 deletions

View File

@ -11,7 +11,7 @@ import subprocess
import json import json
from typing import Dict, Any, List, Optional from typing import Dict, Any, List, Optional
from pathlib import Path from pathlib import Path
from datetime import datetime from datetime import datetime, timezone
import asyncio import asyncio
import httpx import httpx
@ -164,7 +164,7 @@ class CIService:
self.db.add(review_record) self.db.add(review_record)
# Update project activity # Update project activity
project.latest_pr_activity = datetime.utcnow() project.latest_pr_activity = datetime.now(timezone.utc)
await self.db.commit() await self.db.commit()
except Exception as e: except Exception as e:
@ -300,6 +300,9 @@ class CIService:
context_used=json.dumps([r.file_path for r in context_results]) context_used=json.dumps([r.file_path for r in context_results])
) )
self.db.add(review_record) self.db.add(review_record)
# Update project activity
project.latest_pr_activity = datetime.now(timezone.utc)
await self.db.commit() await self.db.commit()

View File

@ -0,0 +1,178 @@
import React from 'react';
/**
* AppLogo Component
* A professional SVG-based logo representing an AI Code Review Bot.
* Supports theme switching and various sizes.
*/
interface AppLogoProps {
className?: string;
size?: 'sm' | 'md' | 'lg' | 'xl' | '2xl';
showText?: boolean;
collapsed?: boolean;
theme?: 'dark' | 'light'; // Optional override
subtitle?: string;
}
const AppLogo: React.FC<AppLogoProps> = ({
className = "",
size = 'md',
showText = true,
collapsed = false,
subtitle = "AI Code Review Bot"
}) => {
// Size mapping for both icon and text
const sizeMap = {
sm: { icon: 'w-6 h-6', text: 'text-lg', sub: 'text-[8px]', gap: 'gap-2' },
md: { icon: 'w-10 h-10', text: 'text-xl', sub: 'text-[10px]', gap: 'gap-3' },
lg: { icon: 'w-14 h-14', text: 'text-3xl', sub: 'text-sm', gap: 'gap-4' },
xl: { icon: 'w-20 h-20', text: 'text-4xl', sub: 'text-base', gap: 'gap-5' },
'2xl': { icon: 'w-24 h-24', text: 'text-5xl', sub: 'text-lg', gap: 'gap-6' }
};
const currentSize = sizeMap[size];
return (
<div className={`flex items-center ${currentSize.gap} transition-all duration-300 ${className} ${collapsed ? 'justify-center' : ''}`}>
{/* Logo Icon Container */}
<div className={`relative flex-shrink-0 ${currentSize.icon} transition-transform duration-300 hover:scale-110 group`}>
{/* SVG Logo */}
<svg
viewBox="0 0 100 100"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="w-full h-full drop-shadow-[0_0_15px_rgba(255,107,44,0.3)]"
>
<defs>
<linearGradient id="logo-grad-primary" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stopColor="hsl(var(--primary))" />
<stop offset="100%" stopColor="hsl(var(--primary) / 0.7)" />
</linearGradient>
<filter id="logo-glow" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="3" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
</defs>
{/* Outer Hexagon Frame */}
<path
d="M50 5 L90 28 L90 72 L50 95 L10 72 L10 28 Z"
stroke="url(#logo-grad-primary)"
strokeWidth="4"
fill="currentColor"
className="text-primary/10 transition-colors duration-300"
/>
{/* Circuit Like Lines */}
<path
d="M30 15 L50 5 L70 15"
stroke="url(#logo-grad-primary)"
strokeWidth="2"
strokeLinecap="round"
strokeOpacity="0.5"
/>
<path
d="M30 85 L50 95 L70 85"
stroke="url(#logo-grad-primary)"
strokeWidth="2"
strokeLinecap="round"
strokeOpacity="0.5"
/>
{/* Brackets < > */}
<path
d="M32 35 L18 50 L32 65"
stroke="url(#logo-grad-primary)"
strokeWidth="7"
strokeLinecap="round"
strokeLinejoin="round"
filter="url(#logo-glow)"
className="group-hover:translate-x-[-2px] transition-transform duration-300"
/>
<path
d="M68 35 L82 50 L68 65"
stroke="url(#logo-grad-primary)"
strokeWidth="7"
strokeLinecap="round"
strokeLinejoin="round"
filter="url(#logo-glow)"
className="group-hover:translate-x-[2px] transition-transform duration-300"
/>
{/* Central AI Eye Entity */}
<circle
cx="50"
cy="50"
r="20"
stroke="url(#logo-grad-primary)"
strokeWidth="2"
fill="var(--cyber-bg-elevated)"
className="transition-colors duration-300"
/>
{/* Glowing Core */}
<circle
cx="50"
cy="50"
r="12"
fill="url(#logo-grad-primary)"
className="animate-pulse"
filter="url(#logo-glow)"
/>
{/* Lens Highlight */}
<circle
cx="46"
cy="46"
r="4"
fill="white"
fillOpacity="0.8"
/>
{/* Scanline Effect across the icon */}
<rect
x="15"
y="48"
width="70"
height="4"
fill="url(#logo-grad-primary)"
fillOpacity="0.2"
className="animate-[scan_3s_ease-in-out_infinite]"
>
<animate
attributeName="y"
values="25;75;25"
dur="3s"
repeatCount="indefinite"
/>
</rect>
</svg>
{/* Outer Glow for Hover */}
<div className="absolute inset-0 bg-primary/20 rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
</div>
{/* Text Section */}
{showText && !collapsed && (
<div className="flex flex-col transition-all duration-300">
<div
className={`${currentSize.text} font-bold tracking-wider font-mono leading-tight`}
style={{
textShadow: '0 0 25px rgba(255,107,44,0.4)',
color: 'var(--cyber-text)'
}}
>
<span className="text-primary">DEEP</span>
<span>AUDIT</span>
</div>
<div className={`${currentSize.sub} text-muted-foreground font-mono tracking-[0.2em] uppercase mt-0.5 whitespace-nowrap`}>
{subtitle}
</div>
</div>
)}
</div>
);
};
export default AppLogo;

View File

@ -26,6 +26,7 @@ import {
ExternalLink, ExternalLink,
GitGraph, GitGraph,
} from "lucide-react"; } from "lucide-react";
import AppLogo from "@/components/common/AppLogo";
import routes from "@/app/routes"; import routes from "@/app/routes";
import { version } from "../../../package.json"; import { version } from "../../../package.json";
@ -123,41 +124,14 @@ export default function Sidebar({ collapsed, setCollapsed }: SidebarProps) {
<Link <Link
to="/" to="/"
className={`flex items-center gap-3 group transition-all duration-300 ${collapsed ? 'justify-center' : 'flex-1 min-w-0'}`} className={`flex items-center group transition-all duration-300 ${collapsed ? 'justify-center' : 'flex-1 min-w-0'}`}
onClick={() => setMobileOpen(false)} onClick={() => setMobileOpen(false)}
> >
{/* Logo Icon with enhanced styling */} <AppLogo
<div className="relative flex-shrink-0"> collapsed={collapsed}
<div size="md"
className="w-11 h-11 rounded-xl flex items-center justify-center overflow-hidden transition-all duration-300 group-hover:shadow-[0_0_20px_rgba(255,107,44,0.3)]" subtitle="AI Code Review Bot"
style={{ />
background: 'linear-gradient(135deg, hsl(var(--primary) / 0.15), hsl(var(--primary) / 0.05))',
border: '1px solid hsl(var(--primary) / 0.4)'
}}
>
<img
src="/logo_deepaudit.png"
alt="DeepAudit"
className="w-7 h-7 object-contain transition-transform duration-300 group-hover:scale-110"
/>
</div>
{/* Glow effect */}
<div className="absolute inset-0 bg-primary/30 rounded-xl blur-xl opacity-0 group-hover:opacity-100 transition-opacity duration-500" />
</div>
{/* Logo Text with enhanced styling */}
<div className={`transition-all duration-300 ${collapsed ? 'w-0 opacity-0 overflow-hidden' : 'flex-1 min-w-0 opacity-100'}`}>
<div
className="text-xl font-bold tracking-wider font-mono leading-tight"
style={{ textShadow: '0 0 25px rgba(255,107,44,0.4)' }}
>
<span className="text-primary">DEEP</span>
<span style={{ color: 'var(--cyber-text)' }}>AUDIT</span>
</div>
<div className="text-[10px] text-muted-foreground tracking-[0.15em] uppercase mt-0.5">
Security Agent
</div>
</div>
</Link> </Link>
{/* Collapse button with enhanced styling */} {/* Collapse button with enhanced styling */}

View File

@ -5,6 +5,7 @@
*/ */
import { Square, Download, Play, Loader2, Radio, Cpu, Sparkles } from "lucide-react"; import { Square, Download, Play, Loader2, Radio, Cpu, Sparkles } from "lucide-react";
import AppLogo from "@/components/common/AppLogo";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { StatusBadge } from "./StatusBadge"; import { StatusBadge } from "./StatusBadge";
import type { HeaderProps } from "../types"; import type { HeaderProps } from "../types";
@ -26,27 +27,14 @@ export function Header({
{/* Left side - Brand and task info */} {/* Left side - Brand and task info */}
<div className="flex items-center gap-5 relative z-10"> <div className="flex items-center gap-5 relative z-10">
{/* Logo section with enhanced styling */}
<div className="flex items-center gap-3 pr-5 border-r border-border/50"> <div className="flex items-center gap-3 pr-5 border-r border-border/50">
<div className="relative group"> <AppLogo size="sm" subtitle="AI Code Review Bot" />
{/* Logo background glow */} {isRunning && (
<div className="absolute inset-0 bg-primary/20 rounded-lg blur-lg opacity-0 group-hover:opacity-100 transition-opacity duration-500" /> <div className="relative ml-[-12px] mt-[-20px]">
<div className="relative p-2 rounded-lg bg-gradient-to-br from-primary/20 to-primary/5 border border-primary/30"> <span className="absolute w-2 h-2 bg-emerald-400 rounded-full animate-pulse shadow-[0_0_10px_rgba(52,211,153,0.6)]" />
<Cpu className="w-5 h-5 text-primary" /> <span className="absolute w-2 h-2 bg-emerald-400 rounded-full animate-ping opacity-75" />
{isRunning && (
<>
<span className="absolute -top-1 -right-1 w-2.5 h-2.5 bg-emerald-400 rounded-full animate-pulse shadow-[0_0_10px_rgba(52,211,153,0.6)]" />
<span className="absolute -top-1 -right-1 w-2.5 h-2.5 bg-emerald-400 rounded-full animate-ping opacity-75" />
</>
)}
</div> </div>
</div> )}
<div className="flex flex-col">
<span className="font-bold text-foreground tracking-wider text-base leading-tight">
DEEP<span className="text-primary">AUDIT</span>
</span>
<span className="text-[10px] text-muted-foreground tracking-[0.2em] uppercase">Security Agent</span>
</div>
</div> </div>
{/* Task info with enhanced styling */} {/* Task info with enhanced styling */}

View File

@ -6,6 +6,7 @@
import { useState, useEffect, useRef, useCallback } from "react"; import { useState, useEffect, useRef, useCallback } from "react";
import { Shield, Zap } from "lucide-react"; import { Shield, Zap } from "lucide-react";
import AppLogo from "@/components/common/AppLogo";
interface SplashScreenProps { interface SplashScreenProps {
onComplete: () => void; onComplete: () => void;
@ -14,7 +15,7 @@ interface SplashScreenProps {
// Enhanced boot sequence messages with icons // Enhanced boot sequence messages with icons
const BOOT_SEQUENCE = [ const BOOT_SEQUENCE = [
{ text: "[INIT] Loading DeepAudit Core...", delay: 0, type: 'init' }, { text: "[INIT] Loading DeepAudit Core...", delay: 0, type: 'init' },
{ text: "[SCAN] Neural Analysis Engine v3.0", delay: 200, type: 'scan' }, { text: "[SCAN] AI Code Review Engine v3.0", delay: 200, type: 'scan' },
{ text: "[LOAD] Vulnerability Pattern Database", delay: 400, type: 'load' }, { text: "[LOAD] Vulnerability Pattern Database", delay: 400, type: 'load' },
{ text: "[SYNC] Agent Orchestration Module", delay: 600, type: 'sync' }, { text: "[SYNC] Agent Orchestration Module", delay: 600, type: 'sync' },
{ text: "[READY] System Online", delay: 800, type: 'ready' }, { text: "[READY] System Online", delay: 800, type: 'ready' },
@ -229,175 +230,148 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
<div className="w-full max-w-2xl"> <div className="w-full max-w-2xl">
{/* Logo with adaptive styling */} {/* Logo with adaptive styling */}
<div className={`text-center mb-10 transition-all duration-1000 ${showLogo ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-8"}`}> <div className={`text-center mb-10 transition-all duration-1000 ${showLogo ? "opacity-100 translate-y-0" : "opacity-0 -translate-y-8"}`}>
{/* Logo text - light mode: clean, dark mode: neon glow */} <div className="flex justify-center mb-6">
<div className="logo-glitch relative inline-block"> <AppLogo size="xl" subtitle="AI Code Review Bot" />
<div
className="text-5xl sm:text-6xl md:text-7xl font-bold tracking-wider mb-3 font-mono relative logo-text"
>
<span className="text-primary">DEEP</span>
<span className="text-gray-800 dark:text-white">AUDIT</span>
</div>
{/* Glitch layers - dark mode only, opacity controlled by CSS */}
<div className="glitch-layer glitch-layer-1 text-5xl sm:text-6xl md:text-7xl font-bold tracking-wider font-mono absolute top-0 left-0 w-full opacity-0 dark:opacity-0">
<span className="text-cyan-500">DEEP</span>
<span className="text-white">AUDIT</span>
</div>
<div className="glitch-layer glitch-layer-2 text-5xl sm:text-6xl md:text-7xl font-bold tracking-wider font-mono absolute top-0 left-0 w-full opacity-0 dark:opacity-0">
<span className="text-red-500">DEEP</span>
<span className="text-white">AUDIT</span>
</div>
</div> </div>
{/* Subtitle - adaptive styling */} </div>
<div className="flex items-center justify-center gap-3 text-gray-500 dark:text-gray-400 text-sm tracking-[0.3em] uppercase mt-4"> {/* Version tag */}
<div className="w-12 h-px bg-gradient-to-r from-transparent via-primary/40 dark:via-cyan-500/50 to-transparent" /> <div className="mt-2 text-[10px] font-mono text-primary/50 tracking-widest">
<Shield className="w-4 h-4 text-primary/70 dark:text-cyan-500/70" /> [ v3.0.0 // NEURAL_CORE ]
<span className="dark:cyber-text">Autonomous Security Agent</span> </div>
<Shield className="w-4 h-4 text-primary/70 dark:text-cyan-500/70" /> </div>
<div className="w-12 h-px bg-gradient-to-r from-transparent via-primary/40 dark:via-cyan-500/50 to-transparent" />
{/* Terminal window - adaptive styling */}
<div
className="relative rounded-xl overflow-hidden bg-white dark:bg-transparent border border-gray-200 dark:border-transparent shadow-xl dark:shadow-none"
onClick={handleTerminalClick}
>
{/* Terminal border glow - dark mode only */}
<div className="absolute inset-0 rounded-xl border border-primary/30 pointer-events-none hidden dark:block" />
<div className="absolute inset-0 rounded-xl shadow-[0_0_30px_rgba(255,107,44,0.2),inset_0_0_30px_rgba(0,0,0,0.5)] pointer-events-none hidden dark:block" />
{/* Terminal header - adaptive */}
<div className="relative flex items-center gap-3 px-4 py-2.5 bg-gray-100 dark:bg-gray-950 border-b border-gray-200 dark:border-primary/20">
{/* Window dots */}
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-red-400 dark:bg-red-500 dark:shadow-[0_0_10px_rgba(239,68,68,0.8)]" />
<div className="w-3 h-3 rounded-full bg-yellow-400 dark:bg-yellow-500 dark:shadow-[0_0_10px_rgba(234,179,8,0.8)]" />
<div className="w-3 h-3 rounded-full bg-green-400 dark:bg-green-500 dark:shadow-[0_0_10px_rgba(34,197,94,0.8)]" />
</div> </div>
{/* Version tag */} {/* Terminal title */}
<div className="mt-2 text-[10px] font-mono text-primary/50 tracking-widest"> <div className="flex-1 flex items-center justify-center gap-2">
[ v3.0.0 // NEURAL_CORE ] <span className="text-primary/60 text-xs"></span>
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono tracking-[0.15em] uppercase">
root@deepaudit:~#
</span>
<span className="w-2 h-4 bg-primary/80 animate-pulse" />
</div>
{/* Status indicator */}
<div className="flex items-center gap-1.5">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse dark:shadow-[0_0_6px_rgba(52,211,153,0.8)]" />
<span className="text-[10px] text-emerald-600 dark:text-emerald-500/80 font-mono">LIVE</span>
</div> </div>
</div> </div>
{/* Terminal window - adaptive styling */} {/* Terminal content - adaptive */}
<div <div
className="relative rounded-xl overflow-hidden bg-white dark:bg-transparent border border-gray-200 dark:border-transparent shadow-xl dark:shadow-none" ref={terminalRef}
onClick={handleTerminalClick} className="relative p-5 font-mono text-sm h-80 overflow-y-auto custom-scrollbar bg-gray-50 dark:bg-gray-950/95"
> >
{/* Terminal border glow - dark mode only */} {/* Boot logs - adaptive styling */}
<div className="absolute inset-0 rounded-xl border border-primary/30 pointer-events-none hidden dark:block" /> {bootLogs.map((log, i) => (
<div className="absolute inset-0 rounded-xl shadow-[0_0_30px_rgba(255,107,44,0.2),inset_0_0_30px_rgba(0,0,0,0.5)] pointer-events-none hidden dark:block" /> <div
key={`boot-${i}`}
{/* Terminal header - adaptive */} className={`mb-2 flex items-center gap-2 ${log.includes("[READY]") ? "text-emerald-600 dark:text-emerald-400" :
<div className="relative flex items-center gap-3 px-4 py-2.5 bg-gray-100 dark:bg-gray-950 border-b border-gray-200 dark:border-primary/20"> log.includes("[INIT]") ? "text-primary" :
{/* Window dots */}
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-red-400 dark:bg-red-500 dark:shadow-[0_0_10px_rgba(239,68,68,0.8)]" />
<div className="w-3 h-3 rounded-full bg-yellow-400 dark:bg-yellow-500 dark:shadow-[0_0_10px_rgba(234,179,8,0.8)]" />
<div className="w-3 h-3 rounded-full bg-green-400 dark:bg-green-500 dark:shadow-[0_0_10px_rgba(34,197,94,0.8)]" />
</div>
{/* Terminal title */}
<div className="flex-1 flex items-center justify-center gap-2">
<span className="text-primary/60 text-xs"></span>
<span className="text-xs text-gray-500 dark:text-gray-400 font-mono tracking-[0.15em] uppercase">
root@deepaudit:~#
</span>
<span className="w-2 h-4 bg-primary/80 animate-pulse" />
</div>
{/* Status indicator */}
<div className="flex items-center gap-1.5">
<span className="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse dark:shadow-[0_0_6px_rgba(52,211,153,0.8)]" />
<span className="text-[10px] text-emerald-600 dark:text-emerald-500/80 font-mono">LIVE</span>
</div>
</div>
{/* Terminal content - adaptive */}
<div
ref={terminalRef}
className="relative p-5 font-mono text-sm h-80 overflow-y-auto custom-scrollbar bg-gray-50 dark:bg-gray-950/95"
>
{/* Boot logs - adaptive styling */}
{bootLogs.map((log, i) => (
<div
key={`boot-${i}`}
className={`mb-2 flex items-center gap-2 ${
log.includes("[READY]") ? "text-emerald-600 dark:text-emerald-400" :
log.includes("[INIT]") ? "text-primary" :
log.includes("[SCAN]") ? "text-violet-600 dark:text-violet-400" : log.includes("[SCAN]") ? "text-violet-600 dark:text-violet-400" :
log.includes("[LOAD]") ? "text-amber-600 dark:text-amber-400" : log.includes("[LOAD]") ? "text-amber-600 dark:text-amber-400" :
log.includes("[SYNC]") ? "text-cyan-600 dark:text-cyan-400" : log.includes("[SYNC]") ? "text-cyan-600 dark:text-cyan-400" :
"text-gray-500" "text-gray-500"
}`} }`}
style={{ style={{
animation: "fadeSlideIn 0.3s ease-out", animation: "fadeSlideIn 0.3s ease-out",
animationFillMode: "both", animationFillMode: "both",
animationDelay: `${i * 0.08}s` animationDelay: `${i * 0.08}s`
}} }}
> >
<span className="text-emerald-600 dark:text-emerald-500/60">$</span> <span className="text-emerald-600 dark:text-emerald-500/60">$</span>
<span className={`w-1.5 h-1.5 rounded-full ${ <span className={`w-1.5 h-1.5 rounded-full ${log.includes("[READY]") ? "bg-emerald-500 dark:shadow-[0_0_8px_rgba(52,211,153,0.8)]" :
log.includes("[READY]") ? "bg-emerald-500 dark:shadow-[0_0_8px_rgba(52,211,153,0.8)]" : log.includes("[INIT]") ? "bg-primary dark:shadow-[0_0_8px_rgba(255,107,44,0.8)]" :
log.includes("[INIT]") ? "bg-primary dark:shadow-[0_0_8px_rgba(255,107,44,0.8)]" :
log.includes("[SCAN]") ? "bg-violet-500 dark:shadow-[0_0_8px_rgba(167,139,250,0.8)]" : log.includes("[SCAN]") ? "bg-violet-500 dark:shadow-[0_0_8px_rgba(167,139,250,0.8)]" :
log.includes("[LOAD]") ? "bg-amber-500 dark:shadow-[0_0_8px_rgba(251,191,36,0.8)]" : log.includes("[LOAD]") ? "bg-amber-500 dark:shadow-[0_0_8px_rgba(251,191,36,0.8)]" :
log.includes("[SYNC]") ? "bg-cyan-500 dark:shadow-[0_0_8px_rgba(34,211,238,0.8)]" : log.includes("[SYNC]") ? "bg-cyan-500 dark:shadow-[0_0_8px_rgba(34,211,238,0.8)]" :
"bg-gray-400 dark:bg-gray-600" "bg-gray-400 dark:bg-gray-600"
}`} /> }`} />
<span>{log}</span> <span>{log}</span>
</div> </div>
))} ))}
{/* Welcome message - adaptive */} {/* Welcome message - adaptive */}
{bootComplete && ( {bootComplete && (
<div className="mt-5 mb-4 pt-4 border-t border-gray-200 dark:border-primary/20"> <div className="mt-5 mb-4 pt-4 border-t border-gray-200 dark:border-primary/20">
<div className="flex items-center gap-2 text-primary mb-2"> <div className="flex items-center gap-2 text-primary mb-2">
<Zap className="w-4 h-4 text-cyan-600 dark:text-cyan-400" /> <Zap className="w-4 h-4 text-cyan-600 dark:text-cyan-400" />
<span className="font-semibold text-cyan-600 dark:text-cyan-400">// SYSTEM READY</span> <span className="font-semibold text-cyan-600 dark:text-cyan-400">// SYSTEM READY</span>
</div>
<div className="text-gray-600 dark:text-gray-400 text-sm pl-6">
Execute <span className="text-emerald-600 dark:text-emerald-400 font-bold px-2 py-0.5 bg-emerald-500/10 dark:bg-emerald-500/20 border border-emerald-500/30 rounded">'audit'</span> to initialize security scan protocol
</div>
<div className="text-gray-400 dark:text-gray-600 text-xs pl-6 mt-1">
[ Type 'help' for available commands ]
</div>
</div> </div>
)} <div className="text-gray-600 dark:text-gray-400 text-sm pl-6">
Execute <span className="text-emerald-600 dark:text-emerald-400 font-bold px-2 py-0.5 bg-emerald-500/10 dark:bg-emerald-500/20 border border-emerald-500/30 rounded">'audit'</span> to initialize security scan protocol
{/* Command history */}
{commandHistory.map((entry, i) => (
<div key={`cmd-${i}`} className="mb-2">
<div className="flex items-center gap-2 text-foreground">
<span className="text-emerald-500">$</span>
<span>{entry.input}</span>
</div>
{entry.output && (
<div className={`ml-4 mt-1 whitespace-pre-wrap text-xs ${
entry.isError ? "text-red-400" : "text-muted-foreground"
}`}>
{entry.output}
</div>
)}
</div> </div>
))} <div className="text-gray-400 dark:text-gray-600 text-xs pl-6 mt-1">
[ Type 'help' for available commands ]
</div>
</div>
)}
{/* Current input line */} {/* Command history */}
{bootComplete && ( {commandHistory.map((entry, i) => (
<div key={`cmd-${i}`} className="mb-2">
<div className="flex items-center gap-2 text-foreground"> <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"> <span>{entry.input}</span>
<input
ref={inputRef}
type="text"
value={currentInput}
onChange={(e) => setCurrentInput(e.target.value)}
onKeyDown={handleKeyDown}
className="absolute inset-0 w-full bg-transparent text-transparent outline-none border-none"
style={{ caretColor: "transparent" }}
spellCheck={false}
autoComplete="off"
autoFocus
/>
<span className="text-foreground">{currentInput}</span>
<span
className={`inline-block w-2 h-4 bg-emerald-400 ml-0.5 align-middle transition-opacity ${
cursorBlink ? "opacity-100" : "opacity-0"
}`}
/>
</div>
</div> </div>
)} {entry.output && (
</div> <div className={`ml-4 mt-1 whitespace-pre-wrap text-xs ${entry.isError ? "text-red-400" : "text-muted-foreground"
</div> }`}>
{entry.output}
</div>
)}
</div>
))}
{/* Hint */} {/* Current input line */}
<div className={`mt-4 text-center transition-all duration-500 ${bootComplete ? "opacity-100" : "opacity-0"}`}> {bootComplete && (
<div className="flex items-center justify-center gap-3"> <div className="flex items-center gap-2 text-foreground">
<div className="h-px w-8 bg-gradient-to-r from-transparent to-gray-700" /> <span className="text-emerald-500">$</span>
<span className="text-muted-foreground text-xs font-mono tracking-wider">PRESS ENTER TO EXECUTE</span> <div className="flex-1 relative">
<div className="h-px w-8 bg-gradient-to-l from-transparent to-gray-700" /> <input
</div> ref={inputRef}
type="text"
value={currentInput}
onChange={(e) => setCurrentInput(e.target.value)}
onKeyDown={handleKeyDown}
className="absolute inset-0 w-full bg-transparent text-transparent outline-none border-none"
style={{ caretColor: "transparent" }}
spellCheck={false}
autoComplete="off"
autoFocus
/>
<span className="text-foreground">{currentInput}</span>
<span
className={`inline-block w-2 h-4 bg-emerald-400 ml-0.5 align-middle transition-opacity ${cursorBlink ? "opacity-100" : "opacity-0"
}`}
/>
</div>
</div>
)}
</div>
</div>
{/* Hint */}
<div className={`mt-4 text-center transition-all duration-500 ${bootComplete ? "opacity-100" : "opacity-0"}`}>
<div className="flex items-center justify-center gap-3">
<div className="h-px w-8 bg-gradient-to-r from-transparent to-gray-700" />
<span className="text-muted-foreground text-xs font-mono tracking-wider">PRESS ENTER TO EXECUTE</span>
<div className="h-px w-8 bg-gradient-to-l from-transparent to-gray-700" />
</div> </div>
</div> </div>
</div> </div>
@ -572,7 +546,7 @@ export function SplashScreen({ onComplete }: SplashScreenProps) {
text-shadow: 0 0 10px rgba(52,211,153,0.8), 0 0 20px rgba(52,211,153,0.4); text-shadow: 0 0 10px rgba(52,211,153,0.8), 0 0 20px rgba(52,211,153,0.4);
} }
`}</style> `}</style>
</div> </div >
); );
} }

View File

@ -241,6 +241,6 @@ export const DEEPAUDIT_ASCII = `
| |_| | |___| |___| __/ ___ \\ |_| | |_| | | | | | |_| | |___| |___| __/ ___ \\ |_| | |_| | | | |
|____/|_____|_____|_| /_/ \\_\\___/|____/___| |_| |____/|_____|_____|_| /_/ \\_\\___/|____/___| |_|
[ Autonomous Security Agent ] [ AI Code Review Bot ]
`; `;

View File

@ -13,6 +13,7 @@ import { Label } from "@/components/ui/label";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { toast } from "sonner"; import { toast } from "sonner";
import { Lock, Mail, Terminal, Shield, Fingerprint, Cpu } from "lucide-react"; import { Lock, Mail, Terminal, Shield, Fingerprint, Cpu } from "lucide-react";
import AppLogo from "@/components/common/AppLogo";
import { version } from "../../package.json"; import { version } from "../../package.json";
export default function Login() { export default function Login() {
@ -143,29 +144,14 @@ 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 cyber-dialog border border-border/60 rounded-lg mb-6" <div className="flex flex-col items-center justify-center mb-6">
style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}> <AppLogo size="lg" subtitle="AI Code Review Bot" />
<img
src="/logo_deepaudit.png"
alt="DeepAudit"
className="w-14 h-14 object-contain"
/>
</div> </div>
<div
className="text-3xl font-bold tracking-wider mb-2 font-mono"
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-foreground">AUDIT</span>
</div>
<p className="text-base font-mono text-muted-foreground">
// Autonomous Security Agent
</p>
</div> </div>
{/* Login Form Card */} {/* Login Form Card */}
<div className="cyber-dialog border border-border/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 cyber-bg-elevated border-b border-border"> <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">

View File

@ -11,6 +11,7 @@ import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label'; import { Label } from '@/components/ui/label';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { User, Mail, Lock, Terminal, Shield, Cpu } from 'lucide-react'; import { User, Mail, Lock, Terminal, Shield, Cpu } from 'lucide-react';
import AppLogo from '@/components/common/AppLogo';
import { version } from '../../package.json'; import { version } from '../../package.json';
export default function Register() { export default function Register() {
@ -112,29 +113,14 @@ 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 cyber-dialog border border-border/60 rounded-lg mb-6" <div className="flex flex-col items-center justify-center mb-6">
style={{ boxShadow: '0 0 30px rgba(255,107,44,0.1)' }}> <AppLogo size="lg" subtitle="Create New Account" />
<img
src="/logo_deepaudit.png"
alt="DeepAudit"
className="w-14 h-14 object-contain"
/>
</div> </div>
<div
className="text-3xl font-bold tracking-wider mb-2 font-mono"
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-foreground">AUDIT</span>
</div>
<p className="text-sm font-mono text-muted-foreground">
// Create New Account
</p>
</div> </div>
{/* Register Form Card */} {/* Register Form Card */}
<div className="cyber-dialog border border-border/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 cyber-bg-elevated border-b border-border"> <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">

View File

@ -4,7 +4,7 @@ import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/com
import { Badge } from "@/components/ui/badge"; import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { GitGraph, ArrowRight, Trash2, Clock } from "lucide-react"; import { GitGraph, ArrowRight, Trash2, Clock } from "lucide-react";
import { formatDistanceToNow } from 'date-fns'; import { formatDistanceToNowStrict } from 'date-fns';
import { zhCN } from 'date-fns/locale'; import { zhCN } from 'date-fns/locale';
interface CIProject { interface CIProject {
@ -102,7 +102,7 @@ const CIProjects: React.FC = () => {
<div className="flex items-center gap-2 text-sm text-muted-foreground"> <div className="flex items-center gap-2 text-sm text-muted-foreground">
<Clock className="w-4 h-4" /> <Clock className="w-4 h-4" />
<span> <span>
Latest: {project.latest_pr_activity ? formatDistanceToNow(new Date(project.latest_pr_activity), { addSuffix: true, locale: zhCN }) : 'Never'} AI : {project.latest_pr_activity ? formatDistanceToNowStrict(new Date(project.latest_pr_activity), { addSuffix: true, locale: zhCN }) : '从无回复'}
</span> </span>
</div> </div>