diff --git a/frontend/src/components/common/LoadingSkeleton.tsx b/frontend/src/components/common/LoadingSkeleton.tsx
new file mode 100644
index 0000000..1e9518e
--- /dev/null
+++ b/frontend/src/components/common/LoadingSkeleton.tsx
@@ -0,0 +1,240 @@
+import React from 'react';
+import { Box, Skeleton, Card, CardContent, Grid, useTheme, alpha } from '@mui/material';
+
+/**
+ * Professional Loading Skeleton Components
+ * Provides smooth loading states instead of spinners
+ */
+
+// Lab Card Skeleton
+export const LabCardSkeleton: React.FC = () => {
+ const theme = useTheme();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+// Lab Grid Skeleton
+export const LabGridSkeleton: React.FC<{ count?: number }> = ({ count = 6 }) => {
+ return (
+
+ {Array.from({ length: count }).map((_, index) => (
+
+
+
+ ))}
+
+ );
+};
+
+// Dashboard Widget Skeleton
+export const DashboardWidgetSkeleton: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+// Table Row Skeleton
+export const TableRowSkeleton: React.FC<{ columns?: number }> = ({ columns = 5 }) => {
+ return (
+
+ {Array.from({ length: columns }).map((_, index) => (
+
+ ))}
+
+ );
+};
+
+// Profile Skeleton
+export const ProfileSkeleton: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+// Stats Card Skeleton
+export const StatsCardSkeleton: React.FC = () => {
+ return (
+
+ `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)} 0%, ${alpha(
+ theme.palette.secondary.main,
+ 0.1
+ )} 100%)`,
+ }}
+ >
+
+
+
+
+
+
+
+
+
+ );
+};
+
+// List Item Skeleton
+export const ListItemSkeleton: React.FC<{ avatar?: boolean }> = ({ avatar = true }) => {
+ return (
+
+ {avatar && }
+
+
+
+
+
+
+ );
+};
+
+// Form Skeleton
+export const FormSkeleton: React.FC<{ fields?: number }> = ({ fields = 4 }) => {
+ return (
+
+
+
+ {Array.from({ length: fields }).map((_, index) => (
+
+
+
+
+ ))}
+
+
+
+ );
+};
+
+// Progress Bar Skeleton
+export const ProgressSkeleton: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
+
+// Full Page Skeleton (combines multiple skeletons)
+export const PageSkeleton: React.FC = () => {
+ return (
+
+
+
+ {[1, 2, 3, 4].map((i) => (
+
+
+
+ ))}
+
+
+
+ );
+};
+
+// Export all as a single object for convenience
+export const LoadingSkeletons = {
+ LabCard: LabCardSkeleton,
+ LabGrid: LabGridSkeleton,
+ DashboardWidget: DashboardWidgetSkeleton,
+ TableRow: TableRowSkeleton,
+ Profile: ProfileSkeleton,
+ StatsCard: StatsCardSkeleton,
+ ListItem: ListItemSkeleton,
+ Form: FormSkeleton,
+ Progress: ProgressSkeleton,
+ Page: PageSkeleton,
+};
+
+export default LoadingSkeletons;
diff --git a/frontend/src/components/labs/LabCard.tsx b/frontend/src/components/labs/LabCard.tsx
index 48a65ca..84ed2c2 100644
--- a/frontend/src/components/labs/LabCard.tsx
+++ b/frontend/src/components/labs/LabCard.tsx
@@ -9,12 +9,16 @@ import {
Box,
Button,
LinearProgress,
+ alpha,
+ useTheme,
} from '@mui/material';
import {
AccessTime,
EmojiEvents,
PlayArrow,
Lock,
+ CheckCircle,
+ TrendingUp,
} from '@mui/icons-material';
import { useNavigate } from 'react-router-dom';
import type { Lab, LabDifficulty } from '../../types';
@@ -23,12 +27,14 @@ interface LabCardProps {
lab: Lab;
progress?: number;
isLocked?: boolean;
+ isNew?: boolean;
+ isFeatured?: boolean;
}
const DIFFICULTY_COLORS: Record = {
- beginner: '#4caf50',
- intermediate: '#ff9800',
- advanced: '#f44336',
+ beginner: '#00ff88',
+ intermediate: '#ffb020',
+ advanced: '#ff5f56',
expert: '#9c27b0',
};
@@ -42,18 +48,28 @@ const CATEGORY_LABELS: Record = {
};
/**
- * LabCard Component
- * Displays individual lab information with progress and actions
+ * Modern LabCard Component
+ * Features: Glassmorphism, neon borders, smooth animations, professional design
*/
-export const LabCard: React.FC = ({ lab, progress = 0, isLocked = false }) => {
+export const LabCard: React.FC = ({
+ lab,
+ progress = 0,
+ isLocked = false,
+ isNew = false,
+ isFeatured = false,
+}) => {
const navigate = useNavigate();
+ const theme = useTheme();
const handleStartLab = () => {
- navigate(`/labs/${lab.id}`);
+ if (!isLocked) {
+ navigate(`/labs/${lab.id}`);
+ }
};
const difficultyColor = DIFFICULTY_COLORS[lab.difficulty];
const categoryLabel = CATEGORY_LABELS[lab.category] || lab.category;
+ const isCompleted = progress === 100;
return (
= ({ lab, progress = 0, isLocked =
display: 'flex',
flexDirection: 'column',
position: 'relative',
- transition: 'transform 0.2s, box-shadow 0.2s',
+ overflow: 'hidden',
+ transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
+ cursor: isLocked ? 'not-allowed' : 'pointer',
+ border: `2px solid ${isCompleted ? '#00ff88' : alpha(difficultyColor, 0.3)}`,
+ background:
+ theme.palette.mode === 'dark'
+ ? `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.9)} 0%, ${alpha(
+ theme.palette.background.default,
+ 0.9
+ )} 100%)`
+ : theme.palette.background.paper,
+ backdropFilter: 'blur(10px)',
+ opacity: isLocked ? 0.6 : 1,
'&:hover': {
- transform: isLocked ? 'none' : 'translateY(-4px)',
- boxShadow: isLocked ? 1 : 8,
+ transform: isLocked ? 'none' : 'translateY(-8px) scale(1.02)',
+ boxShadow: isLocked
+ ? theme.shadows[2]
+ : `0 12px 40px ${alpha(difficultyColor, 0.3)}, 0 0 20px ${alpha(difficultyColor, 0.2)}`,
+ border: `2px solid ${isLocked ? alpha(difficultyColor, 0.3) : difficultyColor}`,
+ },
+ '&::before': !isLocked && {
+ content: '""',
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ height: '4px',
+ background: `linear-gradient(90deg, ${difficultyColor}, ${alpha(difficultyColor, 0.5)})`,
+ opacity: 0,
+ transition: 'opacity 0.3s ease',
+ },
+ '&:hover::before': !isLocked && {
+ opacity: 1,
},
- opacity: isLocked ? 0.7 : 1,
}}
+ onClick={handleStartLab}
>
- {/* Lab Image */}
+ {/* Status Badges */}
+ {(isNew || isFeatured || isCompleted) && (
+
+ {isNew && (
+
+ )}
+ {isFeatured && (
+
+ )}
+ {isCompleted && (
+ }
+ label="COMPLETED"
+ size="small"
+ sx={{
+ background: `linear-gradient(135deg, #00ff88 0%, #00cc6d 100%)`,
+ color: 'white',
+ fontWeight: 700,
+ fontSize: '0.65rem',
+ height: 22,
+ }}
+ />
+ )}
+
+ )}
+
+ {/* Lab Image with Overlay Gradient */}
{/* Difficulty Badge */}
@@ -92,10 +208,14 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
position: 'absolute',
top: 12,
right: 12,
- backgroundColor: difficultyColor,
- color: 'white',
- fontWeight: 'bold',
- fontSize: '0.75rem',
+ zIndex: 2,
+ background: difficultyColor,
+ color: theme.palette.mode === 'dark' ? '#000' : '#fff',
+ fontWeight: 800,
+ fontSize: '0.7rem',
+ letterSpacing: '0.05em',
+ boxShadow: `0 4px 12px ${alpha(difficultyColor, 0.4)}`,
+ border: `2px solid ${theme.palette.mode === 'dark' ? '#000' : '#fff'}`,
}}
/>
@@ -109,28 +229,63 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
right: 0,
bottom: 0,
display: 'flex',
+ flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
- backgroundColor: 'rgba(0, 0, 0, 0.6)',
+ background: 'rgba(0, 0, 0, 0.75)',
+ backdropFilter: 'blur(8px)',
+ zIndex: 3,
}}
>
-
+
+
+ Complete previous labs to unlock
+
)}
{/* Lab Info */}
-
- {/* Category */}
+
+ {/* Category Badge */}
{/* Lab Name */}
-
+
{lab.name}
@@ -146,25 +301,71 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
WebkitLineClamp: 2,
WebkitBoxOrient: 'vertical',
minHeight: '2.8em',
+ lineHeight: 1.4,
}}
>
{lab.description}
- {/* Metadata */}
-
-
-
-
+ {/* Metadata with Icons */}
+
+
+
+
{lab.estimatedTime}min
-
-
-
+
+
+
{lab.points} pts
+ {progress > 0 && progress < 100 && (
+
+
+
+ {progress}% done
+
+
+ )}
{/* Tags */}
@@ -174,28 +375,41 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
key={tag}
label={tag}
size="small"
- variant="outlined"
- sx={{ fontSize: '0.65rem', height: 20 }}
+ sx={{
+ fontSize: '0.65rem',
+ height: 22,
+ background: alpha(theme.palette.primary.main, 0.08),
+ color: theme.palette.primary.main,
+ fontWeight: 600,
+ '&:hover': {
+ background: alpha(theme.palette.primary.main, 0.15),
+ },
+ }}
/>
))}
{lab.tags.length > 3 && (
)}
{/* Progress Bar */}
- {progress > 0 && (
+ {progress > 0 && progress < 100 && (
-
+
Progress
-
+
{progress}%
@@ -203,12 +417,12 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
variant="determinate"
value={progress}
sx={{
- height: 6,
- borderRadius: 3,
- backgroundColor: 'grey.200',
+ height: 8,
+ borderRadius: 4,
+ background: alpha(theme.palette.primary.main, 0.1),
'& .MuiLinearProgress-bar': {
- borderRadius: 3,
- backgroundColor: progress === 100 ? '#4caf50' : '#2196f3',
+ borderRadius: 4,
+ background: `linear-gradient(90deg, ${theme.palette.primary.main}, ${theme.palette.secondary.main})`,
},
}}
/>
@@ -220,21 +434,34 @@ export const LabCard: React.FC = ({ lab, progress = 0, isLocked =
diff --git a/frontend/src/components/labs/Terminal.tsx b/frontend/src/components/labs/Terminal.tsx
new file mode 100644
index 0000000..d43a2cf
--- /dev/null
+++ b/frontend/src/components/labs/Terminal.tsx
@@ -0,0 +1,366 @@
+import React, { useEffect, useRef, useState } from 'react';
+import { Box, IconButton, Typography, Chip, alpha, useTheme } from '@mui/material';
+import ContentCopyIcon from '@mui/icons-material/ContentCopy';
+import RefreshIcon from '@mui/icons-material/Refresh';
+import FullscreenIcon from '@mui/icons-material/Fullscreen';
+import CloseIcon from '@mui/icons-material/Close';
+
+/**
+ * Professional Terminal Component
+ * Features: Command history, syntax highlighting, copy functionality
+ * Note: In production, integrate with xterm.js for full terminal emulation
+ */
+
+interface TerminalProps {
+ labId?: string;
+ instanceId?: string;
+ onClose?: () => void;
+}
+
+const Terminal: React.FC = ({ labId, instanceId, onClose }) => {
+ const theme = useTheme();
+ const terminalRef = useRef(null);
+ const inputRef = useRef(null);
+
+ const [output, setOutput] = useState>([
+ { type: 'output', text: '╔════════════════════════════════════════════════════════════════╗' },
+ { type: 'output', text: '║ AURON SECURITY LAB - TERMINAL v2.0.0 ║' },
+ { type: 'output', text: '╚════════════════════════════════════════════════════════════════╝' },
+ { type: 'output', text: '' },
+ { type: 'output', text: '🔒 Secure connection established...' },
+ { type: 'output', text: '📡 Connected to lab environment' },
+ { type: 'output', text: `🆔 Lab ID: ${labId || 'sandbox-001'}` },
+ { type: 'output', text: '' },
+ { type: 'output', text: 'Type "help" for available commands or "exit" to disconnect.' },
+ { type: 'output', text: '' },
+ ]);
+
+ const [currentInput, setCurrentInput] = useState('');
+ const [commandHistory, setCommandHistory] = useState([]);
+ const [historyIndex, setHistoryIndex] = useState(-1);
+ const [isConnected, setIsConnected] = useState(true);
+
+ // Available commands (demo - replace with real shell commands in production)
+ const commands: Record string[]> = {
+ help: () => [
+ 'Available commands:',
+ ' help - Show this help message',
+ ' ls - List files and directories',
+ ' pwd - Print working directory',
+ ' whoami - Display current user',
+ ' cat - Display file contents',
+ ' clear - Clear terminal',
+ ' date - Show current date and time',
+ ' uname - Show system information',
+ ' exit - Disconnect from terminal',
+ '',
+ 'Note: This is a demo terminal. In production, this connects to a real shell.',
+ ],
+ ls: () => [
+ 'drwxr-xr-x 5 auron auron 160 Nov 18 12:34 .',
+ 'drwxr-xr-x 8 auron auron 256 Nov 17 09:15 ..',
+ '-rw-r--r-- 1 auron auron 1234 Nov 18 11:20 exploit.py',
+ '-rw-r--r-- 1 auron auron 456 Nov 18 10:15 notes.txt',
+ 'drwxr-xr-x 3 auron auron 96 Nov 17 14:22 payloads',
+ '-rwxr-xr-x 1 auron auron 2048 Nov 18 12:34 scan.sh',
+ ],
+ pwd: () => ['/home/auron/lab'],
+ whoami: () => ['auron'],
+ date: () => [new Date().toString()],
+ uname: () => ['Linux auron-lab 5.15.0-1044-aws #49-Ubuntu SMP Thu Oct 6 02:08:18 UTC 2023 x86_64 GNU/Linux'],
+ clear: () => [],
+ cat: (args) => {
+ if (args.length === 0) return ['cat: missing file operand'];
+ if (args[0] === 'notes.txt') {
+ return [
+ '=== Security Lab Notes ===',
+ '',
+ '1. Check for SQL injection vulnerabilities',
+ '2. Test XSS on input fields',
+ '3. Enumerate open ports: nmap -sV target',
+ '4. Try default credentials',
+ '',
+ '⚠️ Remember to log all findings!',
+ ];
+ }
+ return [`cat: ${args[0]}: No such file or directory`];
+ },
+ };
+
+ const executeCommand = (cmd: string) => {
+ const trimmed = cmd.trim();
+ if (!trimmed) return;
+
+ // Add to history
+ setCommandHistory((prev) => [...prev, trimmed]);
+ setHistoryIndex(-1);
+
+ // Add command to output
+ setOutput((prev) => [...prev, { type: 'input', text: `$ ${trimmed}` }]);
+
+ // Handle exit
+ if (trimmed === 'exit') {
+ setOutput((prev) => [
+ ...prev,
+ { type: 'output', text: 'Connection closed. Goodbye!' },
+ ]);
+ setIsConnected(false);
+ setTimeout(() => onClose?.(), 1500);
+ return;
+ }
+
+ // Handle clear
+ if (trimmed === 'clear') {
+ setOutput([]);
+ return;
+ }
+
+ // Parse command and arguments
+ const parts = trimmed.split(' ');
+ const command = parts[0];
+ const args = parts.slice(1);
+
+ // Execute command
+ if (commands[command]) {
+ const result = commands[command](args);
+ setOutput((prev) => [
+ ...prev,
+ ...result.map((line) => ({ type: 'output' as const, text: line })),
+ ]);
+ } else {
+ setOutput((prev) => [
+ ...prev,
+ { type: 'error', text: `Command not found: ${command}` },
+ { type: 'output', text: 'Type "help" for available commands.' },
+ ]);
+ }
+ };
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ executeCommand(currentInput);
+ setCurrentInput('');
+ } else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ if (commandHistory.length > 0) {
+ const newIndex = historyIndex < commandHistory.length - 1 ? historyIndex + 1 : historyIndex;
+ setHistoryIndex(newIndex);
+ setCurrentInput(commandHistory[commandHistory.length - 1 - newIndex]);
+ }
+ } else if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ if (historyIndex > 0) {
+ const newIndex = historyIndex - 1;
+ setHistoryIndex(newIndex);
+ setCurrentInput(commandHistory[commandHistory.length - 1 - newIndex]);
+ } else if (historyIndex === 0) {
+ setHistoryIndex(-1);
+ setCurrentInput('');
+ }
+ }
+ };
+
+ const copyToClipboard = () => {
+ const text = output.map((line) => line.text).join('\n');
+ navigator.clipboard.writeText(text);
+ };
+
+ const handleRefresh = () => {
+ setOutput([
+ { type: 'output', text: 'Reconnecting to lab environment...' },
+ { type: 'output', text: '✓ Connection re-established' },
+ { type: 'output', text: '' },
+ ]);
+ setIsConnected(true);
+ };
+
+ // Auto-scroll to bottom
+ useEffect(() => {
+ if (terminalRef.current) {
+ terminalRef.current.scrollTop = terminalRef.current.scrollHeight;
+ }
+ }, [output]);
+
+ // Focus input on mount
+ useEffect(() => {
+ inputRef.current?.focus();
+ }, []);
+
+ return (
+
+ {/* Terminal Header */}
+
+
+
+
+
+
+ auron@lab:~
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {onClose && (
+
+
+
+ )}
+
+
+
+ {/* Terminal Output */}
+
+ {output.map((line, index) => (
+
+ {line.text}
+
+ ))}
+
+ {/* Input Line */}
+ {isConnected && (
+
+ $
+ setCurrentInput(e.target.value)}
+ onKeyDown={handleKeyDown}
+ style={{
+ flex: 1,
+ background: 'transparent',
+ border: 'none',
+ outline: 'none',
+ color: '#ffffff',
+ fontFamily: 'inherit',
+ fontSize: 'inherit',
+ caretColor: '#00ff41',
+ }}
+ autoFocus
+ />
+
+
+ )}
+
+
+ );
+};
+
+export default Terminal;
diff --git a/frontend/src/components/layout/AppBar.tsx b/frontend/src/components/layout/AppBar.tsx
index 43b2bc7..1a09a75 100644
--- a/frontend/src/components/layout/AppBar.tsx
+++ b/frontend/src/components/layout/AppBar.tsx
@@ -1,8 +1,24 @@
-import { AppBar as MuiAppBar, Toolbar, IconButton, Typography, Box, Avatar, Menu, MenuItem } from '@mui/material';
+import {
+ AppBar as MuiAppBar,
+ Toolbar,
+ IconButton,
+ Typography,
+ Box,
+ Avatar,
+ Menu,
+ MenuItem,
+ alpha,
+ useTheme,
+ Fade,
+ Slide,
+ Badge,
+} from '@mui/material';
import MenuIcon from '@mui/icons-material/Menu';
import AccountCircleIcon from '@mui/icons-material/AccountCircle';
import LogoutIcon from '@mui/icons-material/Logout';
-import { useState } from 'react';
+import NotificationsIcon from '@mui/icons-material/Notifications';
+import SettingsIcon from '@mui/icons-material/Settings';
+import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useAppDispatch, useAppSelector } from '@hooks/redux';
import { logout } from '@features/auth/authSlice';
@@ -12,12 +28,27 @@ interface AppBarProps {
handleDrawerToggle: () => void;
}
+/**
+ * Modern AppBar Component
+ * Features: Glassmorphism, scroll elevation, smooth animations
+ */
export default function AppBar({ drawerWidth, handleDrawerToggle }: AppBarProps): JSX.Element {
const [anchorEl, setAnchorEl] = useState(null);
+ const [scrolled, setScrolled] = useState(false);
const dispatch = useAppDispatch();
const navigate = useNavigate();
+ const theme = useTheme();
const { user } = useAppSelector((state) => state.auth);
+ // Handle scroll effect
+ useEffect(() => {
+ const handleScroll = () => {
+ setScrolled(window.scrollY > 20);
+ };
+ window.addEventListener('scroll', handleScroll);
+ return () => window.removeEventListener('scroll', handleScroll);
+ }, []);
+
const handleMenu = (event: React.MouseEvent): void => {
setAnchorEl(event.currentTarget);
};
@@ -37,46 +68,253 @@ export default function AppBar({ drawerWidth, handleDrawerToggle }: AppBarProps)
handleClose();
};
+ const handleSettings = (): void => {
+ navigate('/settings');
+ handleClose();
+ };
+
return (
-
-
-
-
-
-
- Auron Security Platform
-
-
-
- {user?.avatar ? (
-
- ) : (
-
- )}
+
+
+
+
+
-
-
-
-
+
+ {/* Logo and Title */}
+ navigate('/dashboard')}
+ >
+
+ A
+
+
+ Auron Security
+
+
+
+ {/* Action Icons */}
+
+ {/* Notifications */}
+
+
+
+
+
+
+ {/* User Menu */}
+
+ {user?.avatar ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
);
}
diff --git a/frontend/src/components/progress/ProgressDashboard.tsx b/frontend/src/components/progress/ProgressDashboard.tsx
index 8ffb36a..67bfce8 100644
--- a/frontend/src/components/progress/ProgressDashboard.tsx
+++ b/frontend/src/components/progress/ProgressDashboard.tsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import React, { useEffect, useState } from 'react';
import {
Box,
Grid,
@@ -9,6 +9,11 @@ import {
Card,
CardContent,
Avatar,
+ Button,
+ alpha,
+ useTheme,
+ Fade,
+ Grow,
} from '@mui/material';
import {
EmojiEvents,
@@ -17,9 +22,19 @@ import {
AccessTime,
Lightbulb,
Star,
+ PlayArrow,
+ Assessment,
+ Speed,
+ FireIcon,
+ LocalFireDepartment,
+ Explore,
+ Settings,
+ BookmarkBorder,
} from '@mui/icons-material';
import { useDispatch, useSelector } from 'react-redux';
+import { useNavigate } from 'react-router-dom';
import { fetchUserProgress } from '@features/progress/progressSlice';
+import { StatsCardSkeleton } from '@components/common/LoadingSkeleton';
import type { RootState, AppDispatch } from '../../store';
interface StatCardProps {
@@ -27,44 +42,214 @@ interface StatCardProps {
value: string | number;
icon: React.ReactElement;
color?: string;
+ gradient?: string;
subtitle?: string;
+ trend?: number;
+ delay?: number;
}
-const StatCard: React.FC = ({ title, value, icon, color = 'primary.main', subtitle }) => {
+/**
+ * Modern Stat Card with Glassmorphism and Animations
+ */
+const StatCard: React.FC = ({
+ title,
+ value,
+ icon,
+ color = 'primary.main',
+ gradient,
+ subtitle,
+ trend,
+ delay = 0,
+}) => {
+ const theme = useTheme();
+
return (
-
-
-
-
-
- {title}
-
-
- {value}
-
- {subtitle && (
-
- {subtitle}
+
+
+
+
+
+
+ {title}
+
+
+ {value}
- )}
+ {subtitle && (
+
+ {subtitle}
+
+ )}
+ {trend && (
+
+ 0 ? 'success.main' : 'error.main',
+ transform: trend < 0 ? 'rotate(180deg)' : 'none',
+ }}
+ />
+ 0 ? 'success.main' : 'error.main',
+ }}
+ >
+ {trend > 0 ? '+' : ''}
+ {trend}% this week
+
+
+ )}
+
+
+ {icon}
+
-
- {icon}
-
-
-
-
+
+
+
+ );
+};
+
+/**
+ * Quick Action Card Component
+ */
+interface QuickActionProps {
+ title: string;
+ description: string;
+ icon: React.ReactElement;
+ color: string;
+ onClick: () => void;
+ delay?: number;
+}
+
+const QuickActionCard: React.FC = ({
+ title,
+ description,
+ icon,
+ color,
+ onClick,
+ delay = 0,
+}) => {
+ const theme = useTheme();
+
+ return (
+
+
+
+
+ {icon}
+
+
+ {title}
+
+
+ {description}
+
+
+
+
+
+
);
};
/**
- * ProgressDashboard Component
- * Displays user progress statistics and achievements
+ * Modern ProgressDashboard Component
+ * Enhanced with glassmorphism, animations, and modern widgets
*/
export const ProgressDashboard: React.FC = () => {
const dispatch = useDispatch();
+ const navigate = useNavigate();
+ const theme = useTheme();
const { user } = useSelector((state: RootState) => state.auth);
const { stats, isLoading } = useSelector((state: RootState) => state.progress);
+ const [showWelcome, setShowWelcome] = useState(true);
useEffect(() => {
if (user?.id) {
@@ -72,8 +257,17 @@ export const ProgressDashboard: React.FC = () => {
}
}, [dispatch, user]);
- // Mock data for demonstration (stats is unknown type, so we provide defaults)
- const statsData = stats as { completedLabs?: number; totalPoints?: number; rank?: number; timeSpent?: number; hintsUsed?: number; streak?: number } | null;
+ // Mock data for demonstration
+ const statsData = stats as
+ | {
+ completedLabs?: number;
+ totalPoints?: number;
+ rank?: number;
+ timeSpent?: number;
+ hintsUsed?: number;
+ streak?: number;
+ }
+ | null;
const completedLabs = statsData?.completedLabs || 8;
const totalLabs = 25;
const totalPoints = statsData?.totalPoints || 1250;
@@ -84,26 +278,96 @@ export const ProgressDashboard: React.FC = () => {
const completionPercentage = (completedLabs / totalLabs) * 100;
const hoursSpent = Math.floor(timeSpent / 60);
+ const currentHour = new Date().getHours();
+ const greeting = currentHour < 12 ? 'Good Morning' : currentHour < 18 ? 'Good Afternoon' : 'Good Evening';
if (isLoading) {
return (
-
-
+
+
+ {[1, 2, 3, 4].map((i) => (
+
+
+
+ ))}
+
);
}
return (
- {/* Header */}
-
-
- Your Progress
-
-
- Track your learning journey and achievements
-
-
+ {/* Welcome Banner */}
+ {showWelcome && (
+
+
+
+
+
+
+ {greeting}, {user?.username || 'Hacker'}! 👋
+
+
+ Ready to level up your cybersecurity skills?
+
+
+ }
+ label={`${streak} Day Streak`}
+ sx={{
+ backgroundColor: alpha('#ffffff', 0.2),
+ color: 'white',
+ fontWeight: 700,
+ backdropFilter: 'blur(10px)',
+ }}
+ />
+ }
+ label={`Rank #${rank}`}
+ sx={{
+ backgroundColor: alpha('#ffffff', 0.2),
+ color: 'white',
+ fontWeight: 700,
+ backdropFilter: 'blur(10px)',
+ }}
+ />
+ }
+ label={`${totalPoints.toLocaleString()} Points`}
+ sx={{
+ backgroundColor: alpha('#ffffff', 0.2),
+ color: 'white',
+ fontWeight: 700,
+ backdropFilter: 'blur(10px)',
+ }}
+ />
+
+
+
+
+
+
+ )}
{/* Stats Grid */}
@@ -111,8 +375,11 @@ export const ProgressDashboard: React.FC = () => {
}
- color="#f57c00"
+ icon={}
+ color="#ffb020"
+ gradient="linear-gradient(135deg, #ffb020 0%, #ff8c00 100%)"
+ trend={12}
+ delay={0}
/>
@@ -120,190 +387,400 @@ export const ProgressDashboard: React.FC = () => {
title="Labs Completed"
value={completedLabs}
subtitle={`of ${totalLabs} total`}
- icon={}
- color="#4caf50"
+ icon={}
+ color="#00ff88"
+ gradient="linear-gradient(135deg, #00ff88 0%, #00cc6d 100%)"
+ trend={8}
+ delay={100}
/>
}
- color="#2196f3"
+ icon={}
+ color="#42a5f5"
+ gradient="linear-gradient(135deg, #42a5f5 0%, #1976d2 100%)"
+ trend={-2}
+ delay={200}
/>
}
- color="#ff9800"
+ value={`${streak}`}
+ subtitle="days in a row"
+ icon={}
+ color="#ff3864"
+ gradient="linear-gradient(135deg, #ff3864 0%, #cc2d50 100%)"
+ trend={5}
+ delay={300}
/>
+ {/* Quick Actions */}
+
+
+
+ Quick Actions
+
+
+
+ }
+ color={theme.palette.primary.main}
+ onClick={() => navigate('/labs')}
+ delay={0}
+ />
+
+
+ }
+ color="#00ff88"
+ onClick={() => navigate('/labs')}
+ delay={100}
+ />
+
+
+ }
+ color="#ffb020"
+ onClick={() => navigate('/reports')}
+ delay={200}
+ />
+
+
+ }
+ color="#9c27b0"
+ onClick={() => navigate('/settings')}
+ delay={300}
+ />
+
+
+
+
+
{/* Progress Overview */}
-
-
- Overall Progress
-
-
-
-
- Lab Completion
-
-
- {completedLabs}/{totalLabs} ({completionPercentage.toFixed(0)}%)
-
+
+
+
+ Overall Progress
+
+
+
+
+ Lab Completion
+
+
+ {completedLabs}/{totalLabs} ({completionPercentage.toFixed(0)}%)
+
+
+
-
-
-
-
-
-
-
-
- Time Spent
-
-
- {hoursSpent}h {timeSpent % 60}m
-
+
+
+
+
+
+
+
+
+ Time Spent
+
+
+ {hoursSpent}h {timeSpent % 60}m
+
+
-
-
-
-
-
-
-
- Hints Used
-
-
- {hintsUsed}
-
+
+
+
+
+
+
+
+
+ Hints Used
+
+
+ {hintsUsed}
+
+
-
-
-
-
-
-
-
- Avg Points/Lab
-
-
- {completedLabs > 0 ? Math.round(totalPoints / completedLabs) : 0}
-
+
+
+
+
+
+
+
+
+ Avg Points/Lab
+
+
+ {completedLabs > 0 ? Math.round(totalPoints / completedLabs) : 0}
+
+
-
+
-
-
+
+
- {/* Recent Activity */}
-
-
- Recent Activity
-
-
- {/* Mock recent activities */}
- {[
- { lab: 'DVWA - SQL Injection', action: 'Completed', points: 150, time: '2 hours ago' },
- { lab: 'Juice Shop - XSS Challenge', action: 'Started', points: 0, time: '1 day ago' },
- { lab: 'Metasploitable - Port Scanning', action: 'Completed', points: 200, time: '3 days ago' },
- ].map((activity, index) => (
-
+ {/* Recent Activity */}
+
+
+
-
-
- {activity.lab}
-
-
- {activity.time}
-
-
-
-
- {activity.points > 0 && (
- }
- label={`+${activity.points}`}
- size="small"
- color="warning"
- />
- )}
+
+ Recent Activity
+
+
+ {[
+ {
+ lab: 'DVWA - SQL Injection',
+ action: 'Completed',
+ points: 150,
+ time: '2 hours ago',
+ color: '#00ff88',
+ },
+ {
+ lab: 'Juice Shop - XSS Challenge',
+ action: 'Started',
+ points: 0,
+ time: '1 day ago',
+ color: '#42a5f5',
+ },
+ {
+ lab: 'Metasploitable - Port Scanning',
+ action: 'Completed',
+ points: 200,
+ time: '3 days ago',
+ color: '#00ff88',
+ },
+ ].map((activity, index) => (
+
+
+
+
+ {activity.lab}
+
+
+ {activity.time}
+
+
+
+
+ {activity.points > 0 && (
+ }
+ label={`+${activity.points}`}
+ size="small"
+ sx={{
+ bgcolor: '#ffb020',
+ color: '#000',
+ fontWeight: 700,
+ }}
+ />
+ )}
+
+
+
+ ))}
-
- ))}
-
-
+
+
+
- {/* Skills Breakdown */}
-
-
- Skills Breakdown
-
-
- {[
- { skill: 'Web Security', level: 75, color: '#2196f3' },
- { skill: 'Network Security', level: 60, color: '#4caf50' },
- { skill: 'Cryptography', level: 45, color: '#ff9800' },
- { skill: 'Exploitation', level: 80, color: '#f44336' },
- ].map((skill) => (
-
-
-
- {skill.skill}
-
- {skill.level}%
-
-
-
+ {/* Skills Breakdown */}
+
+
+
+
+ Skills Breakdown
+
+
+ {[
+ { skill: 'Web Security', level: 75, color: '#42a5f5' },
+ { skill: 'Network Security', level: 60, color: '#00ff88' },
+ { skill: 'Cryptography', level: 45, color: '#ffb020' },
+ { skill: 'Exploitation', level: 80, color: '#ff3864' },
+ ].map((skill, index) => (
+
+
+
+
+ {skill.skill}
+
+
+ {skill.level}%
+
+
+
+
+
+ ))}
-
- ))}
+
+
-
+
);
};
diff --git a/frontend/src/pages/NotFoundPage.tsx b/frontend/src/pages/NotFoundPage.tsx
index 9360f48..7ab67b8 100644
--- a/frontend/src/pages/NotFoundPage.tsx
+++ b/frontend/src/pages/NotFoundPage.tsx
@@ -1,14 +1,287 @@
-import { Typography, Container } from '@mui/material';
+import React from 'react';
+import { Box, Typography, Button, Container, useTheme, alpha } from '@mui/material';
+import { useNavigate } from 'react-router-dom';
+import HomeIcon from '@mui/icons-material/Home';
+import SearchIcon from '@mui/icons-material/Search';
+import ArrowBackIcon from '@mui/icons-material/ArrowBack';
+import SecurityIcon from '@mui/icons-material/Security';
+
+/**
+ * Modern 404 Not Found Page
+ * Features: Cybersecurity-themed, animated, professional design
+ */
+const NotFoundPage: React.FC = () => {
+ const navigate = useNavigate();
+ const theme = useTheme();
-export default function NotFoundPage(): JSX.Element {
return (
-
-
- NotFoundPage
-
-
- This page is under construction. Feature coming soon!
-
-
+
+
+
+ {/* Animated 404 */}
+
+
+ 404
+
+
+ {/* Lock Icon Overlay */}
+
+
+
+ {/* Error Message */}
+
+ Access Denied
+
+
+
+ The page you're looking for has been classified or doesn't exist in our database.
+ Our security systems have logged this attempt.
+
+
+ {/* Terminal-style code block */}
+
+
+ {`$ security-scan --status 404
+>> ERROR: Resource not found
+>> Possible causes:
+ - Incorrect URL path
+ - Resource moved or deleted
+ - Access permissions required
+>> Recommendation: Return to dashboard`}
+
+
+
+ {/* Action Buttons */}
+
+ }
+ onClick={() => navigate('/dashboard')}
+ sx={{
+ px: 4,
+ py: 1.5,
+ fontSize: '1rem',
+ fontWeight: 600,
+ background: `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.dark} 100%)`,
+ boxShadow: `0 4px 20px ${alpha(theme.palette.primary.main, 0.4)}`,
+ '&:hover': {
+ background: `linear-gradient(135deg, ${theme.palette.primary.dark} 0%, ${theme.palette.primary.main} 100%)`,
+ boxShadow: `0 6px 30px ${alpha(theme.palette.primary.main, 0.5)}`,
+ transform: 'translateY(-2px)',
+ },
+ transition: 'all 0.3s ease',
+ }}
+ >
+ Go to Dashboard
+
+
+ }
+ onClick={() => navigate(-1)}
+ sx={{
+ px: 4,
+ py: 1.5,
+ fontSize: '1rem',
+ fontWeight: 600,
+ borderWidth: 2,
+ '&:hover': {
+ borderWidth: 2,
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 20px ${alpha(theme.palette.primary.main, 0.2)}`,
+ },
+ transition: 'all 0.3s ease',
+ }}
+ >
+ Go Back
+
+
+ }
+ onClick={() => navigate('/labs')}
+ sx={{
+ px: 4,
+ py: 1.5,
+ fontSize: '1rem',
+ fontWeight: 600,
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ background: alpha(theme.palette.primary.main, 0.05),
+ },
+ transition: 'all 0.3s ease',
+ }}
+ >
+ Browse Labs
+
+
+
+ {/* Additional Help Text */}
+
+ Need help? Check our{' '}
+ navigate('/help')}
+ >
+ documentation
+
+ {' '}or contact support.
+
+
+
+
);
-}
+};
+
+export default NotFoundPage;
diff --git a/frontend/src/pages/auth/LoginPage.tsx b/frontend/src/pages/auth/LoginPage.tsx
index 841c873..26bc7fc 100644
--- a/frontend/src/pages/auth/LoginPage.tsx
+++ b/frontend/src/pages/auth/LoginPage.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -12,7 +12,22 @@ import {
Typography,
Link,
Alert,
+ alpha,
+ useTheme,
+ Fade,
+ Zoom,
+ InputAdornment,
+ IconButton,
+ CircularProgress,
} from '@mui/material';
+import {
+ Email,
+ Lock,
+ Visibility,
+ VisibilityOff,
+ Security,
+ ArrowForward,
+} from '@mui/icons-material';
import { useAppDispatch, useAppSelector } from '@hooks/redux';
import { login } from '@features/auth/authSlice';
import type { LoginCredentials } from '../../types';
@@ -24,10 +39,16 @@ const loginSchema = z.object({
type LoginFormData = z.infer;
+/**
+ * Modern Login Page
+ * Features: Glassmorphism, animated background, smooth transitions
+ */
export default function LoginPage(): JSX.Element {
const navigate = useNavigate();
const dispatch = useAppDispatch();
+ const theme = useTheme();
const { isAuthenticated, isLoading, error } = useAppSelector((state) => state.auth);
+ const [showPassword, setShowPassword] = useState(false);
const {
register,
@@ -48,64 +69,306 @@ export default function LoginPage(): JSX.Element {
};
return (
-
-
-
-
- Sign in to Auron
-
- {error && (
-
- {error}
-
- )}
-
-
-
-
-
-
- {"Don't have an account? Sign Up"}
-
-
+
+
+
+
+ {/* Logo and Branding */}
+
+
+
+
+
+
+ Auron Security
+
+
+ Cybersecurity Training Platform
+
+
+
+
+ {/* Login Form Card */}
+
+
+
+ Welcome Back
+
+
+ Sign in to continue your security training
+
+
+ {error && (
+
+
+ {error}
+
+
+ )}
+
+
+
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.primary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.primary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+
+
+
+ ),
+ endAdornment: (
+
+ setShowPassword(!showPassword)}
+ edge="end"
+ sx={{
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'scale(1.1)',
+ },
+ }}
+ >
+ {showPassword ? : }
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.primary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.primary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+ : }
+ sx={{
+ mt: 4,
+ mb: 2,
+ py: 1.5,
+ borderRadius: 2,
+ fontSize: '1rem',
+ fontWeight: 700,
+ background: `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.dark} 100%)`,
+ boxShadow: `0 4px 16px ${alpha(theme.palette.primary.main, 0.4)}`,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ background: `linear-gradient(135deg, ${theme.palette.primary.dark} 0%, ${theme.palette.primary.main} 100%)`,
+ transform: 'translateY(-2px)',
+ boxShadow: `0 8px 24px ${alpha(theme.palette.primary.main, 0.5)}`,
+ },
+ '&:active': {
+ transform: 'translateY(0)',
+ },
+ }}
+ >
+ {isLoading ? 'Signing in...' : 'Sign In'}
+
+
+
+
+ Don't have an account?{' '}
+
+
+ Sign Up
+
+
+
+
+
+
+ {/* Footer */}
+
+
+
+ © 2025 Auron Security Platform. All rights reserved.
+
+
+
-
-
-
+
+
+
);
}
diff --git a/frontend/src/pages/auth/RegisterPage.tsx b/frontend/src/pages/auth/RegisterPage.tsx
index 1025520..c7773e1 100644
--- a/frontend/src/pages/auth/RegisterPage.tsx
+++ b/frontend/src/pages/auth/RegisterPage.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import { useNavigate, Link as RouterLink } from 'react-router-dom';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
@@ -12,42 +12,84 @@ import {
Typography,
Link,
Alert,
+ alpha,
+ useTheme,
+ Fade,
+ Zoom,
+ InputAdornment,
+ IconButton,
+ CircularProgress,
+ LinearProgress,
} from '@mui/material';
+import {
+ Email,
+ Lock,
+ Visibility,
+ VisibilityOff,
+ Security,
+ Person,
+ ArrowForward,
+ CheckCircle,
+} from '@mui/icons-material';
import { useAppDispatch, useAppSelector } from '@hooks/redux';
import { register as registerUser } from '@features/auth/authSlice';
import { VALIDATION } from '@config/constants';
-const registerSchema = z.object({
- email: z.string().email('Invalid email address'),
- username: z
- .string()
- .min(VALIDATION.USERNAME_MIN_LENGTH, `Username must be at least ${VALIDATION.USERNAME_MIN_LENGTH} characters`)
- .max(VALIDATION.USERNAME_MAX_LENGTH, `Username must be at most ${VALIDATION.USERNAME_MAX_LENGTH} characters`)
- .regex(VALIDATION.USERNAME_REGEX, 'Username can only contain letters, numbers, _ and -'),
- password: z
- .string()
- .min(VALIDATION.PASSWORD_MIN_LENGTH, `Password must be at least ${VALIDATION.PASSWORD_MIN_LENGTH} characters`),
- confirmPassword: z.string(),
-}).refine((data) => data.password === data.confirmPassword, {
- message: "Passwords don't match",
- path: ['confirmPassword'],
-});
+const registerSchema = z
+ .object({
+ email: z.string().email('Invalid email address'),
+ username: z
+ .string()
+ .min(VALIDATION.USERNAME_MIN_LENGTH, `Username must be at least ${VALIDATION.USERNAME_MIN_LENGTH} characters`)
+ .max(VALIDATION.USERNAME_MAX_LENGTH, `Username must be at most ${VALIDATION.USERNAME_MAX_LENGTH} characters`)
+ .regex(VALIDATION.USERNAME_REGEX, 'Username can only contain letters, numbers, _ and -'),
+ password: z
+ .string()
+ .min(VALIDATION.PASSWORD_MIN_LENGTH, `Password must be at least ${VALIDATION.PASSWORD_MIN_LENGTH} characters`),
+ confirmPassword: z.string(),
+ })
+ .refine((data) => data.password === data.confirmPassword, {
+ message: "Passwords don't match",
+ path: ['confirmPassword'],
+ });
type RegisterFormData = z.infer;
+/**
+ * Modern Register Page
+ * Features: Glassmorphism, animated background, smooth transitions, password strength indicator
+ */
export default function RegisterPage(): JSX.Element {
const navigate = useNavigate();
const dispatch = useAppDispatch();
+ const theme = useTheme();
const { isAuthenticated, isLoading, error } = useAppSelector((state) => state.auth);
+ const [showPassword, setShowPassword] = useState(false);
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
+ const [passwordStrength, setPasswordStrength] = useState(0);
const {
register,
handleSubmit,
+ watch,
formState: { errors },
} = useForm({
resolver: zodResolver(registerSchema),
});
+ const password = watch('password', '');
+
+ // Calculate password strength
+ useEffect(() => {
+ let strength = 0;
+ if (password.length >= 8) strength += 25;
+ if (password.length >= 12) strength += 25;
+ if (/[a-z]/.test(password) && /[A-Z]/.test(password)) strength += 25;
+ if (/[0-9]/.test(password)) strength += 12.5;
+ if (/[^a-zA-Z0-9]/.test(password)) strength += 12.5;
+ setPasswordStrength(Math.min(strength, 100));
+ }, [password]);
+
useEffect(() => {
if (isAuthenticated) {
navigate('/dashboard');
@@ -59,70 +101,425 @@ export default function RegisterPage(): JSX.Element {
await dispatch(registerUser(registerData));
};
+ const getPasswordStrengthColor = () => {
+ if (passwordStrength < 40) return theme.palette.error.main;
+ if (passwordStrength < 70) return theme.palette.warning.main;
+ return theme.palette.success.main;
+ };
+
+ const getPasswordStrengthLabel = () => {
+ if (passwordStrength < 40) return 'Weak';
+ if (passwordStrength < 70) return 'Medium';
+ return 'Strong';
+ };
+
return (
-
-
-
-
- Create Account
-
- {error && {error}}
-
-
-
-
-
-
-
-
- Already have an account? Sign In
-
-
+
+
+
+
+ {/* Logo and Branding */}
+
+
+
+
+
+
+ Auron Security
+
+
+ Join Our Cybersecurity Community
+
+
+
+
+ {/* Register Form Card */}
+
+
+
+ Create Account
+
+
+ Start your journey to becoming a security expert
+
+
+ {error && (
+
+
+ {error}
+
+
+ )}
+
+
+
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.secondary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.secondary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.secondary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.secondary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+
+
+
+ ),
+ endAdornment: (
+
+ setShowPassword(!showPassword)}
+ edge="end"
+ sx={{
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'scale(1.1)',
+ },
+ }}
+ >
+ {showPassword ? : }
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.secondary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.secondary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+ {/* Password Strength Indicator */}
+ {password && (
+
+
+
+
+ Password Strength
+
+
+ {getPasswordStrengthLabel()}
+
+
+
+
+
+ )}
+
+
+
+
+ ),
+ endAdornment: (
+
+ setShowConfirmPassword(!showConfirmPassword)}
+ edge="end"
+ sx={{
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'scale(1.1)',
+ },
+ }}
+ >
+ {showConfirmPassword ? : }
+
+
+ ),
+ }}
+ sx={{
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 2,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 12px ${alpha(theme.palette.secondary.main, 0.1)}`,
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-2px)',
+ boxShadow: `0 4px 16px ${alpha(theme.palette.secondary.main, 0.2)}`,
+ },
+ },
+ }}
+ />
+
+ : }
+ sx={{
+ mt: 4,
+ mb: 2,
+ py: 1.5,
+ borderRadius: 2,
+ fontSize: '1rem',
+ fontWeight: 700,
+ background: `linear-gradient(135deg, ${theme.palette.secondary.main} 0%, ${theme.palette.secondary.dark} 100%)`,
+ boxShadow: `0 4px 16px ${alpha(theme.palette.secondary.main, 0.4)}`,
+ transition: 'all 0.3s ease',
+ '&:hover': {
+ background: `linear-gradient(135deg, ${theme.palette.secondary.dark} 0%, ${theme.palette.secondary.main} 100%)`,
+ transform: 'translateY(-2px)',
+ boxShadow: `0 8px 24px ${alpha(theme.palette.secondary.main, 0.5)}`,
+ },
+ '&:active': {
+ transform: 'translateY(0)',
+ },
+ }}
+ >
+ {isLoading ? 'Creating Account...' : 'Sign Up'}
+
+
+
+
+ Already have an account?{' '}
+
+
+ Sign In
+
+
+
+
+
+
+ {/* Footer */}
+
+
+
+ © 2025 Auron Security Platform. All rights reserved.
+
+
+
-
-
-
+
+
+
);
}
diff --git a/frontend/src/styles/modernTheme.ts b/frontend/src/styles/modernTheme.ts
new file mode 100644
index 0000000..2d1ef54
--- /dev/null
+++ b/frontend/src/styles/modernTheme.ts
@@ -0,0 +1,457 @@
+import { createTheme, ThemeOptions } from '@mui/material/styles';
+
+/**
+ * Modern Cybersecurity-Themed Design System for Auron
+ * Features: Terminal aesthetics, neon accents, glassmorphism, professional polish
+ */
+
+// Custom color palette - Cybersecurity themed
+const colors = {
+ // Primary - Electric Blue (cybersecurity brand color)
+ electric: {
+ 50: '#e3f2fd',
+ 100: '#bbdefb',
+ 200: '#90caf9',
+ 300: '#64b5f6',
+ 400: '#42a5f5',
+ 500: '#2196f3', // Main
+ 600: '#1e88e5',
+ 700: '#1976d2',
+ 800: '#1565c0',
+ 900: '#0d47a1',
+ },
+
+ // Terminal Green (hacker aesthetic)
+ terminal: {
+ 50: '#e8f5e9',
+ 100: '#c8e6c9',
+ 200: '#a5d6a7',
+ 300: '#81c784',
+ 400: '#66bb6a',
+ 500: '#00ff41', // Bright terminal green
+ 600: '#00e676',
+ 700: '#00c853',
+ 800: '#00b248',
+ 900: '#00962d',
+ },
+
+ // Neon Purple (accent)
+ neon: {
+ 50: '#f3e5f5',
+ 100: '#e1bee7',
+ 200: '#ce93d8',
+ 300: '#ba68c8',
+ 400: '#ab47bc',
+ 500: '#9c27b0',
+ 600: '#8e24aa',
+ 700: '#7b1fa2',
+ 800: '#6a1b9a',
+ 900: '#4a148c',
+ },
+
+ // Cyber Dark (backgrounds)
+ cyber: {
+ 900: '#0a0e27', // Darkest
+ 800: '#0f172a',
+ 700: '#1e293b',
+ 600: '#334155',
+ 500: '#475569',
+ 400: '#64748b',
+ 300: '#94a3b8',
+ 200: '#cbd5e1',
+ 100: '#e2e8f0',
+ 50: '#f8fafc',
+ },
+
+ // Status colors
+ danger: '#ff3864',
+ warning: '#ffb020',
+ success: '#00ff88',
+ info: '#00d4ff',
+};
+
+// Light Theme Options
+const lightThemeOptions: ThemeOptions = {
+ palette: {
+ mode: 'light',
+ primary: {
+ main: colors.electric[600],
+ light: colors.electric[400],
+ dark: colors.electric[800],
+ contrastText: '#ffffff',
+ },
+ secondary: {
+ main: colors.terminal[500],
+ light: colors.terminal[400],
+ dark: colors.terminal[700],
+ contrastText: '#000000',
+ },
+ error: {
+ main: colors.danger,
+ light: '#ff6b8a',
+ dark: '#cc2d50',
+ },
+ warning: {
+ main: colors.warning,
+ light: '#ffc14d',
+ dark: '#cc8d1a',
+ },
+ info: {
+ main: colors.info,
+ light: '#33ddff',
+ dark: '#00aacc',
+ },
+ success: {
+ main: colors.success,
+ light: '#33ffa0',
+ dark: '#00cc6d',
+ },
+ background: {
+ default: '#f8fafc',
+ paper: '#ffffff',
+ },
+ text: {
+ primary: colors.cyber[900],
+ secondary: colors.cyber[600],
+ disabled: colors.cyber[400],
+ },
+ },
+ typography: {
+ fontFamily: [
+ 'Inter',
+ '-apple-system',
+ 'BlinkMacSystemFont',
+ '"Segoe UI"',
+ 'Roboto',
+ 'Arial',
+ 'sans-serif',
+ ].join(','),
+ fontFamilyMonospace: [
+ '"Fira Code"',
+ '"JetBrains Mono"',
+ 'Monaco',
+ 'Consolas',
+ '"Courier New"',
+ 'monospace',
+ ].join(','),
+ h1: {
+ fontSize: '3rem',
+ fontWeight: 800,
+ lineHeight: 1.1,
+ letterSpacing: '-0.02em',
+ },
+ h2: {
+ fontSize: '2.25rem',
+ fontWeight: 700,
+ lineHeight: 1.2,
+ letterSpacing: '-0.01em',
+ },
+ h3: {
+ fontSize: '1.875rem',
+ fontWeight: 600,
+ lineHeight: 1.3,
+ },
+ h4: {
+ fontSize: '1.5rem',
+ fontWeight: 600,
+ lineHeight: 1.4,
+ },
+ h5: {
+ fontSize: '1.25rem',
+ fontWeight: 600,
+ lineHeight: 1.5,
+ },
+ h6: {
+ fontSize: '1.125rem',
+ fontWeight: 600,
+ lineHeight: 1.5,
+ },
+ subtitle1: {
+ fontSize: '1.125rem',
+ fontWeight: 500,
+ lineHeight: 1.75,
+ },
+ subtitle2: {
+ fontSize: '1rem',
+ fontWeight: 500,
+ lineHeight: 1.75,
+ },
+ body1: {
+ fontSize: '1rem',
+ lineHeight: 1.75,
+ },
+ body2: {
+ fontSize: '0.875rem',
+ lineHeight: 1.6,
+ },
+ button: {
+ textTransform: 'none',
+ fontWeight: 600,
+ letterSpacing: '0.02em',
+ },
+ caption: {
+ fontSize: '0.75rem',
+ lineHeight: 1.5,
+ letterSpacing: '0.01em',
+ },
+ overline: {
+ fontSize: '0.75rem',
+ fontWeight: 700,
+ lineHeight: 2,
+ letterSpacing: '0.1em',
+ textTransform: 'uppercase',
+ },
+ },
+ shape: {
+ borderRadius: 12,
+ },
+ shadows: [
+ 'none',
+ '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
+ '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
+ '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
+ '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
+ '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
+ ],
+ components: {
+ MuiButton: {
+ styleOverrides: {
+ root: {
+ borderRadius: 10,
+ padding: '10px 24px',
+ fontWeight: 600,
+ fontSize: '0.95rem',
+ transition: 'all 0.2s ease-in-out',
+ '&:hover': {
+ transform: 'translateY(-2px)',
+ },
+ },
+ contained: {
+ boxShadow: '0 4px 12px rgba(33, 150, 243, 0.25)',
+ '&:hover': {
+ boxShadow: '0 8px 24px rgba(33, 150, 243, 0.35)',
+ },
+ },
+ containedPrimary: {
+ background: `linear-gradient(135deg, ${colors.electric[600]} 0%, ${colors.electric[700]} 100%)`,
+ '&:hover': {
+ background: `linear-gradient(135deg, ${colors.electric[700]} 0%, ${colors.electric[800]} 100%)`,
+ },
+ },
+ outlined: {
+ borderWidth: 2,
+ '&:hover': {
+ borderWidth: 2,
+ },
+ },
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: {
+ borderRadius: 16,
+ boxShadow: '0 4px 20px rgba(0, 0, 0, 0.08)',
+ transition: 'all 0.3s ease',
+ overflow: 'hidden',
+ '&:hover': {
+ boxShadow: '0 8px 30px rgba(0, 0, 0, 0.12)',
+ transform: 'translateY(-4px)',
+ },
+ },
+ },
+ },
+ MuiPaper: {
+ styleOverrides: {
+ root: {
+ borderRadius: 12,
+ },
+ elevation1: {
+ boxShadow: '0 2px 8px rgba(0, 0, 0, 0.08)',
+ },
+ elevation2: {
+ boxShadow: '0 4px 16px rgba(0, 0, 0, 0.1)',
+ },
+ elevation3: {
+ boxShadow: '0 8px 24px rgba(0, 0, 0, 0.12)',
+ },
+ },
+ },
+ MuiAppBar: {
+ styleOverrides: {
+ root: {
+ boxShadow: '0 1px 3px rgba(0, 0, 0, 0.08)',
+ backdropFilter: 'blur(10px)',
+ backgroundColor: 'rgba(255, 255, 255, 0.8)',
+ },
+ },
+ },
+ MuiChip: {
+ styleOverrides: {
+ root: {
+ borderRadius: 8,
+ fontWeight: 500,
+ },
+ },
+ },
+ MuiTextField: {
+ styleOverrides: {
+ root: {
+ '& .MuiOutlinedInput-root': {
+ borderRadius: 10,
+ transition: 'all 0.2s ease',
+ '&:hover': {
+ transform: 'translateY(-1px)',
+ },
+ '&.Mui-focused': {
+ transform: 'translateY(-1px)',
+ boxShadow: '0 4px 12px rgba(33, 150, 243, 0.15)',
+ },
+ },
+ },
+ },
+ },
+ MuiLinearProgress: {
+ styleOverrides: {
+ root: {
+ borderRadius: 4,
+ height: 8,
+ },
+ bar: {
+ borderRadius: 4,
+ },
+ },
+ },
+ },
+};
+
+// Dark Theme Options
+const darkThemeOptions: ThemeOptions = {
+ ...lightThemeOptions,
+ palette: {
+ mode: 'dark',
+ primary: {
+ main: colors.electric[400],
+ light: colors.electric[300],
+ dark: colors.electric[600],
+ contrastText: '#ffffff',
+ },
+ secondary: {
+ main: colors.terminal[500],
+ light: colors.terminal[400],
+ dark: colors.terminal[600],
+ contrastText: '#000000',
+ },
+ error: {
+ main: colors.danger,
+ light: '#ff6b8a',
+ dark: '#cc2d50',
+ },
+ warning: {
+ main: colors.warning,
+ light: '#ffc14d',
+ dark: '#cc8d1a',
+ },
+ info: {
+ main: colors.info,
+ light: '#33ddff',
+ dark: '#00aacc',
+ },
+ success: {
+ main: colors.success,
+ light: '#33ffa0',
+ dark: '#00cc6d',
+ },
+ background: {
+ default: colors.cyber[900],
+ paper: colors.cyber[800],
+ },
+ text: {
+ primary: '#ffffff',
+ secondary: colors.cyber[300],
+ disabled: colors.cyber[500],
+ },
+ },
+ components: {
+ ...lightThemeOptions.components,
+ MuiAppBar: {
+ styleOverrides: {
+ root: {
+ boxShadow: '0 1px 3px rgba(0, 0, 0, 0.3)',
+ backdropFilter: 'blur(10px)',
+ backgroundColor: 'rgba(10, 14, 39, 0.8)',
+ },
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: {
+ borderRadius: 16,
+ boxShadow: '0 4px 20px rgba(0, 0, 0, 0.3)',
+ transition: 'all 0.3s ease',
+ background: `linear-gradient(135deg, ${colors.cyber[800]} 0%, ${colors.cyber[700]} 100%)`,
+ border: `1px solid ${colors.cyber[600]}`,
+ '&:hover': {
+ boxShadow: '0 8px 30px rgba(0, 0, 0, 0.4)',
+ transform: 'translateY(-4px)',
+ border: `1px solid ${colors.electric[700]}`,
+ },
+ },
+ },
+ },
+ },
+};
+
+// Export themes
+export const lightTheme = createTheme(lightThemeOptions);
+export const darkTheme = createTheme(darkThemeOptions);
+
+// Export color palette for direct use
+export { colors };
+
+// Utility: Glassmorphism effect
+export const glassmorphism = (opacity: number = 0.8) => ({
+ background: `rgba(255, 255, 255, ${opacity})`,
+ backdropFilter: 'blur(10px)',
+ WebkitBackdropFilter: 'blur(10px)',
+ border: '1px solid rgba(255, 255, 255, 0.18)',
+});
+
+// Utility: Glassmorphism dark
+export const glassmorphismDark = (opacity: number = 0.8) => ({
+ background: `rgba(10, 14, 39, ${opacity})`,
+ backdropFilter: 'blur(10px)',
+ WebkitBackdropFilter: 'blur(10px)',
+ border: '1px solid rgba(255, 255, 255, 0.1)',
+});
+
+// Utility: Gradient text
+export const gradientText = (color1: string = colors.electric[400], color2: string = colors.terminal[500]) => ({
+ background: `linear-gradient(135deg, ${color1}, ${color2})`,
+ WebkitBackgroundClip: 'text',
+ WebkitTextFillColor: 'transparent',
+ backgroundClip: 'text',
+});
+
+// Utility: Neon glow
+export const neonGlow = (color: string = colors.terminal[500]) => ({
+ boxShadow: `0 0 10px ${color}, 0 0 20px ${color}, 0 0 30px ${color}`,
+});