Ash-211's picture
Fix OOM: lazy-load ML models, rename to VectorMind
de88b8d
Raw
History Blame Contribute Delete
11.4 kB
import { useState } from 'react'
import './TopNav.css'
function TopNav({
user,
isAuthenticated,
onLogin,
onRegister,
onLogout,
onToggleSidebar,
sidebarOpen
}) {
const [showAuthModal, setShowAuthModal] = useState(false)
const [authMode, setAuthMode] = useState('login')
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
const [firstName, setFirstName] = useState('')
const [lastName, setLastName] = useState('')
const [email, setEmail] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const handleSubmit = async (e) => {
e.preventDefault()
setLoading(true)
setError('')
try {
if (authMode === 'login') {
await onLogin(username, password)
} else {
await onRegister({ username, password, first_name: firstName, last_name: lastName, email })
}
setShowAuthModal(false)
setUsername('')
setPassword('')
setFirstName('')
setLastName('')
setEmail('')
} catch (err) {
setError(err.message)
} finally {
setLoading(false)
}
}
return (
<>
<nav className="topnav">
<div className="topnav-left">
<button
className="btn btn-ghost btn-icon sidebar-toggle"
onClick={onToggleSidebar}
aria-label="Toggle sidebar"
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
{sidebarOpen ? (
<path d="M11 19l-7-7 7-7M18 19l-7-7 7-7" />
) : (
<path d="M3 12h18M3 6h18M3 18h18" />
)}
</svg>
</button>
<div className="topnav-brand">
<div className="brand-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
<path
d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"
stroke="url(#brand-gradient)"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<defs>
<linearGradient id="brand-gradient" x1="2" y1="2" x2="22" y2="22">
<stop stopColor="#6366f1" />
<stop offset="1" stopColor="#a855f7" />
</linearGradient>
</defs>
</svg>
</div>
<span className="brand-name">VectorMind</span>
</div>
</div>
<div className="topnav-right">
{isAuthenticated ? (
<div className="user-menu">
<div className="user-avatar">
{user?.[0]?.toUpperCase() || 'U'}
</div>
<span className="user-name">{user}</span>
<button className="btn btn-ghost btn-sm" onClick={onLogout}>
Logout
</button>
</div>
) : (
<button
className="btn btn-primary btn-sm"
onClick={() => setShowAuthModal(true)}
>
Sign In
</button>
)}
</div>
</nav>
{/* Auth Modal */}
{showAuthModal && (
<div className="modal-overlay" onClick={() => setShowAuthModal(false)}>
<div className="modal card-glass" onClick={e => e.stopPropagation()}>
<div className="modal-header">
<h2>{authMode === 'login' ? 'Welcome Back' : 'Create Account'}</h2>
<button
className="btn btn-ghost btn-icon"
onClick={() => setShowAuthModal(false)}
>
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M18 6L6 18M6 6l12 12" />
</svg>
</button>
</div>
<form onSubmit={handleSubmit} className="auth-form">
{error && (
<div className="auth-error">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<circle cx="12" cy="12" r="10" />
<path d="M12 8v4M12 16h.01" />
</svg>
{error}
</div>
)}
<div className="form-group">
<label htmlFor="username">Username</label>
<input
id="username"
type="text"
className="input"
value={username}
onChange={e => setUsername(e.target.value)}
placeholder="Enter username"
required
autoComplete="username"
/>
</div>
<div className="form-group">
<label htmlFor="password">Password</label>
<input
id="password"
type="password"
className="input"
value={password}
onChange={e => setPassword(e.target.value)}
placeholder="Enter password"
required
autoComplete={authMode === 'login' ? 'current-password' : 'new-password'}
/>
</div>
{authMode === 'register' && (
<>
<div className="form-row">
<div className="form-group">
<label htmlFor="firstName">First Name</label>
<input
id="firstName"
type="text"
className="input"
value={firstName}
onChange={e => setFirstName(e.target.value)}
placeholder="First name"
required
/>
</div>
<div className="form-group">
<label htmlFor="lastName">Last Name</label>
<input
id="lastName"
type="text"
className="input"
value={lastName}
onChange={e => setLastName(e.target.value)}
placeholder="Last name"
required
/>
</div>
</div>
<div className="form-group">
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
className="input"
value={email}
onChange={e => setEmail(e.target.value)}
placeholder="you@example.com"
required
/>
</div>
</>
)}
<button
type="submit"
className="btn btn-primary btn-lg"
disabled={loading}
style={{ width: '100%' }}
>
{loading ? (
<span className="loading-dots">
<span></span><span></span><span></span>
</span>
) : authMode === 'login' ? 'Sign In' : 'Create Account'}
</button>
<div className="auth-switch">
{authMode === 'login' ? (
<>
Don't have an account?{' '}
<button type="button" onClick={() => setAuthMode('register')}>
Sign up
</button>
</>
) : (
<>
Already have an account?{' '}
<button type="button" onClick={() => setAuthMode('login')}>
Sign in
</button>
</>
)}
</div>
</form>
</div>
</div>
)}
</>
)
}
export default TopNav