DN-Spamdex-UI-v1 / index.html
DarkNeuron-AI's picture
Upload 7 files
957250d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SpamDex - AI Spam Detection</title>
<!-- React & Tailwind Setup -->
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<!-- Google Fonts -->
<style>
@import url('https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;700&display=swap');
body { font-family: 'Outfit', sans-serif; }
/* Animations */
@keyframes float {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
25% { transform: translate(10px, -20px) rotate(5deg); }
50% { transform: translate(-5px, -30px) rotate(-5deg); }
75% { transform: translate(8px, -15px) rotate(3deg); }
}
@keyframes glow {
0%, 100% { opacity: 0.3; transform: scale(1); }
50% { opacity: 0.6; transform: scale(1.1); }
}
@keyframes slide-up {
from { transform: translateY(30px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes pulse-ring {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 82, 82, 0.7); }
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(255, 82, 82, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(255, 82, 82, 0); }
}
@keyframes pulse-ring-green {
0% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7); }
70% { transform: scale(1); box-shadow: 0 0 0 10px rgba(76, 175, 80, 0); }
100% { transform: scale(0.95); box-shadow: 0 0 0 0 rgba(76, 175, 80, 0); }
}
/* Glassmorphism Classes */
.glass {
backdrop-filter: blur(16px) saturate(180%);
-webkit-backdrop-filter: blur(16px) saturate(180%);
}
.glass-dark {
background: rgba(17, 25, 40, 0.6);
border: 1px solid rgba(255, 255, 255, 0.125);
}
.glass-light {
background: rgba(255, 255, 255, 0.7);
border: 1px solid rgba(209, 213, 219, 0.3);
}
/* Text Effects */
.glow-text-dark { text-shadow: 0 0 20px rgba(168, 85, 247, 0.5); }
.glow-text-light { text-shadow: 0 0 15px rgba(236, 72, 153, 0.3); }
.gradient-text {
background: linear-gradient(135deg, #6366f1 0%, #a855f7 50%, #ec4899 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Utilities */
.animate-slide-up { animation: slide-up 0.8s cubic-bezier(0.2, 0.8, 0.2, 1) forwards; }
.shimmer {
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.1), transparent);
background-size: 1000px 100%;
animation: shimmer 2s infinite linear;
}
@keyframes shimmer { 0% { background-position: -1000px 0; } 100% { background-position: 1000px 0; } }
.cursive { font-family: 'Brush Script MT', cursive; }
/* Smooth Scrollbar */
textarea::-webkit-scrollbar { width: 8px; }
textarea::-webkit-scrollbar-track { background: transparent; }
textarea::-webkit-scrollbar-thumb { background: rgba(156, 163, 175, 0.5); border-radius: 4px; }
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const { useState, useEffect } = React;
// --- Icons (SVG Components for Browser Compatibility) ---
const Icon = ({ path, className }) => (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className={className}>
{path}
</svg>
);
const Icons = {
Shield: (p) => <Icon {...p} path={<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>} />,
Sun: (p) => <Icon {...p} path={<><circle cx="12" cy="12" r="4"/><path d="M12 2v2"/><path d="M12 20v2"/><path d="m4.93 4.93 1.41 1.41"/><path d="m17.66 17.66 1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="m6.34 17.66-1.41 1.41"/><path d="m19.07 4.93-1.41 1.41"/></>} />,
Moon: (p) => <Icon {...p} path={<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"/>} />,
Zap: (p) => <Icon {...p} path={<polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/>} />,
Copy: (p) => <Icon {...p} path={<><rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></>} />,
Check: (p) => <Icon {...p} path={<polyline points="20 6 9 17 4 12"/>} />,
Sparkles: (p) => <Icon {...p} path={<><path d="m12 3-1.912 5.813a2 2 0 0 1-1.275 1.275L3 12l5.813 1.912a2 2 0 0 1 1.275 1.275L12 21l1.912-5.813a2 2 0 0 1 1.275-1.275L12 3Z"/><path d="M5 3v4"/><path d="M19 17v4"/><path d="M3 5h4"/><path d="M17 19h4"/></>} />,
Brain: (p) => <Icon {...p} path={<><path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2Z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2Z"/></>} />,
Lock: (p) => <Icon {...p} path={<><rect width="18" height="11" x="3" y="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></>} />,
Globe: (p) => <Icon {...p} path={<><circle cx="12" cy="12" r="10"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/><path d="M2 12h20"/></>} />,
Code: (p) => <Icon {...p} path={<><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></>} />,
AlertCircle: (p) => <Icon {...p} path={<><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="12"/><line x1="12" x2="12.01" y1="16" y2="16"/></>} />,
CheckCircle: (p) => <Icon {...p} path={<><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></>} />,
Mail: (p) => <Icon {...p} path={<><rect width="20" height="16" x="2" y="4" rx="2"/><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"/></>} />,
Send: (p) => <Icon {...p} path={<><line x1="22" x2="11" y1="2" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/></>} />,
Award: (p) => <Icon {...p} path={<><circle cx="12" cy="8" r="7"/><polyline points="8.21 13.89 7 23 12 20 17 23 15.79 13.88"/></>} />,
TrendingUp: (p) => <Icon {...p} path={<polyline points="23 6 13.5 15.5 8.5 10.5 1 18"/>} />
};
// --- Main Application ---
const SpamDexUI = () => {
const [darkMode, setDarkMode] = useState(true);
const [inputText, setInputText] = useState('');
const [result, setResult] = useState(null);
const [loading, setLoading] = useState(false);
const [copied, setCopied] = useState(false);
const [particles, setParticles] = useState([]);
const [currentUrl, setCurrentUrl] = useState('');
useEffect(() => {
// Initialize particles
const newParticles = [...Array(25)].map((_, i) => ({
id: i,
size: Math.random() * 4 + 2,
x: Math.random() * 100,
y: Math.random() * 100,
duration: Math.random() * 20 + 10,
delay: Math.random() * 5
}));
setParticles(newParticles);
// Set current URL for API display
setCurrentUrl(window.location.origin);
}, []);
const analyzeText = async () => {
if (!inputText.trim()) return;
setLoading(true);
setResult(null);
try {
// Call the Python FastAPI Backend
const response = await fetch('/api/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ text: inputText })
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.detail || 'Prediction failed');
}
const data = await response.json();
setResult({
type: data.prediction, // 'spam' or 'safe'
confidence: data.confidence,
label: data.label
});
} catch (err) {
console.error("Error:", err);
alert("Error connecting to server. Is the model loaded?");
} finally {
setLoading(false);
}
};
const copyApiEndpoint = () => {
navigator.clipboard.writeText(currentUrl + '/api/predict');
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
const examples = [
{ text: "Congratulations! You won $1000! Click here now!", icon: Icons.AlertCircle, type: "spam" },
{ text: "Hi, can we schedule a meeting tomorrow at 3 PM?", icon: Icons.CheckCircle, type: "safe" },
{ text: "FREE FREE FREE!!! Win iPhone now!!!", icon: Icons.AlertCircle, type: "spam" },
{ text: "Your package has been delivered successfully.", icon: Icons.CheckCircle, type: "safe" }
];
const features = [
{ icon: Icons.Zap, title: "Lightning Fast", desc: "Sub-second spam detection", color: "from-yellow-400 to-orange-500" },
{ icon: Icons.Brain, title: "AI Powered", desc: "Naive Bayes + TF-IDF", color: "from-purple-400 to-pink-500" },
{ icon: Icons.Lock, title: "High Accuracy", desc: "98%+ precision rate", color: "from-green-400 to-emerald-500" },
{ icon: Icons.Globe, title: "API Ready", desc: "Easy integration", color: "from-blue-400 to-cyan-500" }
];
const stats = [
{ label: "Accuracy", value: "98.5%", icon: Icons.TrendingUp },
{ label: "Models Trained", value: "10K+", icon: Icons.Brain },
{ label: "API Calls", value: "1M+", icon: Icons.Zap },
{ label: "Users", value: "5K+", icon: Icons.Award }
];
// Dynamic Classes based on Theme
const glassClass = darkMode ? 'glass-dark glass' : 'glass-light glass';
const textClass = darkMode ? 'text-white' : 'text-gray-900';
const subTextClass = darkMode ? 'text-gray-400' : 'text-gray-600';
return (
<div className={`min-h-screen w-full transition-colors duration-700 overflow-x-hidden ${
darkMode
? 'bg-gradient-to-br from-slate-900 via-purple-950 to-slate-900'
: 'bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50'
}`}>
{/* Background Particles */}
<div className="fixed inset-0 overflow-hidden pointer-events-none">
{particles.map(p => (
<div key={p.id}
className={`absolute rounded-full blur-sm transition-colors duration-700 ${darkMode ? 'bg-purple-500' : 'bg-pink-400'}`}
style={{
width: p.size + 'px',
height: p.size + 'px',
left: p.x + '%',
top: p.y + '%',
animation: `float ${p.duration}s linear infinite`,
animationDelay: p.delay + 's',
opacity: 0.4
}}
/>
))}
<div className={`absolute top-0 left-0 w-96 h-96 rounded-full blur-[100px] opacity-20 ${darkMode ? 'bg-purple-600' : 'bg-pink-400'}`} style={{ animation: 'glow 8s ease-in-out infinite' }} />
<div className={`absolute bottom-0 right-0 w-96 h-96 rounded-full blur-[100px] opacity-20 ${darkMode ? 'bg-blue-600' : 'bg-orange-400'}`} style={{ animation: 'glow 10s ease-in-out infinite' }} />
</div>
<div className="relative z-10 container mx-auto px-4 py-6 md:py-10 max-w-7xl">
{/* Header */}
<div className="flex flex-row justify-between items-center mb-10 md:mb-16 animate-slide-up">
<div className="flex items-center gap-3 md:gap-4">
<div className={`p-2 md:p-3 rounded-2xl shadow-xl relative overflow-hidden transition-all hover:scale-105 ${
darkMode ? 'bg-gradient-to-br from-purple-600 to-pink-600' : 'bg-gradient-to-br from-orange-400 to-pink-500'
}`}>
<Icons.Shield className="w-8 h-8 md:w-10 md:h-10 text-white relative z-10" />
<div className="absolute inset-0 shimmer" />
</div>
<div>
<h1 className={`text-2xl md:text-4xl font-bold tracking-tight ${textClass}`}>
DarkNeuron
</h1>
<p className={`text-xs md:text-sm font-semibold tracking-wider ${darkMode ? 'text-purple-400' : 'text-pink-600'}`}>
SpamDex AI v1.0
</p>
</div>
</div>
<button
onClick={() => setDarkMode(!darkMode)}
className={`p-3 md:p-4 rounded-full ${glassClass} hover:scale-110 active:scale-95 transition-all duration-300 shadow-lg group`}
>
<div className="group-hover:rotate-180 transition-transform duration-500">
{darkMode ? <Icons.Sun className="w-6 h-6 text-yellow-400" /> : <Icons.Moon className="w-6 h-6 text-indigo-600" />}
</div>
</button>
</div>
{/* Hero Section */}
<div className="text-center mb-12 animate-slide-up" style={{ animationDelay: '0.1s' }}>
<div className={`inline-flex items-center gap-2 px-4 py-2 rounded-full ${glassClass} mb-6 shadow-lg border-opacity-20`}>
<Icons.Sparkles className={`w-4 h-4 md:w-5 md:h-5 ${darkMode ? 'text-purple-400' : 'text-pink-500'}`} />
<span className={`text-xs md:text-sm font-semibold ${darkMode ? 'text-purple-300' : 'text-pink-600'}`}>
Powered by Advanced ML Algorithms
</span>
</div>
<h2 className={`text-5xl md:text-7xl font-bold mb-6 leading-tight ${textClass}`}>
Welcome to <br className="md:hidden"/>
<span className="cursive gradient-text inline-block hover:scale-105 transition-transform cursor-default">SpamDex</span>
</h2>
<p className={`text-base md:text-xl ${subTextClass} max-w-3xl mx-auto leading-relaxed px-4`}>
Unleash the power of <span className={`font-bold ${darkMode ? 'text-gray-200' : 'text-gray-800'}`}>AI-driven spam detection</span>.
Secure your inbox with <span className={darkMode ? 'text-purple-400' : 'text-pink-600'}>98% Accuracy</span>.
</p>
</div>
{/* Stats Bar (Grid Layout) */}
<div className="grid grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 mb-12 animate-slide-up" style={{ animationDelay: '0.2s' }}>
{stats.map((stat, idx) => (
<div key={idx} className={`${glassClass} rounded-2xl p-5 md:p-6 text-center hover:scale-105 hover:-translate-y-2 transition-all duration-300 shadow-lg cursor-default`}>
<stat.icon className={`w-8 h-8 mx-auto mb-3 ${darkMode ? 'text-purple-400' : 'text-pink-500'}`} />
<div className={`text-2xl md:text-3xl font-bold mb-1 ${textClass}`}>
{stat.value}
</div>
<div className={`text-xs md:text-sm ${subTextClass}`}>
{stat.label}
</div>
</div>
))}
</div>
{/* Main Analysis Section */}
<div className="max-w-6xl mx-auto animate-slide-up" style={{ animationDelay: '0.3s' }}>
<div className={`${glassClass} rounded-3xl p-5 md:p-8 shadow-2xl relative overflow-hidden border-opacity-40`}>
{/* Tab Header */}
<div className="flex gap-3 mb-8 border-b border-gray-500/10 pb-4">
<button className={`flex items-center gap-2 md:gap-3 px-6 py-3 rounded-xl font-bold transition-all shadow-lg text-sm md:text-base ${
darkMode
? 'bg-gradient-to-r from-purple-600 to-pink-600 text-white'
: 'bg-gradient-to-r from-orange-400 to-pink-500 text-white'
}`}>
<Icons.Mail className="w-5 h-5" />
Text Analysis
</button>
</div>
<div className="grid lg:grid-cols-3 gap-8">
{/* Left Column: Input */}
<div className="lg:col-span-2">
<div className="mb-6">
<div className="flex items-center gap-2 mb-3">
<Icons.Send className={`w-5 h-5 ${darkMode ? 'text-purple-400' : 'text-pink-500'}`} />
<label className={`text-lg font-bold ${textClass}`}>
Enter Your Message
</label>
</div>
<textarea
value={inputText}
onChange={(e) => setInputText(e.target.value)}
placeholder="Paste email content or SMS text here..."
className={`w-full h-48 p-4 rounded-xl resize-none focus:outline-none focus:ring-2 transition-all text-base md:text-lg ${
darkMode
? 'bg-slate-900/50 text-white placeholder-gray-500 focus:ring-purple-500/50 border border-white/10'
: 'bg-white/60 text-gray-900 placeholder-gray-500 focus:ring-pink-500/50 border border-gray-200'
}`}
></textarea>
</div>
<div className="flex flex-col sm:flex-row gap-4">
<button
onClick={analyzeText}
disabled={loading || !inputText.trim()}
className={`flex-1 py-4 rounded-xl font-bold text-white text-lg transition-all transform hover:scale-[1.02] active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed shadow-xl relative overflow-hidden group ${
darkMode
? 'bg-gradient-to-r from-purple-600 to-pink-600'
: 'bg-gradient-to-r from-orange-500 to-pink-500'
}`}
>
{loading && <div className="absolute inset-0 shimmer" />}
{loading ? (
<span className="flex items-center justify-center gap-2">
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
Analyzing...
</span>
) : (
<span className="flex items-center justify-center gap-2">
<Icons.Brain className="w-5 h-5 group-hover:animate-bounce" />
Analyze Message
</span>
)}
</button>
<button
onClick={() => { setInputText(''); setResult(null); }}
className={`px-6 py-4 rounded-xl font-bold transition-all hover:bg-opacity-80 active:scale-95 ${
darkMode
? 'bg-red-500/10 text-red-400 hover:bg-red-500/20 border border-red-500/20'
: 'bg-red-100 text-red-600 hover:bg-red-200'
}`}>
Clear
</button>
</div>
</div>
{/* Right Column: Results & Info */}
<div className="lg:col-span-1 flex flex-col gap-6">
{result ? (
<div className={`rounded-2xl p-6 border-2 transition-all animate-slide-up h-full flex flex-col justify-center items-center shadow-2xl relative overflow-hidden ${
result.type === 'spam'
? darkMode ? 'border-red-500/50 bg-red-900/20' : 'border-red-400 bg-red-50'
: darkMode ? 'border-green-500/50 bg-green-900/20' : 'border-green-400 bg-green-50'
}`}>
{/* Pulse Animation based on result */}
<div style={{animation: result.type === 'spam' ? 'pulse-ring 2s infinite' : 'pulse-ring-green 2s infinite'}}
className={`absolute w-32 h-32 rounded-full opacity-20 ${result.type === 'spam' ? 'bg-red-500' : 'bg-green-500'}`}></div>
<div className={`w-20 h-20 rounded-full mb-4 flex items-center justify-center z-10 ${
result.type === 'spam' ? 'bg-red-100 text-red-600' : 'bg-green-100 text-green-600'
}`}>
{result.type === 'spam' ? <Icons.AlertCircle className="w-10 h-10"/> : <Icons.CheckCircle className="w-10 h-10"/>}
</div>
<h3 className={`text-2xl font-bold text-center mb-1 ${
result.type === 'spam' ? 'text-red-500' : 'text-green-600'
}`}>
{result.type === 'spam' ? 'SPAM DETECTED!' : 'SAFE MESSAGE'}
</h3>
<div className={`text-center ${subTextClass} mt-2`}>
<p className="text-xs uppercase tracking-widest opacity-70 mb-1">Confidence Score</p>
<p className={`text-4xl font-bold ${textClass}`}>{result.confidence.toFixed(1)}%</p>
</div>
</div>
) : (
<div className={`${glassClass} rounded-2xl p-6 h-full min-h-[250px] flex flex-col items-center justify-center text-center border border-dashed ${darkMode ? 'border-gray-700' : 'border-gray-300'}`}>
<Icons.Brain className={`w-16 h-16 mb-4 opacity-30 ${textClass}`} />
<p className={`text-sm ${subTextClass}`}>
Your analysis results will appear here automatically.
</p>
</div>
)}
</div>
</div>
{/* Examples */}
<div className="mt-8 pt-6 border-t border-gray-500/20">
<div className="flex items-center gap-2 mb-4">
<Icons.Sparkles className={`w-4 h-4 ${darkMode ? 'text-purple-400' : 'text-pink-500'}`} />
<span className={`text-sm font-bold uppercase tracking-wider ${subTextClass}`}>
Or try these examples
</span>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{examples.map((example, idx) => (
<button
key={idx}
onClick={() => setInputText(example.text)}
className={`p-4 rounded-xl text-left transition-all hover:-translate-y-1 group flex items-start gap-3 ${
darkMode
? 'bg-white/5 hover:bg-white/10 border border-white/5'
: 'bg-white hover:bg-gray-50 border border-gray-200 shadow-sm'
}`}>
<div className={`mt-0.5 ${example.type === 'spam' ? 'text-red-500' : 'text-green-500'}`}>
{example.type === 'spam' ? <Icons.AlertCircle className="w-4 h-4"/> : <Icons.CheckCircle className="w-4 h-4"/>}
</div>
<span className={`text-xs md:text-sm line-clamp-2 ${darkMode ? 'text-gray-300' : 'text-gray-600'}`}>
{example.text}
</span>
</button>
))}
</div>
</div>
</div>
</div>
{/* Features Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 md:gap-6 my-12 animate-slide-up" style={{ animationDelay: '0.4s' }}>
{features.map((feature, idx) => (
<div key={idx} className={`${glassClass} rounded-2xl p-6 text-center hover:scale-105 hover:shadow-xl transition-all duration-300 cursor-default group`}>
<div className={`w-14 h-14 mx-auto mb-4 rounded-2xl bg-gradient-to-br ${feature.color} flex items-center justify-center shadow-lg group-hover:rotate-12 transition-transform`}>
<feature.icon className="w-7 h-7 text-white" />
</div>
<h3 className={`text-lg font-bold mb-2 ${textClass}`}>
{feature.title}
</h3>
<p className={`text-xs md:text-sm ${subTextClass} leading-relaxed`}>
{feature.desc}
</p>
</div>
))}
</div>
{/* API Section */}
<div className={`${glassClass} rounded-3xl p-6 md:p-8 shadow-2xl animate-slide-up mb-10`} style={{ animationDelay: '0.5s' }}>
<div className="flex items-center gap-3 mb-6">
<Icons.Code className={`w-7 h-7 md:w-8 md:h-8 ${darkMode ? 'text-purple-400' : 'text-pink-500'}`} />
<h3 className={`text-xl md:text-2xl font-bold ${textClass}`}>
API Integration
</h3>
</div>
<div className={`flex flex-col md:flex-row items-center gap-4 p-4 rounded-xl ${darkMode ? 'bg-gray-900/50 border border-white/10' : 'bg-gray-100 border border-gray-200'}`}>
<div className="flex-1 w-full overflow-hidden">
<code className={`block text-xs md:text-base font-mono truncate ${darkMode ? 'text-cyan-400' : 'text-purple-600'}`}>
POST {currentUrl}/api/predict
</code>
</div>
<button
onClick={copyApiEndpoint}
className={`flex items-center gap-2 px-4 py-2 rounded-lg transition-all hover:scale-105 active:scale-95 font-medium text-sm ${
darkMode ? 'bg-white/10 hover:bg-white/20 text-white' : 'bg-white hover:bg-gray-50 text-gray-700 shadow-sm'
}`}>
{copied ? <Icons.Check className="w-4 h-4 text-green-500" /> : <Icons.Copy className="w-4 h-4" />}
{copied ? 'Copied!' : 'Copy Endpoint'}
</button>
</div>
<p className={`mt-4 text-sm ${subTextClass}`}>
Send a JSON body <code>{`{"text": "your message"}`}</code> to get a prediction.
</p>
</div>
{/* Footer */}
<div className={`text-center pb-8 ${subTextClass} animate-slide-up`} style={{ animationDelay: '0.6s' }}>
<p className="text-sm flex items-center justify-center gap-2">
Crafted with <span className="text-red-500 animate-pulse text-lg">❀️</span> by
<span className="font-bold cursive text-lg gradient-text">@Madara369Uchiha</span>
</p>
</div>
</div>
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<SpamDexUI />);
</script>
</body>
</html>