ca-grow-ops-manager/frontend/src/components/aura/BentoGrid.tsx
fullsizemalt 38f9ef5f0b
Some checks are pending
Test / backend-test (push) Waiting to run
Test / frontend-test (push) Waiting to run
style: Complete visual refactor with CSS variable tokens
- Apply Climate Monitoring design system to all 81 files
- Replace 931 hardcoded color references with CSS variables
- Consistent theming: --color-primary, --color-text-*, --color-bg-*
- Status colors: --color-error, --color-warning, --color-accent
2025-12-27 11:55:09 -08:00

129 lines
4.4 KiB
TypeScript

import { ReactNode } from "react";
import { ArrowRight, LucideIcon } from "lucide-react";
import { Link } from "react-router-dom";
import { cn } from "../../lib/utils";
/**
* Bento Grid Components - Feature 14 from AuraUI
*
* A responsive, modular grid system for dashboard widgets.
*/
// --- Grid Container ---
export const BentoGrid = ({
children,
className,
}: {
children: ReactNode;
className?: string;
}) => {
return (
<div
className={cn(
"grid w-full auto-rows-[22rem] grid-cols-1 md:grid-cols-3 gap-4",
className
)}
>
{children}
</div>
);
};
// --- Grid Item (Card) ---
interface BentoCardProps {
name: string;
className: string;
background?: ReactNode;
Icon: LucideIcon;
description: string;
href: string;
cta?: string;
children?: ReactNode; // For custom content inside the card
value?: string | number; // For metric displays
}
export const BentoCard = ({
name,
className,
background,
Icon,
description,
href,
cta = "View Details",
children,
value
}: BentoCardProps) => {
return (
<div
key={name}
className={cn(
"group relative col-span-3 flex flex-col justify-between overflow-hidden rounded-xl",
// Light mode styles
"bg-white border border-slate-200", // shadow-sm
// Dark mode styles
"dark:bg-slate-950 dark:border-slate-800",
className
)}
>
{/* Background Graphic (optional) */}
<div className="absolute inset-0 z-0 opacity-20 group-hover:opacity-40 transition-opacity duration-500">
{background}
</div>
{/* Content Area */}
<div className="relative z-10 p-6 flex flex-col h-full pointer-events-none">
{/* Header */}
<div className="flex items-center gap-2 mb-2">
<div className="p-2 rounded-lg bg-[var(--color-bg-tertiary)] group-hover:bg-cyan-50 dark:group-hover:bg-cyan-950/30 transition-colors duration-300">
<Icon className="h-5 w-5 text-slate-600 dark:text-[var(--color-text-tertiary)] group-hover:text-cyan-600 dark:group-hover:text-cyan-400 transition-colors" />
</div>
<h3 className="font-semibold text-slate-900 dark:text-slate-50 text-lg">
{name}
</h3>
</div>
{/* Metric Value (if provided) - Large display */}
{value && (
<div className="mt-4 mb-2">
<span className="text-4xl font-bold text-[var(--color-text-primary)] tracking-tight">
{value}
</span>
</div>
)}
{/* Description / Subtext */}
<p className="text-[var(--color-text-tertiary)] text-sm leading-relaxed max-w-[90%]">
{description}
</p>
{/* Custom Children (Charts, Lists, etc) */}
{children && (
<div className="flex-1 mt-4 min-h-0 overflow-hidden">
{children}
</div>
)}
</div>
{/* Interactive Footer / CTA */}
<div
className={cn(
"pointer-events-auto",
"absolute bottom-0 flex w-full translate-y-10 flex-row items-center p-4 opacity-0 transition-all duration-300 group-hover:translate-y-0 group-hover:opacity-100",
"bg-gradient-to-t from-white via-white to-transparent dark:from-slate-950 dark:via-slate-950"
)}
>
<Link
to={href}
className="flex items-center gap-2 text-sm font-medium text-cyan-600 dark:text-cyan-400 hover:text-cyan-700 dark:hover:text-cyan-300"
>
{cta}
<ArrowRight className="ml-2 h-4 w-4" />
</Link>
</div>
{/* Hover Effect Details */}
<div className="pointer-events-none absolute inset-0 transform-gpu transition-all duration-300 group-hover:bg-black/[.03] group-hover:dark:bg-neutral-800/10" />
</div>
);
};