{"name":"card","type":"registry:component","title":"Card","description":"A card component built with Lit and styled using Tailwind CSS. Includes subcomponents for header, title, description, action, content, and footer.","categories":["ui","card","web-component"],"author":"Lloyd Richards <lloyd.d.richards@gmail.com>","registryDependencies":["@lit/button"],"dependencies":[],"files":[{"path":"registry/ui/card/card.ts","type":"registry:ui","content":"import { css, html, LitElement } from \"lit\";\nimport { customElement } from \"lit/decorators.js\";\nimport { TW } from \"@/lib/tailwindMixin\";\nimport { cn } from \"@/lib/utils\";\n\n@customElement(\"ui-card\")\nexport class Card extends TW(LitElement) {\n  static styles = css`\n    :host {\n      display: block;\n    }\n  `;\n\n  override render() {\n    return html`\n      <div\n        data-slot=\"card\"\n        class=${cn(\n          \"bg-card text-card-foreground flex flex-col gap-6 rounded-xl border border-border py-6 shadow-sm\",\n          this.className,\n        )}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-header\")\nexport class CardHeader extends TW(LitElement) {\n  override render() {\n    return html`\n      <div\n        data-slot=\"card-header\"\n        class=${cn(\n          \"@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-2 px-6 has-[*[data-slot=card-action]]:grid-cols-[1fr_auto] [.border-b]:pb-6\",\n          this.className,\n        )}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-title\")\nexport class CardTitle extends TW(LitElement) {\n  override render() {\n    return html`\n      <div\n        data-slot=\"card-title\"\n        class=${cn(\"leading-none font-semibold\", this.className)}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-description\")\nexport class CardDescription extends TW(LitElement) {\n  override render() {\n    return html`\n      <div\n        data-slot=\"card-description\"\n        class=${cn(\"text-muted-foreground text-sm\", this.className)}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-action\")\nexport class CardAction extends TW(LitElement) {\n  override render() {\n    return html`\n      <div\n        data-slot=\"card-action\"\n        class=${cn(\n          \"col-start-2 row-span-2 row-start-1 self-start justify-self-end\",\n          this.className,\n        )}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-content\")\nexport class CardContent extends TW(LitElement) {\n  override render() {\n    return html`\n      <div data-slot=\"card-content\" class=${cn(\"px-6\", this.className)}>\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\n@customElement(\"ui-card-footer\")\nexport class CardFooter extends TW(LitElement) {\n  override render() {\n    return html`\n      <div\n        data-slot=\"card-footer\"\n        class=${cn(\"flex items-center px-6 [.border-t]:pt-6\", this.className)}\n      >\n        <slot></slot>\n      </div>\n    `;\n  }\n}\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    \"ui-card\": Card;\n    \"ui-card-header\": CardHeader;\n    \"ui-card-title\": CardTitle;\n    \"ui-card-description\": CardDescription;\n    \"ui-card-action\": CardAction;\n    \"ui-card-content\": CardContent;\n    \"ui-card-footer\": CardFooter;\n  }\n}\n"},{"path":"registry/ui/card/card.stories.ts","type":"registry:ui","content":"import \"./card\";\nimport \"../button/button\";\nimport type { Meta, StoryObj } from \"@storybook/web-components-vite\";\nimport { html } from \"lit\";\nimport { unsafeSVG } from \"lit/directives/unsafe-svg.js\";\nimport { BellRing } from \"lucide-static\";\n\nconst notifications = [\n  {\n    title: \"Your call has been confirmed.\",\n    description: \"1 hour ago\",\n  },\n  {\n    title: \"You have a new message!\",\n    description: \"1 hour ago\",\n  },\n  {\n    title: \"Your subscription is expiring soon!\",\n    description: \"2 hours ago\",\n  },\n];\n\n/**\n * Displays a card with header, content, and footer.\n */\nconst meta: Meta = {\n  title: \"ui/Card\",\n  component: \"ui-card\",\n  tags: [\"autodocs\"],\n  argTypes: {},\n  parameters: {\n    layout: \"centered\",\n  },\n};\n\nexport default meta;\n\ntype Story = StoryObj;\n\n/**\n * The default form of the card.\n */\nexport const Default: Story = {\n  render: () => html`\n    <ui-card class=\"w-96\">\n      <ui-card-header>\n        <ui-card-title>Notifications</ui-card-title>\n        <ui-card-description>You have 3 unread messages.</ui-card-description>\n      </ui-card-header>\n      <ui-card-content class=\"grid gap-4\">\n        ${notifications.map(\n          (notification) => html`\n            <div class=\"flex items-center gap-4\">\n              <div class=\"size-6\">${unsafeSVG(BellRing)}</div>\n              <div>\n                <p>${notification.title}</p>\n                <p class=\"text-foreground/60\">${notification.description}</p>\n              </div>\n            </div>\n          `,\n        )}\n      </ui-card-content>\n      <ui-card-footer>\n        <ui-button variant=\"link\">Close</ui-button>\n      </ui-card-footer>\n    </ui-card>\n  `,\n};\n\n/**\n * Use the `CardAction` component to add interactive elements in the header.\n */\nexport const WithCardAction: Story = {\n  render: () => html`\n    <ui-card class=\"w-96\">\n      <ui-card-header>\n        <ui-card-title>Team Settings</ui-card-title>\n        <ui-card-description>Manage your team preferences</ui-card-description>\n        <ui-card-action>\n          <ui-button size=\"sm\" variant=\"outline\">Edit</ui-button>\n        </ui-card-action>\n      </ui-card-header>\n      <ui-card-content>\n        <p>Configure team members, permissions, and notifications.</p>\n      </ui-card-content>\n      <ui-card-footer>\n        <ui-button variant=\"ghost\">Cancel</ui-button>\n        <ui-button class=\"ml-auto\">Save Changes</ui-button>\n      </ui-card-footer>\n    </ui-card>\n  `,\n};\n\n/**\n * A minimal card with only content, no header or footer.\n */\nexport const MinimalCard: Story = {\n  render: () => html`\n    <ui-card class=\"w-96\">\n      <ui-card-content>\n        <p class=\"text-sm\">\n          This is a minimal card with only content. Perfect for displaying\n          simple information without the need for a header or footer.\n        </p>\n      </ui-card-content>\n    </ui-card>\n  `,\n};\n\n/**\n * A card with only a header section, no content or footer.\n */\nexport const HeaderOnly: Story = {\n  render: () => html`\n    <ui-card class=\"w-96\">\n      <ui-card-header>\n        <ui-card-title>Quick Stats</ui-card-title>\n        <ui-card-description>\n          Your account summary at a glance. Click for details.\n        </ui-card-description>\n      </ui-card-header>\n    </ui-card>\n  `,\n};\n"}]}