2026-01-14 16:30:39 +01:00

77 lines
2.0 KiB
TypeScript

import type { ReactNode } from 'react'
export type CardVariant = 'default' | 'interactive' | 'selected' | 'compact'
interface CardProps {
children: ReactNode
variant?: CardVariant
className?: string
onClick?: () => void
'aria-label'?: string
role?: string
}
function getVariantClasses(variant: CardVariant, hasOnClick: boolean): string {
const baseClasses = 'border rounded-lg bg-cyber-dark'
switch (variant) {
case 'default':
return `${baseClasses} border-neon-cyan/30`
case 'interactive':
return `${baseClasses} border-neon-cyan/30 hover:border-neon-cyan/50 hover:shadow-glow-cyan transition-all ${hasOnClick ? 'cursor-pointer' : ''}`
case 'selected':
return `${baseClasses} border-neon-cyan ring-1 ring-neon-cyan/50 shadow-glow-cyan`
case 'compact':
return `${baseClasses} border-neon-cyan/30 p-4`
default:
return `${baseClasses} border-neon-cyan/30`
}
}
function getPaddingClasses(variant: CardVariant): string {
if (variant === 'compact') {
return 'p-4'
}
return 'p-6'
}
export function Card({
children,
variant = 'default',
className = '',
onClick,
'aria-label': ariaLabel,
role: roleProp,
}: CardProps): React.ReactElement {
const variantClasses = getVariantClasses(variant, onClick !== undefined)
const paddingClasses = getPaddingClasses(variant)
const combinedClasses = `${variantClasses} ${paddingClasses} ${className}`.trim()
const role = roleProp ?? (onClick !== undefined ? 'button' : undefined)
if (onClick) {
return (
<div
onClick={onClick}
className={combinedClasses}
role={role}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onClick()
}
}}
aria-label={ariaLabel}
>
{children}
</div>
)
}
return (
<div className={combinedClasses} role={role} aria-label={ariaLabel}>
{children}
</div>
)
}