feat: initialize Infra Manager with React, Tailwind CSS, and Inertia.js
- Added main application entry point (app.jsx) and bootstrap file for React setup. - Created Wiki index page (Index.jsx) for documentation and file management. - Implemented utility functions for formatting and status handling in utils.js. - Set up Blade template (app.blade.php) for Inertia.js integration. - Defined API routes for metrics and terminal access in api.php. - Established console commands for scheduled tasks in console.php. - Created web routes for various application features including authentication, hypervisors, containers, cloud accounts, security, backups, and wiki management in web.php. - Developed setup scripts for Windows (setup.ps1) and Linux (setup.sh) environments. - Configured Tailwind CSS for styling with custom themes and animations in tailwind.config.js. - Set up Vite for asset bundling and development server in vite.config.js.
This commit is contained in:
154
resources/js/Pages/Auth/Login.jsx
Normal file
154
resources/js/Pages/Auth/Login.jsx
Normal file
@@ -0,0 +1,154 @@
|
||||
import { useForm, Head } from '@inertiajs/react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Zap, Lock, Mail, Eye, EyeOff, AlertCircle } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { Button } from '@/Components/ui/Button';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
export default function Login({ ldapEnabled }) {
|
||||
const { data, setData, post, processing, errors } = useForm({
|
||||
email: '',
|
||||
password: '',
|
||||
remember: false,
|
||||
});
|
||||
const [showPass, setShowPass] = useState(false);
|
||||
|
||||
const submit = (e) => {
|
||||
e.preventDefault();
|
||||
post('/login');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="Sign In" />
|
||||
<div className="min-h-screen bg-[#050a0e] flex items-center justify-center p-4 relative overflow-hidden">
|
||||
{/* Background effects */}
|
||||
<div className="absolute inset-0 bg-grid-pattern opacity-50" />
|
||||
<div className="absolute top-1/4 left-1/4 w-96 h-96 bg-cyan-500/5 rounded-full blur-3xl" />
|
||||
<div className="absolute bottom-1/4 right-1/4 w-96 h-96 bg-purple-500/5 rounded-full blur-3xl" />
|
||||
|
||||
{/* Meteors */}
|
||||
{Array.from({ length: 8 }).map((_, i) => (
|
||||
<motion.div
|
||||
key={i}
|
||||
className="absolute w-0.5 h-16 bg-gradient-to-b from-cyan-400/60 to-transparent rounded-full"
|
||||
style={{ top: `${Math.random() * 100}%`, left: `${Math.random() * 100}%`, rotate: -45 }}
|
||||
animate={{ x: [0, -300], y: [0, 300], opacity: [0, 1, 0] }}
|
||||
transition={{ duration: 2 + Math.random() * 3, repeat: Infinity, delay: i * 0.7, ease: 'linear' }}
|
||||
/>
|
||||
))}
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ duration: 0.5 }}
|
||||
className="w-full max-w-md relative z-10"
|
||||
>
|
||||
{/* Logo */}
|
||||
<div className="text-center mb-8">
|
||||
<div className="inline-flex items-center justify-center w-16 h-16 rounded-2xl bg-gradient-to-br from-cyan-500 to-purple-600 mb-4 shadow-[0_0_40px_rgba(0,212,255,0.3)]">
|
||||
<Zap className="w-8 h-8 text-white" />
|
||||
</div>
|
||||
<h1 className="text-2xl font-bold text-white">Infra Manager</h1>
|
||||
<p className="text-sm text-white/40 mt-1">Unified Infrastructure Control Plane</p>
|
||||
</div>
|
||||
|
||||
{/* Card */}
|
||||
<div className="relative rounded-2xl border border-white/10 bg-white/[0.03] backdrop-blur-xl p-8">
|
||||
{/* Gradient border glow */}
|
||||
<div className="absolute inset-0 rounded-2xl bg-gradient-to-br from-cyan-500/10 via-transparent to-purple-500/10 pointer-events-none" />
|
||||
|
||||
<form onSubmit={submit} className="relative space-y-5">
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/60 mb-1.5">Email Address</label>
|
||||
<div className="relative">
|
||||
<Mail className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/30" />
|
||||
<input
|
||||
type="email"
|
||||
value={data.email}
|
||||
onChange={e => setData('email', e.target.value)}
|
||||
placeholder="admin@infra.local"
|
||||
required
|
||||
className={cn(
|
||||
'w-full pl-10 pr-4 py-2.5 bg-white/5 border rounded-xl text-sm text-white placeholder:text-white/20',
|
||||
'focus:outline-none focus:border-cyan-500/60 focus:bg-white/[0.07] transition-all',
|
||||
errors.email ? 'border-red-500/60' : 'border-white/10'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{errors.email && (
|
||||
<p className="flex items-center gap-1 mt-1.5 text-xs text-red-400">
|
||||
<AlertCircle className="w-3 h-3" />{errors.email}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-medium text-white/60 mb-1.5">Password</label>
|
||||
<div className="relative">
|
||||
<Lock className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-white/30" />
|
||||
<input
|
||||
type={showPass ? 'text' : 'password'}
|
||||
value={data.password}
|
||||
onChange={e => setData('password', e.target.value)}
|
||||
placeholder="••••••••"
|
||||
required
|
||||
className={cn(
|
||||
'w-full pl-10 pr-10 py-2.5 bg-white/5 border rounded-xl text-sm text-white placeholder:text-white/20',
|
||||
'focus:outline-none focus:border-cyan-500/60 focus:bg-white/[0.07] transition-all',
|
||||
errors.password ? 'border-red-500/60' : 'border-white/10'
|
||||
)}
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setShowPass(s => !s)}
|
||||
className="absolute right-3 top-1/2 -translate-y-1/2 text-white/30 hover:text-white/60 transition-colors"
|
||||
>
|
||||
{showPass ? <EyeOff className="w-4 h-4" /> : <Eye className="w-4 h-4" />}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between">
|
||||
<label className="flex items-center gap-2 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={data.remember}
|
||||
onChange={e => setData('remember', e.target.checked)}
|
||||
className="w-3.5 h-3.5 rounded border-white/20 bg-white/5 text-cyan-500 focus:ring-0 focus:ring-offset-0"
|
||||
/>
|
||||
<span className="text-xs text-white/50">Remember me</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
size="lg"
|
||||
loading={processing}
|
||||
className="w-full"
|
||||
>
|
||||
Sign In
|
||||
</Button>
|
||||
|
||||
{ldapEnabled && (
|
||||
<div className="relative">
|
||||
<div className="absolute inset-0 flex items-center">
|
||||
<span className="w-full border-t border-white/10" />
|
||||
</div>
|
||||
<div className="relative flex justify-center text-xs">
|
||||
<span className="bg-[#07111d] px-2 text-white/30">or</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<p className="text-center text-xs text-white/20 mt-6">
|
||||
Default: admin@infra.local / Admin@123456
|
||||
</p>
|
||||
</motion.div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user