feat: Introduce reusable AppLogo component and update project activity timestamp to UTC.
This commit is contained in:
parent
a29f57d119
commit
7a3bb08d48
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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 */}
|
||||||
|
|
|
||||||
|
|
@ -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 */}
|
||||||
|
|
|
||||||
|
|
@ -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 >
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -241,6 +241,6 @@ export const DEEPAUDIT_ASCII = `
|
||||||
║ | |_| | |___| |___| __/ ___ \\ |_| | |_| | | | | ║
|
║ | |_| | |___| |___| __/ ___ \\ |_| | |_| | | | | ║
|
||||||
║ |____/|_____|_____|_| /_/ \\_\\___/|____/___| |_| ║
|
║ |____/|_____|_____|_| /_/ \\_\\___/|____/___| |_| ║
|
||||||
║ ║
|
║ ║
|
||||||
║ [ Autonomous Security Agent ] ║
|
║ [ AI Code Review Bot ] ║
|
||||||
║ ║
|
║ ║
|
||||||
╚═══════════════════════════════════════════════════════════════╝`;
|
╚═══════════════════════════════════════════════════════════════╝`;
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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">
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue