- Added new shadow variables for light, medium, and heavy effects in `globals.css` to improve card depth. - Updated `Card` and `StyledCard` components to utilize these shadows and introduced gradient backgrounds for a more dynamic appearance. - Enhanced hover effects in `TaskCard` for improved user interaction with scaling and opacity transitions.
177 lines
7.0 KiB
TypeScript
177 lines
7.0 KiB
TypeScript
import { HTMLAttributes, forwardRef } from 'react';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
|
variant?: 'default' | 'elevated' | 'bordered' | 'column' | 'glass';
|
|
shadow?: 'none' | 'sm' | 'md' | 'lg';
|
|
border?: 'none' | 'default' | 'primary' | 'accent';
|
|
background?: 'default' | 'column' | 'muted';
|
|
}
|
|
|
|
const Card = forwardRef<HTMLDivElement, CardProps>(
|
|
({ className, variant = 'default', shadow = 'sm', border = 'default', background = 'default', ...props }, ref) => {
|
|
const backgrounds = {
|
|
default: 'bg-[var(--card)] bg-gradient-to-br from-[var(--card)] via-[color-mix(in_srgb,var(--card)_90%,var(--background)_10%)] to-[color-mix(in_srgb,var(--card)_75%,var(--background)_25%)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_8%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_4%,transparent)] before:to-transparent before:opacity-80',
|
|
column: 'bg-[var(--card-column)] bg-gradient-to-br from-[var(--card-column)] via-[color-mix(in_srgb,var(--card-column)_90%,var(--background)_10%)] to-[color-mix(in_srgb,var(--card-column)_75%,var(--background)_25%)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_10%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_5%,transparent)] before:to-transparent before:opacity-90',
|
|
muted: 'bg-[var(--muted)]/15 bg-gradient-to-br from-[var(--muted)]/15 via-[color-mix(in_srgb,var(--muted)_10%,var(--background)_5%)] to-[color-mix(in_srgb,var(--muted)_8%,var(--background)_7%)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-transparent before:via-[color-mix(in_srgb,var(--muted)_12%,transparent)] before:to-transparent before:opacity-60'
|
|
};
|
|
|
|
const borders = {
|
|
none: '',
|
|
default: 'border border-[var(--border)]',
|
|
primary: 'border border-[var(--primary)]/30',
|
|
accent: 'border border-[var(--accent)]/30'
|
|
};
|
|
|
|
const shadows = {
|
|
none: '',
|
|
sm: 'shadow-lg shadow-[var(--card-shadow-medium)]',
|
|
md: 'shadow-xl shadow-[var(--card-shadow-medium)]',
|
|
lg: 'shadow-2xl shadow-[var(--card-shadow-heavy)]'
|
|
};
|
|
|
|
// Variants prédéfinis pour la rétrocompatibilité
|
|
const variantStyles = {
|
|
default: 'shadow-lg shadow-[var(--card-shadow-medium)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_6%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_3%,transparent)] before:to-transparent before:opacity-70',
|
|
elevated: 'shadow-xl shadow-[var(--card-shadow-heavy)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_8%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_4%,transparent)] before:to-[color-mix(in_srgb,var(--primary)_2%,transparent)] before:opacity-80',
|
|
bordered: 'border-[var(--primary)]/40 shadow-xl shadow-[var(--primary)]/20 relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_10%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_5%,transparent)] before:to-transparent before:opacity-90',
|
|
column: 'bg-[var(--card-column)] shadow-xl shadow-[var(--card-shadow-heavy)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_8%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_4%,transparent)] before:to-[color-mix(in_srgb,var(--primary)_2%,transparent)] before:opacity-80',
|
|
glass: 'bg-[var(--card)]/40 border border-[var(--border)]/60 backdrop-blur-md shadow-xl shadow-[var(--card-shadow-medium)] relative before:absolute before:inset-0 before:rounded-lg before:bg-gradient-to-br before:from-[color-mix(in_srgb,var(--primary)_12%,transparent)] before:via-[color-mix(in_srgb,var(--primary)_6%,transparent)] before:to-transparent before:opacity-90'
|
|
};
|
|
|
|
// Appliquer le variant si spécifié, sinon utiliser les props individuelles
|
|
const finalShadow = variant !== 'default' ? variantStyles[variant] : shadows[shadow];
|
|
const finalBorder = variant !== 'default' ? variantStyles[variant] : borders[border];
|
|
const finalBackground = variant !== 'default' ? variantStyles[variant] : backgrounds[background];
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
'rounded-lg backdrop-blur-sm transition-all duration-200',
|
|
finalBackground,
|
|
finalBorder,
|
|
finalShadow,
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
Card.displayName = 'Card';
|
|
|
|
interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
|
|
separator?: boolean;
|
|
padding?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(
|
|
({ className, separator = true, padding = 'md', ...props }, ref) => {
|
|
const paddings = {
|
|
sm: 'p-2',
|
|
md: 'p-4',
|
|
lg: 'p-6'
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
paddings[padding],
|
|
separator && 'border-b border-[var(--border)]',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
CardHeader.displayName = 'CardHeader';
|
|
|
|
interface CardTitleProps extends HTMLAttributes<HTMLHeadingElement> {
|
|
size?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
const CardTitle = forwardRef<HTMLHeadingElement, CardTitleProps>(
|
|
({ className, size = 'md', ...props }, ref) => {
|
|
const sizes = {
|
|
sm: 'text-sm',
|
|
md: 'text-base',
|
|
lg: 'text-lg'
|
|
};
|
|
|
|
return (
|
|
<h3
|
|
ref={ref}
|
|
className={cn(
|
|
'font-mono font-semibold text-[var(--foreground)] tracking-wide',
|
|
sizes[size],
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
CardTitle.displayName = 'CardTitle';
|
|
|
|
interface CardContentProps extends HTMLAttributes<HTMLDivElement> {
|
|
padding?: 'sm' | 'md' | 'lg' | 'none';
|
|
}
|
|
|
|
const CardContent = forwardRef<HTMLDivElement, CardContentProps>(
|
|
({ className, padding = 'md', ...props }, ref) => {
|
|
const paddings = {
|
|
none: '',
|
|
sm: 'p-2',
|
|
md: 'p-4',
|
|
lg: 'p-6'
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(paddings[padding], className)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
CardContent.displayName = 'CardContent';
|
|
|
|
interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {
|
|
separator?: boolean;
|
|
padding?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(
|
|
({ className, separator = true, padding = 'md', ...props }, ref) => {
|
|
const paddings = {
|
|
sm: 'p-2',
|
|
md: 'p-4',
|
|
lg: 'p-6'
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
paddings[padding],
|
|
separator && 'border-t border-[var(--border)]',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
);
|
|
|
|
CardFooter.displayName = 'CardFooter';
|
|
|
|
export { Card, CardHeader, CardTitle, CardContent, CardFooter };
|