mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-20 13:32:00 +00:00
149 lines
3.6 KiB
TypeScript
149 lines
3.6 KiB
TypeScript
'use client';
|
|
|
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
|
|
import { cn } from '@/lib/helper';
|
|
|
|
export interface CardProps
|
|
extends Omit<HTMLAttributes<HTMLDivElement>, 'className'> {
|
|
title?: string;
|
|
subtitle?: string;
|
|
image?: string;
|
|
imageAlt?: string;
|
|
actions?: ReactNode;
|
|
footer?: ReactNode;
|
|
className?: {
|
|
wrapper?: string;
|
|
image?: string;
|
|
body?: string;
|
|
title?: string;
|
|
subtitle?: string;
|
|
actions?: string;
|
|
footer?: string;
|
|
};
|
|
variant?: 'default' | 'compact' | 'bordered' | 'shadow' | 'image-full';
|
|
size?: 'sm' | 'md' | 'lg';
|
|
}
|
|
|
|
const Card = ({
|
|
title,
|
|
subtitle,
|
|
image,
|
|
imageAlt,
|
|
actions,
|
|
footer,
|
|
className,
|
|
variant = 'default',
|
|
size = 'md',
|
|
children,
|
|
...props
|
|
}: CardProps) => {
|
|
const getCardClasses = () => {
|
|
const baseClasses = 'card bg-base-100';
|
|
|
|
const variantClasses = {
|
|
default: '',
|
|
compact: 'card-compact',
|
|
bordered: 'border border-base-300',
|
|
shadow: 'shadow-xl',
|
|
'image-full': 'card-side card-compact shadow-xl',
|
|
};
|
|
|
|
const sizeClasses = {
|
|
sm: 'w-64',
|
|
md: 'w-96',
|
|
lg: 'w-[28rem]',
|
|
};
|
|
|
|
return cn(
|
|
baseClasses,
|
|
variantClasses[variant],
|
|
variant !== 'image-full' ? sizeClasses[size] : '',
|
|
className?.wrapper
|
|
);
|
|
};
|
|
|
|
const getImageClasses = () => {
|
|
if (variant === 'image-full') {
|
|
return cn('w-32 h-32 object-cover', className?.image);
|
|
}
|
|
return cn('h-48 object-cover', className?.image);
|
|
};
|
|
|
|
const getBodyClasses = () => {
|
|
const baseClasses = 'card-body';
|
|
|
|
if (variant === 'compact' || variant === 'image-full') {
|
|
return cn(baseClasses, 'p-4', className?.body);
|
|
}
|
|
|
|
return cn(baseClasses, 'p-6', className?.body);
|
|
};
|
|
|
|
const getTitleClasses = () => {
|
|
const sizeClasses = {
|
|
sm: 'text-lg',
|
|
md: 'text-xl',
|
|
lg: 'text-2xl',
|
|
};
|
|
|
|
return cn('card-title font-bold', sizeClasses[size], className?.title);
|
|
};
|
|
|
|
const getSubtitleClasses = () => {
|
|
return cn('text-base-content/70 text-sm mt-1', className?.subtitle);
|
|
};
|
|
|
|
const getActionsClasses = () => {
|
|
return cn('card-actions justify-end mt-4', className?.actions);
|
|
};
|
|
|
|
const getFooterClasses = () => {
|
|
return cn('border-t border-base-300 mt-4 pt-4', className?.footer);
|
|
};
|
|
|
|
if (variant === 'image-full' && image) {
|
|
return (
|
|
<div className={getCardClasses()} {...props}>
|
|
<figure>
|
|
<img
|
|
src={image}
|
|
alt={imageAlt || title || 'Card image'}
|
|
className={getImageClasses()}
|
|
/>
|
|
</figure>
|
|
<div className={getBodyClasses()}>
|
|
{title && <h2 className={getTitleClasses()}>{title}</h2>}
|
|
{subtitle && <p className={getSubtitleClasses()}>{subtitle}</p>}
|
|
{children}
|
|
{actions && <div className={getActionsClasses()}>{actions}</div>}
|
|
</div>
|
|
{footer && <div className={getFooterClasses()}>{footer}</div>}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className={getCardClasses()} {...props}>
|
|
{image && (
|
|
<figure>
|
|
<img
|
|
src={image}
|
|
alt={imageAlt || title || 'Card image'}
|
|
className={getImageClasses()}
|
|
/>
|
|
</figure>
|
|
)}
|
|
<div className={getBodyClasses()}>
|
|
{title && <h2 className={getTitleClasses()}>{title}</h2>}
|
|
{subtitle && <p className={getSubtitleClasses()}>{subtitle}</p>}
|
|
{children}
|
|
{actions && <div className={getActionsClasses()}>{actions}</div>}
|
|
</div>
|
|
{footer && <div className={getFooterClasses()}>{footer}</div>}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Card;
|