Files
I-Fun c649f055d8 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.
2026-04-07 20:29:32 +07:00

60 lines
3.0 KiB
JavaScript

import { motion } from 'framer-motion';
import { cn } from '@/lib/utils';
export function GlassCard({ children, className, hover = true, glow, ...props }) {
return (
<motion.div
whileHover={hover ? { y: -2, scale: 1.005 } : undefined}
transition={{ type: 'spring', stiffness: 300, damping: 30 }}
className={cn(
'relative overflow-hidden rounded-xl',
'border border-white/10 bg-white/[0.03] backdrop-blur-xl',
hover && 'cursor-pointer',
glow === 'cyan' && 'hover:border-cyan-500/40 hover:shadow-[0_0_30px_rgba(0,212,255,0.1)]',
glow === 'green' && 'hover:border-green-500/40 hover:shadow-[0_0_30px_rgba(0,255,136,0.1)]',
glow === 'purple' && 'hover:border-purple-500/40 hover:shadow-[0_0_30px_rgba(157,78,221,0.1)]',
className
)}
{...props}
>
{/* Inner gradient */}
<div className="absolute inset-0 bg-gradient-to-br from-white/[0.02] to-transparent pointer-events-none" />
<div className="relative z-10">{children}</div>
</motion.div>
);
}
export function StatCard({ title, value, subtitle, icon: Icon, color = 'cyan', trend, className }) {
const colors = {
cyan: { text: 'text-cyan-400', bg: 'bg-cyan-500/10', border: 'border-cyan-500/20' },
green: { text: 'text-green-400', bg: 'bg-green-500/10', border: 'border-green-500/20' },
purple: { text: 'text-purple-400', bg: 'bg-purple-500/10', border: 'border-purple-500/20' },
orange: { text: 'text-orange-400', bg: 'bg-orange-500/10', border: 'border-orange-500/20' },
red: { text: 'text-red-400', bg: 'bg-red-500/10', border: 'border-red-500/20' },
blue: { text: 'text-blue-400', bg: 'bg-blue-500/10', border: 'border-blue-500/20' },
};
const c = colors[color] ?? colors.cyan;
return (
<GlassCard className={cn('p-5', className)} glow={color === 'cyan' ? 'cyan' : undefined}>
<div className="flex items-start justify-between">
<div className="flex-1">
<p className="text-xs font-medium text-white/50 uppercase tracking-wider mb-1">{title}</p>
<p className={cn('text-3xl font-bold tracking-tight', c.text)}>{value}</p>
{subtitle && <p className="text-xs text-white/40 mt-1">{subtitle}</p>}
{trend !== undefined && (
<p className={cn('text-xs mt-2', trend >= 0 ? 'text-green-400' : 'text-red-400')}>
{trend >= 0 ? '↑' : '↓'} {Math.abs(trend)}% vs last hour
</p>
)}
</div>
{Icon && (
<div className={cn('p-2.5 rounded-lg border', c.bg, c.border)}>
<Icon className={cn('w-5 h-5', c.text)} />
</div>
)}
</div>
</GlassCard>
);
}