Overhaul the GuruRMM dashboard with a dark cyberpunk aesthetic featuring glassmorphism effects, cyan accent lighting, and smooth animations. Visual Changes: - Dark theme with CSS variables for consistent theming - Glassmorphism card effects with colored glow variants - Grid pattern backgrounds and floating geometric shapes - JetBrains Mono + Inter font pairing for tech aesthetic - Cyan, green, amber, and rose accent colors with glow effects Component Updates: - index.css: Complete CSS overhaul with utility classes, animations, and glassmorphism foundations (1300+ lines added) - Login.tsx: Glassmorphism login card with gradient logo and floating background shapes - Layout.tsx: Dark sidebar with cyan nav highlights, grid pattern main area, animated user profile section - Dashboard.tsx: Animated stat cards with staggered entrances, live status indicator with pulse animation, relative timestamps - Card.tsx: Added glow variants (cyan/green/amber/rose) with hover lift effects - Button.tsx: Gradient backgrounds, glow-on-hover, scale animations - Input.tsx: Dark styling with cyan focus glow, added Textarea component Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
142 lines
4.1 KiB
TypeScript
142 lines
4.1 KiB
TypeScript
import { HTMLAttributes, forwardRef } from "react";
|
|
import { cn } from "../lib/utils";
|
|
|
|
/**
|
|
* Mission Control Card Component
|
|
* Glassmorphism design with optional glow variants
|
|
*/
|
|
|
|
export type CardVariant = "default" | "glow-cyan" | "glow-green" | "glow-amber" | "glow-rose";
|
|
|
|
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
variant?: CardVariant;
|
|
}
|
|
|
|
const cardVariants: Record<CardVariant, string> = {
|
|
default: "border-slate-700/50",
|
|
"glow-cyan": "border-cyan-500/50 shadow-[0_0_15px_rgba(6,182,212,0.15)]",
|
|
"glow-green": "border-emerald-500/50 shadow-[0_0_15px_rgba(16,185,129,0.15)]",
|
|
"glow-amber": "border-amber-500/50 shadow-[0_0_15px_rgba(245,158,11,0.15)]",
|
|
"glow-rose": "border-rose-500/50 shadow-[0_0_15px_rgba(244,63,94,0.15)]",
|
|
};
|
|
|
|
const cardHoverVariants: Record<CardVariant, string> = {
|
|
default: "hover:border-slate-600/70 hover:shadow-lg hover:shadow-slate-900/50",
|
|
"glow-cyan": "hover:border-cyan-400/70 hover:shadow-[0_0_25px_rgba(6,182,212,0.25)]",
|
|
"glow-green": "hover:border-emerald-400/70 hover:shadow-[0_0_25px_rgba(16,185,129,0.25)]",
|
|
"glow-amber": "hover:border-amber-400/70 hover:shadow-[0_0_25px_rgba(245,158,11,0.25)]",
|
|
"glow-rose": "hover:border-rose-400/70 hover:shadow-[0_0_25px_rgba(244,63,94,0.25)]",
|
|
};
|
|
|
|
const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
({ className, variant = "default", ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
// Base glassmorphism
|
|
"rounded-xl bg-slate-900/60 backdrop-blur-xl",
|
|
// Border
|
|
"border",
|
|
cardVariants[variant],
|
|
// Inner shadow for depth
|
|
"shadow-[inset_0_1px_0_0_rgba(148,163,184,0.1)]",
|
|
// Text color
|
|
"text-slate-100",
|
|
// Transition for hover effects
|
|
"transition-all duration-300 ease-out",
|
|
// Hover: subtle lift
|
|
"hover:-translate-y-0.5",
|
|
cardHoverVariants[variant],
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
Card.displayName = "Card";
|
|
|
|
const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"flex flex-col space-y-1.5 p-6",
|
|
// Bottom border separator
|
|
"border-b border-slate-700/50",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
CardHeader.displayName = "CardHeader";
|
|
|
|
export interface CardTitleProps extends HTMLAttributes<HTMLHeadingElement> {
|
|
gradient?: boolean;
|
|
gradientFrom?: string;
|
|
gradientTo?: string;
|
|
}
|
|
|
|
const CardTitle = forwardRef<HTMLParagraphElement, CardTitleProps>(
|
|
({ className, gradient = false, gradientFrom = "cyan-400", gradientTo = "blue-500", ...props }, ref) => (
|
|
<h3
|
|
ref={ref}
|
|
className={cn(
|
|
// Monospace/bold styling
|
|
"font-mono font-bold leading-none tracking-tight text-lg",
|
|
// Gradient text option
|
|
gradient && [
|
|
"bg-clip-text text-transparent",
|
|
`bg-gradient-to-r from-${gradientFrom} to-${gradientTo}`,
|
|
],
|
|
// Default text color when not gradient
|
|
!gradient && "text-slate-100",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
CardTitle.displayName = "CardTitle";
|
|
|
|
const CardDescription = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(
|
|
({ className, ...props }, ref) => (
|
|
<p
|
|
ref={ref}
|
|
className={cn(
|
|
"text-sm text-slate-400",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
CardDescription.displayName = "CardDescription";
|
|
|
|
const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn("p-6 pt-0", className)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
CardContent.displayName = "CardContent";
|
|
|
|
const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
|
({ className, ...props }, ref) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
"flex items-center p-6 pt-0",
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
)
|
|
);
|
|
CardFooter.displayName = "CardFooter";
|
|
|
|
export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter };
|