Skip to content

Commit 6cae5ec

Browse files
committed
feat: add attack simulation and fix mobile menu positioning
1 parent 98d5118 commit 6cae5ec

1 file changed

Lines changed: 23 additions & 6 deletions

File tree

frontend/components/ui/AttackSimulation.tsx

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState } from "react";
1+
import { useState, useRef, useEffect } from "react";
22
import { motion, AnimatePresence } from "framer-motion";
33
import { Zap, ShieldAlert, ChevronUp, Terminal, Skull, Lock, Eye } from "lucide-react";
44

@@ -52,15 +52,32 @@ const ATTACK_SCENARIOS = [
5252

5353
export default function AttackSimulation({ onSelect, disabled }: AttackSimulationProps) {
5454
const [isOpen, setIsOpen] = useState(false);
55+
const containerRef = useRef<HTMLDivElement>(null);
56+
57+
useEffect(() => {
58+
const handleClickOutside = (event: MouseEvent) => {
59+
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
60+
setIsOpen(false);
61+
}
62+
};
63+
64+
if (isOpen) {
65+
document.addEventListener("mousedown", handleClickOutside);
66+
}
67+
68+
return () => {
69+
document.removeEventListener("mousedown", handleClickOutside);
70+
};
71+
}, [isOpen]);
5572

5673
return (
57-
<div className="relative">
74+
<div ref={containerRef} className="relative">
5875
<button
5976
onClick={() => setIsOpen(!isOpen)}
6077
disabled={disabled}
6178
className={`flex items-center gap-2 px-3 py-1.5 rounded-lg border transition-all text-xs font-mono tracking-wide ${isOpen
62-
? "bg-red-500/20 border-red-500/50 text-red-200"
63-
: "bg-zinc-900/50 border-white/10 text-zinc-400 hover:text-white hover:border-white/30"
79+
? "bg-red-500/20 border-red-500/50 text-red-200"
80+
: "bg-zinc-900/50 border-white/10 text-zinc-400 hover:text-white hover:border-white/30"
6481
} ${disabled ? "opacity-50 cursor-not-allowed" : ""}`}
6582
>
6683
<Zap className={`w-3 h-3 ${isOpen ? "text-red-400" : "text-zinc-500"}`} />
@@ -74,14 +91,14 @@ export default function AttackSimulation({ onSelect, disabled }: AttackSimulatio
7491
initial={{ opacity: 0, y: 10, scale: 0.95 }}
7592
animate={{ opacity: 1, y: 0, scale: 1 }}
7693
exit={{ opacity: 0, y: 10, scale: 0.95 }}
77-
className="absolute bottom-full left-0 mb-2 w-72 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50"
94+
className="absolute bottom-full right-0 mb-2 w-72 bg-zinc-900/95 backdrop-blur-xl border border-white/10 rounded-xl shadow-2xl overflow-hidden z-50"
7895
>
7996
<div className="p-3 border-b border-white/10 bg-white/5">
8097
<h3 className="text-xs font-bold text-white uppercase tracking-wider">Select Attack Vector</h3>
8198
<p className="text-[10px] text-zinc-500 mt-0.5">Pre-configured prompts to test Cerberus</p>
8299
</div>
83100

84-
<div className="max-h-64 overflow-y-auto custom-scrollbar p-1">
101+
<div className="p-1">
85102
{ATTACK_SCENARIOS.map((scenario) => (
86103
<button
87104
key={scenario.id}

0 commit comments

Comments
 (0)