Spaces:
Running
Running
File size: 8,651 Bytes
7b4f5dd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 | /* βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
LandingPage β Hero section with GitHub URL input & code paste
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
import { useState } from 'react';
import { useScan } from '../context/ScanContext';
import ParticleBackground from './ParticleBackground';
import './LandingPage.css';
export default function LandingPage() {
const { startScan } = useScan();
const [inputMode, setInputMode] = useState('url'); // 'url' or 'code'
const [githubUrl, setGithubUrl] = useState('');
const [codeInput, setCodeInput] = useState('');
const [language, setLanguage] = useState('javascript');
const [isStarting, setIsStarting] = useState(false);
const canScan = inputMode === 'url' ? githubUrl.trim().length > 0 : codeInput.trim().length > 0;
const handleScan = async () => {
if (!canScan || isStarting) return;
// Request Notification permission on user gesture
if ('Notification' in window && Notification.permission === 'default') {
Notification.requestPermission();
}
setIsStarting(true);
const sessionId = `cs-${Math.random().toString(36).substring(2, 11)}-${Date.now()}`;
let sourceType = 'github';
if (inputMode === 'url') {
if (githubUrl.includes('huggingface.co')) {
sourceType = 'huggingface';
}
} else {
sourceType = 'code';
}
const payload = inputMode === 'url'
? {
source_type: sourceType,
source: githubUrl.trim(),
session_id: sessionId
}
: {
source_type: sourceType,
source: codeInput.trim(),
session_id: sessionId
};
await startScan(payload);
};
const handleKeyDown = (e) => {
if (e.key === 'Enter' && !e.shiftKey && inputMode === 'url') {
e.preventDefault();
handleScan();
}
};
return (
<div className="landing-page">
<div className="vignette-overlay" />
<div className="ambient-light" />
<ParticleBackground />
{/* Header */}
<header className="landing-header">
<div className="header-logo">
<span className="shield-icon">π‘οΈ</span>
<span className="logo-text">CodeSentry</span>
</div>
</header>
{/* Hero */}
<main className="landing-main">
<div className="hero-section">
<div className="hero-badge animate-fade-in">
<span className="status-dot scanning" />
<span>AI-Powered Security Intelligence</span>
</div>
<h1 className="hero-title animate-fade-in-up">
Secure Your Code<br />
<span className="hero-gradient">Before It Ships</span>
</h1>
<p className="hero-subtitle animate-fade-in-up" style={{ animationDelay: '0.1s' }}>
3 AI agents analyze your codebase in real-time β detecting vulnerabilities,
finding performance issues, and generating fixes. All locally, all privately.
</p>
{/* Privacy Banner */}
<div className="privacy-banner animate-fade-in-up" style={{ animationDelay: '0.2s' }}>
<span>π</span>
<span>Your code never leaves this machine β 100% local inference, zero data retention</span>
</div>
</div>
{/* Input Section */}
<div className="input-section animate-fade-in-up" style={{ animationDelay: '0.3s' }}>
{/* Mode Tabs */}
<div className="input-tabs">
<button
id="tab-github-url"
className={`input-tab ${inputMode === 'url' ? 'active' : ''}`}
onClick={() => setInputMode('url')}
>
<span>π/π€</span> Repo URL
</button>
<button
id="tab-paste-code"
className={`input-tab ${inputMode === 'code' ? 'active' : ''}`}
onClick={() => setInputMode('code')}
>
<span>π</span> Paste Code
</button>
</div>
{/* Input Area */}
<div className="input-area glass-card-static">
{inputMode === 'url' ? (
<div className="url-input-wrapper">
<div className="input-icon">π</div>
<input
id="github-url-input"
type="url"
className="input-field"
placeholder="https://github.com/owner/repo or https://huggingface.co/spaces/owner/repo"
value={githubUrl}
onChange={(e) => setGithubUrl(e.target.value)}
onKeyDown={handleKeyDown}
autoFocus
/>
</div>
) : (
<div className="code-input-wrapper">
<div className="code-input-header">
<select
id="language-select"
className="language-select"
value={language}
onChange={(e) => setLanguage(e.target.value)}
>
<option value="javascript">JavaScript</option>
<option value="python">Python</option>
<option value="typescript">TypeScript</option>
<option value="java">Java</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="cpp">C++</option>
<option value="csharp">C#</option>
</select>
<span className="line-count mono text-secondary">
{codeInput.split('\n').filter(l => l.trim()).length} lines
</span>
</div>
<textarea
id="code-paste-editor"
className="code-editor"
placeholder="// Paste your code here for analysis... const express = require('express'); const app = express(); app.get('/user/:id', async (req, res) => { const query = `SELECT * FROM users WHERE id = '${req.params.id}'`; // ... });"
value={codeInput}
onChange={(e) => setCodeInput(e.target.value)}
spellCheck={false}
/>
</div>
)}
</div>
{/* Scan Button */}
<button
id="scan-button"
className={`scan-btn ${canScan ? 'animate-glow' : ''}`}
onClick={handleScan}
disabled={!canScan || isStarting}
>
{isStarting ? (
<>
<span className="scan-spinner">β³</span>
<span>Initializing Agents...</span>
</>
) : (
<>
<span className="scan-icon">β‘</span>
<span>Launch Security Scan</span>
</>
)}
</button>
</div>
{/* Feature Cards */}
<div className="features-grid animate-fade-in-up" style={{ animationDelay: '0.5s' }}>
<div className="feature-card glass-card">
<div className="feature-icon agent-security">π</div>
<h4>Security Agent</h4>
<p>OWASP vulnerabilities, prompt injection, hardcoded secrets, auth weaknesses</p>
</div>
<div className="feature-card glass-card">
<div className="feature-icon agent-performance">β‘</div>
<h4>Performance Agent</h4>
<p>Memory leaks, N+1 queries, GPU inefficiencies, tensor optimization</p>
</div>
<div className="feature-card glass-card">
<div className="feature-icon agent-fix">π§</div>
<h4>Fix Agent</h4>
<p>AI-generated patches, before/after diffs, secure code suggestions</p>
</div>
</div>
</main>
{/* Footer */}
<footer className="landing-footer">
<div className="footer-content">
<span className="footer-powered">
Powered by <strong>Qwen</strong> Β· Built on <strong>AMD</strong>
</span>
<span className="footer-divider">β’</span>
<span className="text-secondary">Privacy-First AI Security</span>
</div>
</footer>
</div>
);
}
|