File size: 1,863 Bytes
b64de39
 
 
 
4995d62
 
b64de39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4995d62
b64de39
 
4995d62
 
b64de39
4995d62
b64de39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
/**
 * Card - Container card with variant support.
 *
 * Variants: default | bordered | elevated | flat
 * Optional header, footer, and hover-lift effect with smooth
 * transform animation on hover.
 */

import PropTypes from "prop-types";

const VARIANT_CLASSES = {
  default: "bg-white shadow-card border border-neutral-200",
  bordered: "bg-white border-2 border-neutral-300",
  elevated: "bg-white shadow-card-hover",
  flat: "bg-neutral-100",
};

function Card({
  children,
  variant = "default",
  header,
  footer,
  hoverable = false,
  padding = true,
  className = "",
  onClick,
  ...rest
}) {
  const isClickable = Boolean(onClick);
  const shouldLift = hoverable || isClickable;

  const classes = [
    "rounded-xl overflow-hidden",
    "transition-all duration-200 ease-out",
    VARIANT_CLASSES[variant] || VARIANT_CLASSES.default,
    shouldLift ? "hover-lift" : "",
    isClickable ? "cursor-pointer" : "",
    className,
  ]
    .filter(Boolean)
    .join(" ");

  const Tag = isClickable ? "button" : "div";

  return (
    <Tag
      className={classes}
      onClick={onClick}
      role={isClickable ? "button" : undefined}
      tabIndex={isClickable ? 0 : undefined}
      {...rest}
    >
      {header && (
        <div className="border-b border-neutral-200 px-5 py-4">{header}</div>
      )}
      <div className={padding ? "p-5" : ""}>{children}</div>
      {footer && (
        <div className="border-t border-neutral-200 px-5 py-3 bg-neutral-50">
          {footer}
        </div>
      )}
    </Tag>
  );
}

Card.propTypes = {
  children: PropTypes.node.isRequired,
  variant: PropTypes.oneOf(["default", "bordered", "elevated", "flat"]),
  header: PropTypes.node,
  footer: PropTypes.node,
  hoverable: PropTypes.bool,
  padding: PropTypes.bool,
  className: PropTypes.string,
  onClick: PropTypes.func,
};

export default Card;