{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"card","type":"registry:ui","title":"Card","description":"A container that groups related content and actions — from simple panels to image-rich product, article and profile cards.","dependencies":[],"registryDependencies":["https://dashral.com/r/utils.json"],"files":[{"path":"registry/dashral/card.tsx","type":"registry:file","target":"components/dashral/card.tsx","content":"import * as React from \"react\"\n\nimport { cn } from \"./lib/utils\"\n\ntype CardVariant = \"default\" | \"soft\" | \"shadow\" | \"inset\" | \"panel\" | \"bordered\"\n\nconst variants: Record<CardVariant, string> = {\n  // Flat: an edge, no shadow. Depth is the shadow variant's job.\n  default: \"border\",\n  // No edge or shadow: a tinted panel. The transparent border keeps the content where the other variants put it.\n  soft: \"border border-transparent bg-muted\",\n  // Shadows barely show on dark surfaces, so a faint ring keeps the edge visible.\n  shadow: \"border border-transparent shadow-lg ring-1 ring-black/5 dark:shadow-black/40 dark:ring-white/10\",\n  // A tinted frame: the header and footer sit on it, the content on a panel set in by 6px (see below).\n  inset: \"border bg-muted/60 dark:bg-muted/40\",\n  // The same frame, with the content on a panel flush with the card's edge wherever no header or footer sits (see below).\n  panel: \"border bg-muted/60 dark:bg-muted/40\",\n  // The old name, from before soft replaced its heavy 2px edge.\n  bordered: \"border border-transparent bg-muted\",\n}\n\ntype CardProps = Omit<React.ComponentProps<\"div\">, \"title\"> & {\n  /**\n   * default: an edge; soft: a tinted panel, no edge; shadow: lifted off the page; inset: the header on a tinted frame\n   * and the content on a panel set into it; panel: the same, the panel flush with the card's sides (and its top or\n   * bottom when nothing sits there), for a chart, a table or a list. (\"bordered\" is deprecated: it looks like soft.)\n   */\n  variant?: CardVariant\n  title?: React.ReactNode\n  description?: React.ReactNode\n  /** Above the title, e.g. a badge or a category. */\n  eyebrow?: React.ReactNode\n  /** At the end of the header, e.g. a menu button. */\n  action?: React.ReactNode\n  /** An image (or anything) flush with the card's edge: on top, or at the start when horizontal. */\n  media?: React.ReactNode\n  /** horizontal puts the media beside the content from the sm breakpoint. */\n  orientation?: \"vertical\" | \"horizontal\"\n  /** Under the content, e.g. buttons. */\n  footer?: React.ReactNode\n  /** A line between the content and the footer. */\n  footerDivider?: boolean\n  /** none drops the padding around the content, for a layout of your own (an image filling the card). */\n  padding?: \"default\" | \"none\"\n  classNames?: {\n    media?: string\n    /** The column holding the header, content and footer: its padding and gap, e.g. \"gap-3 py-5\" for a tighter card. */\n    section?: string\n    header?: string\n    eyebrow?: string\n    title?: string\n    description?: string\n    action?: string\n    body?: string\n    footer?: string\n  }\n}\n\n/**\n * A surface for related content, in one tag: a header (eyebrow, title, description, action), the content as children,\n * and a footer. media puts an image flush with the edge, on top or beside.\n */\nfunction Card({\n  variant = \"default\",\n  title,\n  description,\n  eyebrow,\n  action,\n  media,\n  orientation = \"vertical\",\n  footer,\n  footerDivider = false,\n  padding = \"default\",\n  className,\n  classNames,\n  children,\n  ...props\n}: CardProps) {\n  const header = title || description || eyebrow || action\n  const padded = padding === \"default\"\n  // inset and panel share the frame: the header and footer on the tint, the content on a panel.\n  const framed = variant === \"inset\" || variant === \"panel\"\n  const flush = variant === \"panel\"\n\n  return (\n    <div\n      data-slot=\"card\"\n      data-variant={variant}\n      className={cn(\n        \"flex flex-col overflow-hidden rounded-xl bg-card text-card-foreground\",\n        orientation === \"horizontal\" && \"sm:flex-row\",\n        variants[variant],\n        className\n      )}\n      {...props}\n    >\n      {media && (\n        <div\n          data-slot=\"card-media\"\n          className={cn(\n            \"shrink-0 [&>img]:w-full [&>img]:object-cover\",\n            orientation === \"horizontal\" && \"sm:w-56 sm:[&>img]:h-full\",\n            classNames?.media\n          )}\n        >\n          {media}\n        </div>\n      )}\n      <div\n        data-slot=\"card-section\"\n        className={cn(\n          \"flex min-w-0 flex-1 flex-col\",\n          // A footer under a line sits close to it: 12px above and below its actions, like a toolbar.\n          padded && !framed && (footer && footerDivider ? \"gap-6 pt-6 pb-3\" : \"gap-6 py-6\"),\n          classNames?.section\n        )}\n      >\n        {header && (\n          <div\n            data-slot=\"card-header\"\n            className={cn(\"grid items-start gap-1.5\", padded && (framed ? \"px-4 py-3\" : \"px-6\"), framed && action && \"items-center\", action && \"grid-cols-[1fr_auto]\", classNames?.header)}\n          >\n            <div className=\"grid min-w-0 gap-1.5\">\n              {eyebrow && <div className={cn(\"flex\", classNames?.eyebrow)}>{eyebrow}</div>}\n              {title && (\n                <div data-slot=\"card-title\" className={cn(\"font-heading leading-none font-medium tracking-[-0.01em]\", classNames?.title)}>\n                  {title}\n                </div>\n              )}\n              {description && (\n                <div data-slot=\"card-description\" className={cn(\"text-sm text-muted-foreground\", classNames?.description)}>\n                  {description}\n                </div>\n              )}\n            </div>\n            {action && <div className={cn(\"self-start\", classNames?.action)}>{action}</div>}\n          </div>\n        )}\n        {children !== undefined && children !== null && children !== false && (\n          <div\n            data-slot=\"card-content\"\n            className={cn(\n              \"min-w-0 flex-1\",\n              // inset: a borderless panel 4px in from the frame's sides (and top or bottom when nothing sits there), its\n              // corners following the frame's (its radius less 1px border + 3px).\n              variant === \"inset\" && [\"mx-[3px] overflow-hidden rounded-[max(0px,calc(var(--radius-xl)-4px))] bg-card text-card-foreground shadow-xs\", !header && \"mt-[3px]\", !footer && \"mb-[3px]\"],\n              // panel: on the frame's own edge (-1px), so the two borders are one line, with the frame's corners.\n              flush && [\"-mx-px overflow-hidden rounded-xl border bg-card text-card-foreground\", !header && \"-mt-px\", !footer && \"-mb-px\"],\n              framed ? padded && \"p-4\" : padded && \"px-6\",\n              classNames?.body\n            )}\n          >\n            {children}\n          </div>\n        )}\n        {footer && (\n          <div\n            data-slot=\"card-footer\"\n            className={cn(\"flex items-center gap-2\", padded && (framed ? \"px-4 py-3\" : \"px-6\"), footerDivider && !framed && \"border-t border-divider pt-3\", classNames?.footer)}\n          >\n            {footer}\n          </div>\n        )}\n      </div>\n    </div>\n  )\n}\n\nexport { Card, type CardProps, type CardVariant }\n"}],"cssVars":{"theme":{"font-heading":"var(--font-geist, \"Geist\"), var(--font-inter, \"Inter\"), var(--font-arabic, \"IBM Plex Sans Arabic\"), ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif"},"light":{},"dark":{}}}