{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card",
  "type": "registry:component",
  "title": "Card",
  "description": "A versatile card component with multiple variants, sizes, and interactive features",
  "dependencies": [
    "iconsax-react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "registry/lagos/ui/card.tsx",
      "content": "\"use client\";\n\nimport React, { FC, ReactNode, forwardRef } from \"react\";\nimport { CloseCircle, MoreCircle } from \"iconsax-react\";\nimport Link from \"next/link\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/registry/lagos/ui/button\";\n\n// Types\nexport type CardVariant =\n  | \"default\"\n  | \"primary\"\n  | \"secondary\"\n  | \"success\"\n  | \"warning\"\n  | \"error\"\n  | \"info\"\n  | \"glass\";\n\nexport type CardSize = \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n\nexport type CardElevation = \"flat\" | \"raised\" | \"floating\" | \"elevated\";\n\nexport type CardBorder =\n  | \"default\"\n  | \"bordered\"\n  | \"dashed\"\n  | \"dotted\"\n  | \"borderless\";\n\nexport interface ActionObject {\n  name: string;\n  path?: string;\n  onClick?: () => void;\n  disabled?: boolean;\n  type?: \"default\" | \"primary\" | \"secondary\" | \"danger\" | \"ghost\" | \"tertiary\";\n  icon?: ReactNode;\n  iconStart?: boolean;\n  external?: boolean;\n  size?: \"sm\" | \"md\" | \"lg\";\n}\n\n// CVA variants for the main card container\nconst cardVariants = cva(\n  \"relative overflow-hidden rounded-3xl border transition-all duration-200 dark:bg-gray-900\",\n  {\n    variants: {\n      variant: {\n        default:\n          \"border-gray-100 bg-white text-gray-800 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-200\",\n        primary:\n          \"border-blue-200 bg-blue-50 text-blue-800 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-200\",\n        secondary:\n          \"border-gray-200 bg-gray-50 text-gray-600 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-200\",\n        success:\n          \"border-green-200 bg-green-50 text-green-800 dark:border-green-800 dark:bg-green-950 dark:text-green-200\",\n        warning:\n          \"border-yellow-200 bg-yellow-50 text-yellow-800 dark:border-yellow-800 dark:bg-yellow-950 dark:text-yellow-200\",\n        error:\n          \"border-red-200 bg-red-50 text-red-800 dark:border-red-800 dark:bg-red-950 dark:text-red-200\",\n        info: \"border-blue-200 bg-blue-50 text-blue-800 dark:border-blue-800 dark:bg-blue-950 dark:text-blue-200\",\n        glass:\n          \"border-white/20 bg-white/10 text-gray-800 backdrop-blur-xl dark:border-gray-700/50 dark:bg-gray-900/10 dark:text-gray-200\",\n      },\n      size: {\n        xs: \"p-3 text-sm\",\n        sm: \"p-4 text-sm\",\n        md: \"p-6 text-base\",\n        lg: \"p-8 text-lg\",\n        xl: \"p-10 text-xl\",\n      },\n      elevation: {\n        flat: \"shadow-none\",\n        raised: \"shadow-sm hover:shadow-md\",\n        floating: \"shadow-lg hover:shadow-xl\",\n        elevated: \"shadow-xl hover:shadow-2xl\",\n      },\n      border: {\n        default: \"\",\n        bordered: \"border-2\",\n        dashed: \"border-2 border-dashed\",\n        dotted: \"border-2 border-dotted\",\n        borderless: \"border-0\",\n      },\n      interactive: {\n        true: \"cursor-pointer transition-all duration-200 hover:scale-[1.02] active:scale-[0.98]\",\n        false: \"\",\n      },\n      hoverable: {\n        true: \"transition-all duration-200 hover:shadow-lg\",\n        false: \"\",\n      },\n      clickable: {\n        true: \"cursor-pointer transition-all duration-200 hover:brightness-105 active:brightness-95\",\n        false: \"\",\n      },\n      loading: {\n        true: \"pointer-events-none opacity-75\",\n        false: \"\",\n      },\n      horizontal: {\n        true: \"flex flex-row items-start gap-4\",\n        false: \"flex flex-col gap-2\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"md\",\n      elevation: \"flat\",\n      border: \"default\",\n      interactive: false,\n      hoverable: false,\n      clickable: false,\n      loading: false,\n      horizontal: false,\n    },\n  }\n);\n\n// CVA variants for card header\nconst cardHeaderVariants = cva(\n  \" border-b  border-gray-100 dark:border-gray-700\",\n  {\n    variants: {\n      borderless: {\n        true: \"border-b-0 pb-0\",\n        false: \"\",\n      },\n      compact: {\n        true: \"mb-0.5 pb-0.5\",\n        false: \"\",\n      },\n    },\n    defaultVariants: {\n      borderless: true,\n      compact: false,\n    },\n  }\n);\n\n// CVA variants for card title\nconst cardTitleVariants = cva(\"font-semibold leading-tight\", {\n  variants: {\n    size: {\n      xs: \"text-sm font-medium\",\n      sm: \"text-base font-medium\",\n      md: \"text-lg\",\n      lg: \"text-xl font-bold\",\n      xl: \"text-2xl font-bold\",\n    },\n  },\n  defaultVariants: {\n    size: \"md\",\n  },\n});\n\n// CVA variants for card subtitle\nconst cardSubtitleVariants = cva(\"opacity-75\", {\n  variants: {\n    size: {\n      xs: \"text-xs\",\n      sm: \"text-sm\",\n      md: \"text-sm\",\n      lg: \"text-base\",\n      xl: \"text-lg\",\n    },\n  },\n  defaultVariants: {\n    size: \"md\",\n  },\n});\n\n// CVA variants for card icon\nconst cardIconVariants = cva(\"flex items-center justify-center rounded-2xl\", {\n  variants: {\n    variant: {\n      default: \"bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400\",\n      primary: \"bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400\",\n      secondary:\n        \"bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400\",\n      success:\n        \"bg-green-100 text-green-600 dark:bg-green-900 dark:text-green-400\",\n      warning:\n        \"bg-yellow-100 text-yellow-600 dark:bg-yellow-900 dark:text-yellow-400\",\n      error: \"bg-red-100 text-red-600 dark:bg-red-900 dark:text-red-400\",\n      info: \"bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-400\",\n      glass: \"bg-white/20 text-gray-600 dark:bg-gray-700/20 dark:text-gray-400\",\n    },\n    size: {\n      xs: \"h-6 w-6 rounded-lg\",\n      sm: \"h-8 w-8 rounded-xl\",\n      md: \"h-12 w-12\",\n      lg: \"h-16 w-16 rounded-3xl\",\n      xl: \"h-20 w-20 rounded-3xl\",\n    },\n  },\n  defaultVariants: {\n    variant: \"default\",\n    size: \"md\",\n  },\n});\n\n// CVA variants for card footer\nconst cardFooterVariants = cva(\n  \"border-t pt-2 border-gray-100 dark:border-gray-700\",\n  {\n    variants: {\n      borderless: {\n        true: \"border-t-0 pt-0\",\n        false: \"\",\n      },\n      alignment: {\n        left: \"flex flex-wrap gap-2\",\n        right: \"flex justify-end gap-2\",\n        center: \"flex justify-center gap-2\",\n        between: \"flex justify-between gap-2\",\n      },\n    },\n    defaultVariants: {\n      borderless: true,\n      alignment: \"left\",\n    },\n  }\n);\n\n// CVA variants for card media\nconst cardMediaVariants = cva(\"overflow-hidden\", {\n  variants: {\n    horizontal: {\n      true: \"w-24 flex-shrink-0 rounded-2xl\",\n      false: \"-m-6 mb-4 rounded-t-3xl\",\n    },\n    size: {\n      xs: \"\",\n      sm: \"\",\n      md: \"\",\n      lg: \"\",\n      xl: \"\",\n    },\n  },\n  compoundVariants: [\n    {\n      horizontal: true,\n      size: \"sm\",\n      className: \"w-16 rounded-xl\",\n    },\n    {\n      horizontal: true,\n      size: \"lg\",\n      className: \"w-32 rounded-3xl\",\n    },\n  ],\n  defaultVariants: {\n    horizontal: false,\n    size: \"md\",\n  },\n});\n\n// CVA variants for progress bar\nconst progressBarVariants = cva(\n  \"absolute left-0 h-1 bg-blue-500 transition-all duration-300\",\n  {\n    variants: {\n      position: {\n        top: \"top-0\",\n        bottom: \"bottom-0\",\n      },\n      thickness: {\n        thin: \"h-0.5\",\n        normal: \"h-1\",\n        thick: \"h-2\",\n      },\n    },\n    defaultVariants: {\n      position: \"bottom\",\n      thickness: \"normal\",\n    },\n  }\n);\n\n// CVA variants for notification dot\nconst notificationVariants = cva(\n  \"absolute -right-1 -top-1 h-3 w-3 rounded-full\",\n  {\n    variants: {\n      variant: {\n        default: \"bg-red-500\",\n        primary: \"bg-blue-500\",\n        success: \"bg-green-500\",\n        warning: \"bg-yellow-500\",\n      },\n      size: {\n        small: \"h-2 w-2\",\n        normal: \"h-3 w-3\",\n        large: \"h-4 w-4\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      size: \"normal\",\n    },\n  }\n);\n\nexport interface CardProps\n  extends Omit<React.HTMLAttributes<HTMLDivElement>, \"title\">,\n    VariantProps<typeof cardVariants> {\n  // Content\n  title?: string | ReactNode;\n  subtitle?: string | ReactNode;\n  children?: ReactNode;\n  icon?: ReactNode;\n  media?: ReactNode;\n  badge?: ReactNode;\n  badges?: Array<ReactNode>;\n\n  // Actions\n  actions?: Array<ActionObject | ReactNode>;\n  primaryAction?: ActionObject | ReactNode;\n  onClose?: () => void;\n  onMore?: () => void;\n\n  // Interactions\n  onClick?: () => void;\n\n  // States\n  collapsed?: boolean;\n\n  // Header/Footer\n  headerDirection?: \"row\" | \"col\";\n  headerBorderless?: boolean;\n  footerBorderless?: boolean;\n  footerAlignment?: \"left\" | \"right\" | \"center\" | \"between\";\n\n  // Accessibility\n  role?: string;\n  tabIndex?: number;\n\n  // Progress\n  progress?: number;\n  progressPosition?: \"top\" | \"bottom\";\n  progressThickness?: \"thin\" | \"normal\" | \"thick\";\n\n  // Notification\n  notification?: boolean;\n  notificationVariant?: \"default\" | \"primary\" | \"success\" | \"warning\";\n  notificationSize?: \"small\" | \"normal\" | \"large\";\n\n  // Link functionality\n  href?: string;\n  external?: boolean;\n}\n\n// Type guard for ActionObject\nconst isActionObject = (action: unknown): action is ActionObject => {\n  return (\n    typeof action === \"object\" &&\n    action !== null &&\n    !React.isValidElement(action) &&\n    \"name\" in (action as never)\n  );\n};\n\n// Card Component\nconst Card = forwardRef<HTMLDivElement, CardProps>(\n  (\n    {\n      title,\n      subtitle,\n      children,\n      icon,\n      media,\n      badge,\n      badges,\n      variant = \"default\",\n      size = \"md\",\n      elevation = \"flat\",\n      border = \"default\",\n      horizontal = false,\n      className,\n      actions,\n      primaryAction,\n      onClose,\n      onMore,\n      interactive = false,\n      hoverable = false,\n      clickable = false,\n      onClick,\n      loading = false,\n      collapsed = false,\n      headerDirection = \"row\",\n      headerBorderless = true,\n      footerBorderless = true,\n      footerAlignment = \"left\",\n      role,\n      tabIndex,\n      progress,\n      progressPosition = \"bottom\",\n      progressThickness = \"normal\",\n      notification = false,\n      notificationVariant = \"default\",\n      notificationSize = \"normal\",\n      href,\n      external = false,\n      ...props\n    },\n    ref\n  ) => {\n    const getActionSize = (): \"sm\" | \"md\" | \"lg\" => {\n      switch (size) {\n        case \"xs\":\n        case \"sm\":\n          return \"sm\";\n        case \"lg\":\n        case \"xl\":\n          return \"lg\";\n        default:\n          return \"md\";\n      }\n    };\n\n    const getActionVariant = (actionType: string) => {\n      switch (actionType) {\n        case \"default\":\n          return \"primary\";\n        case \"primary\":\n          return \"primary\";\n        case \"secondary\":\n          return \"secondary\";\n        case \"tertiary\":\n          return \"tertiary\";\n        case \"ghost\":\n          return \"ghost\";\n        case \"danger\":\n          return \"danger\";\n        default:\n          return \"primary\";\n      }\n    };\n\n    // Render action\n    const renderAction = (action: ActionObject, index: number) => {\n      const variant = getActionVariant(action.type || \"default\");\n      const buttonSize = action.size || getActionSize();\n\n      const content = (\n        <>\n          {action.icon &&\n            action.iconStart &&\n            // <span className=\"icon\">{action.icon}</span>\n            action.icon}\n          <span>{action.name}</span>\n          {action.icon &&\n            !action.iconStart &&\n            // <span className=\"icon\">{action.icon}</span>\n            // add the \"icon\" class to the action.icon directly instead of wrapping within a span\n            action.icon}\n        </>\n      );\n\n      // If path exists, render Link with Button\n      if (action.path) {\n        if (action.external) {\n          return (\n            <Button\n              key={index}\n              asChild\n              variant={variant}\n              size={buttonSize}\n              disabled={action.disabled}\n            >\n              <a href={action.path} target=\"_blank\" rel=\"noopener noreferrer\">\n                {content}\n              </a>\n            </Button>\n          );\n        } else {\n          return (\n            <Button\n              key={index}\n              asChild\n              variant={variant}\n              size={buttonSize}\n              disabled={action.disabled}\n            >\n              <Link href={action.path}>{content}</Link>\n            </Button>\n          );\n        }\n      }\n\n      // Otherwise render Button with onClick\n      return (\n        <Button\n          key={index}\n          variant={variant}\n          size={buttonSize}\n          onClick={action.onClick}\n          disabled={action.disabled}\n        >\n          {content}\n        </Button>\n      );\n    };\n\n    const renderActionItem = (\n      action: ActionObject | ReactNode,\n      index: number\n    ) => {\n      if (isActionObject(action)) {\n        return renderAction(action, index);\n      }\n      return <React.Fragment key={index}>{action}</React.Fragment>;\n    };\n\n    const renderPrimaryAction = (action: ActionObject | ReactNode) => {\n      if (isActionObject(action)) {\n        return renderAction(action, 0);\n      }\n      return <React.Fragment>{action}</React.Fragment>;\n    };\n\n    // Card content\n    const cardContent = (\n      <div\n        ref={ref}\n        className={cn(\n          cardVariants({\n            variant,\n            size,\n            elevation,\n            border,\n            interactive,\n            hoverable,\n            clickable,\n            loading,\n            horizontal,\n          }),\n          className\n        )}\n        onClick={onClick}\n        role={role}\n        tabIndex={tabIndex}\n        {...props}\n      >\n        {/* Progress Bar */}\n        {progress !== undefined && (\n          <div\n            className={progressBarVariants({\n              position: progressPosition,\n              thickness: progressThickness,\n            })}\n            style={{ width: `${Math.max(0, Math.min(100, progress))}%` }}\n          />\n        )}\n\n        {/* Notification Dot */}\n        {notification && (\n          <div\n            className={notificationVariants({\n              variant: notificationVariant,\n              size: notificationSize,\n            })}\n          />\n        )}\n\n        {/* Badges */}\n        {badges && badges.length > 0 ? (\n          <div className=\"absolute right-3 top-3 z-10 flex flex-wrap justify-end gap-2\">\n            {badges.map((badge, index) => (\n              <div key={index}>{badge}</div>\n            ))}\n          </div>\n        ) : (\n          badge && <div className=\"absolute right-3 top-3 z-10\">{badge}</div>\n        )}\n\n        {/* Close/More Actions */}\n        {(onClose || onMore) && (\n          <div className=\"absolute right-3 top-3 z-10 flex gap-1\">\n            {onMore && (\n              <Button\n                onClick={onMore}\n                variant=\"ghost\"\n                size=\"sm\"\n                className=\"h-8 w-8 p-0\"\n                aria-label=\"More options\"\n              >\n                <MoreCircle className=\"h-4 w-4\" />\n              </Button>\n            )}\n            {onClose && (\n              <Button\n                onClick={onClose}\n                variant=\"ghost\"\n                size=\"sm\"\n                className=\"h-8 w-8 p-0\"\n                aria-label=\"Close\"\n              >\n                <CloseCircle className=\"h-4 w-4\" />\n              </Button>\n            )}\n          </div>\n        )}\n\n        {/* Media for horizontal layout */}\n        {media && horizontal && (\n          <div className={cardMediaVariants({ horizontal: true, size })}>\n            {typeof media === \"string\" ? (\n              <img src={media} alt=\"\" className=\"h-full w-full object-cover\" />\n            ) : (\n              media\n            )}\n          </div>\n        )}\n\n        {/* Main Content Container */}\n        <div className=\"flex h-full flex-1 flex-col gap-2\">\n          {/* Media for vertical layout */}\n          {media && !horizontal && (\n            <div className={cardMediaVariants({ horizontal: false })}>\n              {typeof media === \"string\" ? (\n                <img\n                  src={media}\n                  alt=\"\"\n                  className=\"h-full w-full object-cover\"\n                />\n              ) : (\n                media\n              )}\n            </div>\n          )}\n\n          {/* Header */}\n          {(title || subtitle || icon) && (\n            <div\n              className={cardHeaderVariants({\n                borderless: headerBorderless,\n              })}\n            >\n              <div\n                className={`flex items-start gap-3 ${\n                  headerDirection === \"row\" ? \"flex-row\" : \"flex-col\"\n                }`}\n              >\n                {icon && (\n                  <div className={cardIconVariants({ variant, size })}>\n                    {icon}\n                  </div>\n                )}\n\n                <div className=\"flex-1\">\n                  {title && (\n                    <h3 className={cardTitleVariants({ size })}>{title}</h3>\n                  )}\n                  {subtitle && (\n                    <p className={cardSubtitleVariants({ size })}>{subtitle}</p>\n                  )}\n                </div>\n              </div>\n            </div>\n          )}\n\n          {/* Content */}\n          {children && (\n            <div\n              className={cn(\n                \"space-y-4\",\n                collapsed &&\n                  \"max-h-0 overflow-hidden opacity-0 transition-all duration-300 ease-in-out\",\n                !collapsed &&\n                  \"opacity-100 transition-all duration-300 ease-in-out\"\n              )}\n            >\n              {children}\n            </div>\n          )}\n\n          {/* Primary Action */}\n          {primaryAction && (\n            <div className=\"mt-4\">{renderPrimaryAction(primaryAction)}</div>\n          )}\n\n          {/* Footer with Actions */}\n          {actions && actions.length > 0 && (\n            <div\n              className={cn(\n                cardFooterVariants({\n                  borderless: footerBorderless,\n                  alignment: footerAlignment,\n                }),\n                \"mt-auto\"\n              )}\n            >\n              {actions.map((action, index) => renderActionItem(action, index))}\n            </div>\n          )}\n        </div>\n\n        {/* Loading Overlay */}\n        {loading && (\n          <div className=\"absolute inset-0 z-20 flex items-center justify-center bg-black/50 opacity-100\">\n            <div className=\"flex items-center gap-2 rounded-lg bg-white px-3 py-2 text-sm font-medium dark:bg-gray-800\">\n              <div className=\"h-4 w-4 animate-spin rounded-full border-2 border-blue-500 border-t-transparent\"></div>\n              Loading...\n            </div>\n          </div>\n        )}\n      </div>\n    );\n\n    // Wrap with Link if href is provided\n    if (href) {\n      if (external) {\n        return (\n          <a\n            href={href}\n            target=\"_blank\"\n            rel=\"noopener noreferrer\"\n            className=\"block focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-3xl\"\n          >\n            {cardContent}\n          </a>\n        );\n      } else {\n        return (\n          <Link\n            href={href}\n            className=\"block focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 rounded-3xl\"\n          >\n            {cardContent}\n          </Link>\n        );\n      }\n    }\n\n    return cardContent;\n  }\n);\n\nCard.displayName = \"Card\";\n\n// Additional utility components for card layouts\nexport const CardGrid: FC<{\n  children: ReactNode;\n  cols?: 1 | 2 | 3 | 4;\n  spacing?: \"dense\" | \"normal\" | \"loose\";\n  className?: string;\n}> = ({ children, cols = 3, spacing = \"normal\", className }) => {\n  const gridClasses = cn(\n    \"grid\",\n    {\n      \"grid-cols-1\": cols === 1,\n      \"grid-cols-1 md:grid-cols-2\": cols === 2,\n      \"grid-cols-1 md:grid-cols-2 lg:grid-cols-3\": cols === 3,\n      \"grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4\": cols === 4,\n    },\n    {\n      \"gap-4\": spacing === \"dense\",\n      \"gap-6\": spacing === \"normal\",\n      \"gap-8\": spacing === \"loose\",\n    },\n    className\n  );\n\n  return <div className={gridClasses}>{children}</div>;\n};\n\nexport const CardList: FC<{\n  children: ReactNode;\n  spacing?: \"compact\" | \"normal\" | \"loose\";\n  className?: string;\n}> = ({ children, spacing = \"normal\", className }) => {\n  const listClasses = cn(\n    {\n      \"space-y-2\": spacing === \"compact\",\n      \"space-y-4\": spacing === \"normal\",\n      \"space-y-6\": spacing === \"loose\",\n    },\n    className\n  );\n\n  return <div className={listClasses}>{children}</div>;\n};\n\nexport const CardSkeleton: FC<{\n  size?: CardSize;\n  showIcon?: boolean;\n  lines?: number;\n}> = ({ size = \"md\", showIcon = false, lines = 3 }) => {\n  return (\n    <div className={cardVariants({ size, className: \"animate-pulse\" })}>\n      <div className=\"flex items-start gap-3\">\n        {showIcon && (\n          <div\n            className={cn(\n              \"rounded-full bg-gray-200 dark:bg-gray-700\",\n              size === \"sm\" ? \"h-8 w-8\" : \"h-12 w-12\"\n            )}\n          />\n        )}\n        <div className=\"flex-1 space-y-2\">\n          <div className=\"h-4 bg-gray-200 rounded dark:bg-gray-700 w-2/3\" />\n          <div className=\"h-3 bg-gray-200 rounded dark:bg-gray-700 w-1/2\" />\n        </div>\n      </div>\n      <div className=\"space-y-2 mt-4\">\n        {Array.from({ length: lines }).map((_, i) => (\n          <div\n            key={i}\n            className={cn(\n              \"h-3 bg-gray-200 rounded dark:bg-gray-700\",\n              i === lines - 1 ? \"w-3/4\" : \"w-full\"\n            )}\n          />\n        ))}\n      </div>\n    </div>\n  );\n};\n\nexport { Card, cardVariants };\n",
      "type": "registry:component",
      "target": "components/ui/aevr/card.tsx"
    }
  ]
}