ADD new frontend
This commit is contained in:
237
frontend/src/components/ui/Card/Card.tsx
Normal file
237
frontend/src/components/ui/Card/Card.tsx
Normal file
@@ -0,0 +1,237 @@
|
||||
import React, { forwardRef, HTMLAttributes } from 'react';
|
||||
import { clsx } from 'clsx';
|
||||
|
||||
export interface CardProps extends HTMLAttributes<HTMLDivElement> {
|
||||
variant?: 'elevated' | 'outlined' | 'filled' | 'ghost';
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
||||
shadow?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
|
||||
hoverable?: boolean;
|
||||
interactive?: boolean;
|
||||
}
|
||||
|
||||
export interface CardHeaderProps extends HTMLAttributes<HTMLDivElement> {
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
divider?: boolean;
|
||||
}
|
||||
|
||||
export interface CardBodyProps extends HTMLAttributes<HTMLDivElement> {
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
}
|
||||
|
||||
export interface CardFooterProps extends HTMLAttributes<HTMLDivElement> {
|
||||
padding?: 'none' | 'sm' | 'md' | 'lg' | 'xl';
|
||||
divider?: boolean;
|
||||
justify?: 'start' | 'end' | 'center' | 'between' | 'around' | 'evenly';
|
||||
}
|
||||
|
||||
const Card = forwardRef<HTMLDivElement, CardProps>(({
|
||||
variant = 'elevated',
|
||||
padding = 'md',
|
||||
rounded = 'md',
|
||||
shadow = 'md',
|
||||
hoverable = false,
|
||||
interactive = false,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}, ref) => {
|
||||
const baseClasses = [
|
||||
'relative',
|
||||
'transition-all duration-200 ease-in-out',
|
||||
'bg-[var(--bg-primary)]',
|
||||
];
|
||||
|
||||
const variantClasses = {
|
||||
elevated: [
|
||||
'border border-[var(--border-primary)]',
|
||||
],
|
||||
outlined: [
|
||||
'border-2 border-[var(--border-primary)]',
|
||||
'bg-transparent',
|
||||
],
|
||||
filled: [
|
||||
'bg-[var(--bg-secondary)]',
|
||||
'border border-transparent',
|
||||
],
|
||||
ghost: [
|
||||
'bg-transparent',
|
||||
'border border-transparent',
|
||||
],
|
||||
};
|
||||
|
||||
const paddingClasses = {
|
||||
none: '',
|
||||
sm: 'p-3',
|
||||
md: 'p-4',
|
||||
lg: 'p-6',
|
||||
xl: 'p-8',
|
||||
};
|
||||
|
||||
const roundedClasses = {
|
||||
none: 'rounded-none',
|
||||
sm: 'rounded-sm',
|
||||
md: 'rounded-lg',
|
||||
lg: 'rounded-xl',
|
||||
xl: 'rounded-2xl',
|
||||
full: 'rounded-full',
|
||||
};
|
||||
|
||||
const shadowClasses = {
|
||||
none: '',
|
||||
sm: 'shadow-sm',
|
||||
md: 'shadow-md',
|
||||
lg: 'shadow-lg',
|
||||
xl: 'shadow-xl',
|
||||
'2xl': 'shadow-2xl',
|
||||
};
|
||||
|
||||
const interactiveClasses = {
|
||||
hoverable: 'hover:shadow-lg hover:-translate-y-1',
|
||||
interactive: 'cursor-pointer hover:shadow-lg hover:-translate-y-1 focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]/20 focus:ring-offset-2',
|
||||
};
|
||||
|
||||
const classes = clsx(
|
||||
baseClasses,
|
||||
variantClasses[variant],
|
||||
paddingClasses[padding],
|
||||
roundedClasses[rounded],
|
||||
shadowClasses[shadow],
|
||||
{
|
||||
[interactiveClasses.hoverable]: hoverable && !interactive,
|
||||
[interactiveClasses.interactive]: interactive,
|
||||
},
|
||||
className
|
||||
);
|
||||
|
||||
const Component = interactive ? 'button' : 'div';
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={ref}
|
||||
className={classes}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
});
|
||||
|
||||
const CardHeader = forwardRef<HTMLDivElement, CardHeaderProps>(({
|
||||
padding = 'md',
|
||||
divider = true,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}, ref) => {
|
||||
const paddingClasses = {
|
||||
none: '',
|
||||
sm: 'p-3',
|
||||
md: 'p-4',
|
||||
lg: 'p-6',
|
||||
xl: 'p-8',
|
||||
};
|
||||
|
||||
const classes = clsx(
|
||||
'flex items-center justify-between',
|
||||
paddingClasses[padding],
|
||||
{
|
||||
'border-b border-[var(--border-primary)]': divider,
|
||||
},
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classes}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const CardBody = forwardRef<HTMLDivElement, CardBodyProps>(({
|
||||
padding = 'md',
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}, ref) => {
|
||||
const paddingClasses = {
|
||||
none: '',
|
||||
sm: 'p-3',
|
||||
md: 'p-4',
|
||||
lg: 'p-6',
|
||||
xl: 'p-8',
|
||||
};
|
||||
|
||||
const classes = clsx(
|
||||
paddingClasses[padding],
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classes}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
const CardFooter = forwardRef<HTMLDivElement, CardFooterProps>(({
|
||||
padding = 'md',
|
||||
divider = true,
|
||||
justify = 'end',
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}, ref) => {
|
||||
const paddingClasses = {
|
||||
none: '',
|
||||
sm: 'p-3',
|
||||
md: 'p-4',
|
||||
lg: 'p-6',
|
||||
xl: 'p-8',
|
||||
};
|
||||
|
||||
const justifyClasses = {
|
||||
start: 'justify-start',
|
||||
end: 'justify-end',
|
||||
center: 'justify-center',
|
||||
between: 'justify-between',
|
||||
around: 'justify-around',
|
||||
evenly: 'justify-evenly',
|
||||
};
|
||||
|
||||
const classes = clsx(
|
||||
'flex items-center gap-3',
|
||||
paddingClasses[padding],
|
||||
justifyClasses[justify],
|
||||
{
|
||||
'border-t border-[var(--border-primary)]': divider,
|
||||
},
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={classes}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Card.displayName = 'Card';
|
||||
CardHeader.displayName = 'CardHeader';
|
||||
CardBody.displayName = 'CardBody';
|
||||
CardFooter.displayName = 'CardFooter';
|
||||
|
||||
export default Card;
|
||||
export { CardHeader, CardBody, CardFooter };
|
||||
3
frontend/src/components/ui/Card/index.ts
Normal file
3
frontend/src/components/ui/Card/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export { default } from './Card';
|
||||
export { default as Card, CardHeader, CardBody, CardFooter } from './Card';
|
||||
export type { CardProps, CardHeaderProps, CardBodyProps, CardFooterProps } from './Card';
|
||||
Reference in New Issue
Block a user