{
  "schemaVersion": 1,
  "name": "integrations",
  "useFor": "Pass rows with a title, description and options. Each option supplies a label, icon and panel. Use IntegrationCode and IntegrationScreen to build the preview.",
  "constraints": [
    "More than six tools in one row",
    "Autoplaying the rows",
    "A blue stage",
    "Light code windows on the stage"
  ],
  "documentation": "",
  "source": "Extension in the opencommerce site's voice (its windows, keys and code; opencommerce-agentcard-web src/components/window.tsx, in-action.tsx); the layout from agentcard.sh / (.v7-intg-row)",
  "exports": [
    "Integrations",
    "IntegrationCode",
    "IntegrationScreen",
    "IntegrationRow",
    "IntegrationOption"
  ],
  "client": true,
  "docsUrl": "https://opencommerce-ds.vercel.app/components/integrations",
  "markdownUrl": "https://opencommerce-ds.vercel.app/r/integrations.md",
  "examples": [
    {
      "path": "examples/integrations.tsx",
      "content": "import { AppWindow, Bold, CircleDashed, MessageSquare, Triangle, Zap } from \"lucide-react\";\n\nimport { IntegrationCode, IntegrationScreen, Integrations } from \"@/components/site/integrations\";\n\nfunction Field({ title, detail, status }: { title: string; detail: string; status: string }) {\n  return (\n    <div className=\"flex items-center gap-2 rounded-control border border-line px-2.5 py-2 text-fg\">\n      <span className=\"grid\">\n        <b className=\"font-medium\">{title}</b>\n        <small className=\"text-micro text-fg-muted\">{detail}</small>\n      </span>\n      <em className=\"ml-auto rounded-chip bg-tint px-1.5 py-0.5 font-mono text-micro not-italic text-fg-brand\">{status}</em>\n    </div>\n  );\n}\n\nfunction Browser(tool: string, code: string) {\n  return (\n    <>\n      <IntegrationCode name={`${tool.toLowerCase()}.ts`}>{code}</IntegrationCode>\n      <IntegrationScreen name={tool.toUpperCase()} address=\"vault · user-12345\">\n        <Field title=\"Agentcard\" detail=\"Wallet\" status=\"Connected\" />\n        <Field title=\"Order\" detail=\"Card · $23.06 at amazon.com\" status=\"Authorizing\" />\n        <p className=\"text-micro opacity-80\">{tool} swaps the card in at its network edge</p>\n      </IntegrationScreen>\n    </>\n  );\n}\n\nconst CODE = `// One card item per purchase, in the\n// user's vault\nawait client.vaults.items.upsert('order', {\n  type: 'card',\n  spec: { provider: 'agentcard',\n    merchant: 'amazon.com',\n    amount: 2306, currency: 'usd' },\n});`;\n\nexport function Site() {\n  return (\n    <section className=\"mx-auto w-full max-w-(--ds-frame-column) py-20\">\n      <div className=\"mx-auto mb-9 max-w-(--ds-layout-heading) text-center\">\n        <h2 className=\"font-display text-h2 leading-heading font-medium tracking-tighter\">Integrates natively with the tools you use</h2>\n        <p className=\"mt-3.5 text-body-lg leading-6.5 tracking-tight opacity-70\">Kernel, Browserbase, Browser Use, Anchor, your own browser, Linq and Blooio: the stack your agent already runs on.</p>\n      </div>\n      <Integrations\n        rows={[\n          {\n            title: \"Browser integrations\",\n            description: \"Integrate with Kernel, Browserbase, Browser Use, Anchor or your own browser and automate purchases online.\",\n            options: [\n              { label: \"Kernel\", icon: <Zap />, panel: Browser(\"Kernel\", CODE) },\n              { label: \"Browserbase\", icon: <Bold />, panel: Browser(\"Browserbase\", CODE.replace(\"client\", \"bb\")) },\n              { label: \"Browser Use\", icon: <CircleDashed />, panel: Browser(\"Browser Use\", CODE.replace(\"client\", \"browser\")) },\n              { label: \"Anchor\", icon: <Triangle />, panel: Browser(\"Anchor\", CODE.replace(\"client\", \"anchor\")) },\n              { label: \"Your own browser\", icon: <AppWindow />, panel: Browser(\"Browser\", CODE) },\n            ],\n          },\n          {\n            title: \"Messaging integrations\",\n            description: \"iMessage agents built on top of Linq and Blooio can use Agentcard to complete payments.\",\n            options: [\"Linq\", \"Blooio\"].map((tool) => ({\n              label: tool,\n              icon: <MessageSquare />,\n              panel: (\n                <>\n                  <IntegrationCode name={`${tool.toLowerCase()} payments`}>{`POST api.${tool.toLowerCase()}.com/v3/payments\\n\\n{ \"amount\": 2306,\\n  \"currency\": \"usd\",\\n  \"merchant\": \"amazon.com\" }`}</IntegrationCode>\n                  <IntegrationScreen>\n                    <p className=\"w-fit rounded-card bg-surface px-3 py-1.5 text-fg\">Found it. Ready to check out?</p>\n                    <p className=\"ml-auto w-fit rounded-card bg-brand px-3 py-1.5\">Approved</p>\n                  </IntegrationScreen>\n                </>\n              ),\n            })),\n          },\n        ]}\n      />\n    </section>\n  );\n}\n",
      "exports": [
        "Site"
      ],
      "requires": [
        "integrations"
      ],
      "packages": [
        "lucide-react"
      ],
      "previews": [
        {
          "name": "Site",
          "url": "https://opencommerce-ds.vercel.app/preview/integrations/Site"
        }
      ]
    }
  ],
  "type": "site",
  "title": "Integrations",
  "description": "Integration sections with selectable tools and matching previews.",
  "surface": "site",
  "kinds": [
    "card",
    "media-frame",
    "code-window",
    "tabs"
  ],
  "requires": [
    "theme",
    "utils"
  ],
  "packages": [
    "@radix-ui/react-tabs"
  ],
  "files": [
    {
      "path": "components/site/integrations.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\";\n\nimport { cn } from \"@/lib/utils\";\n\n// The integrations, in the home page's voice: one card per kind of integration (white, a hairline, 12px corners and\n// the window's soft drop). The copy sits at one side (a 32px display title, a 16px muted line, then a list of rows, one\n// per tool); a mist stage at the other shows the chosen tool, usually a dark code window with a white card over its\n// corner. Rows are flat keys with a hairline that take the mist under the pointer; the chosen one takes the blue edge\n// and the pale blue, and the stage crossfades (200ms ease-out). Rows alternate sides; below 1024px the copy sits above.\n\ntype IntegrationOption = {\n  label: React.ReactNode;\n  /** The tool's mark, about 24px (decorative: the label is beside it). */\n  icon?: React.ReactNode;\n  /** What the stage shows for this tool: an IntegrationCode, an IntegrationScreen, or both. */\n  panel: React.ReactNode;\n};\n\ntype IntegrationRow = { title: React.ReactNode; description: React.ReactNode; options: IntegrationOption[] };\n\nconst ROW =\n  \"grid grid-cols-1 items-center gap-6 rounded-panel border border-line-strong bg-surface pt-6 pb-3 px-3 text-fg shadow-card lg:gap-[clamp(1.5rem,4vw,3.5rem)] lg:py-3\";\n\nconst OPTION =\n  \"relative flex h-12 items-center gap-3 overflow-hidden rounded-control border border-line-strong bg-surface px-4 text-left text-body-sm font-medium text-fg outline-none transition-[border-color,background-color,color] duration-(--ds-duration-fast) ease-out hover:bg-subtle focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-focus-ring motion-reduce:transition-none \" +\n  // Picked: the blue edge, the pale blue and blue text.\n  \"data-[state=active]:border-brand data-[state=active]:bg-tint data-[state=active]:text-fg-brand data-[state=active]:hover:bg-tint\";\n\nfunction Row({ row, index }: { row: IntegrationRow; index: number }) {\n  const [value, setValue] = React.useState(\"0\");\n  const reverse = index % 2 === 1;\n  return (\n    <TabsPrimitive.Root asChild value={value} onValueChange={setValue} orientation=\"vertical\">\n      <li\n        className={cn(\n          ROW,\n          reverse ? \"lg:grid-cols-[minmax(0,1.25fr)_minmax(0,0.85fr)] lg:pr-[clamp(1.5rem,3vw,2.5rem)]\" : \"lg:grid-cols-[minmax(0,0.85fr)_minmax(0,1.25fr)] lg:pl-[clamp(1.5rem,3vw,2.5rem)]\",\n        )}\n      >\n        <div className=\"px-3 lg:px-0\">\n          <h3 className=\"mb-3.5 font-display text-h2 leading-display font-medium tracking-tighter\">{row.title}</h3>\n          <p className=\"mb-7 max-w-[34ch] text-body leading-lead text-fg-muted\">{row.description}</p>\n          <TabsPrimitive.List className=\"grid gap-2\" aria-label={typeof row.title === \"string\" ? row.title : undefined}>\n            {row.options.map((option, i) => (\n              <TabsPrimitive.Trigger key={i} value={String(i)} className={OPTION}>\n                {option.icon && (\n                  <span aria-hidden className=\"flex size-6 flex-none items-center justify-center [&>img]:size-full [&>svg]:size-full\">\n                    {option.icon}\n                  </span>\n                )}\n                {option.label}\n              </TabsPrimitive.Trigger>\n            ))}\n          </TabsPrimitive.List>\n        </div>\n        <div\n          className={cn(\n            \"relative isolate flex items-center overflow-hidden rounded-card border border-line bg-subtle p-[clamp(1.125rem,2.4vw,2rem)] lg:min-h-105\",\n            reverse && \"lg:order-first\",\n          )}\n        >\n          {/* Every tool's panel shares one cell, so the stage keeps the tallest one's height and never jumps. */}\n          <div className=\"grid w-full items-center\">\n            {row.options.map((option, i) => (\n              <TabsPrimitive.Content\n                key={i}\n                value={String(i)}\n                forceMount\n                className=\"[grid-area:1/1] outline-none transition-[opacity,visibility] duration-200 ease-out data-[state=inactive]:pointer-events-none data-[state=inactive]:invisible data-[state=inactive]:opacity-0 motion-reduce:transition-none\"\n              >\n                {option.panel}\n              </TabsPrimitive.Content>\n            ))}\n          </div>\n        </div>\n      </li>\n    </TabsPrimitive.Root>\n  );\n}\n\n/** The integration rows, alternating sides. */\nfunction Integrations({ rows, className, ...props }: React.ComponentProps<\"ul\"> & { rows: IntegrationRow[] }) {\n  return (\n    <ul data-slot=\"integrations\" className={cn(\"grid gap-6\", className)} {...props}>\n      {rows.map((row, i) => (\n        <Row key={i} row={row} index={i} />\n      ))}\n    </ul>\n  );\n}\n\n/** A code window for the stage: ink, a 30px bar with the file's name in the muted mono, code in the platform mono. */\nfunction IntegrationCode({ name, children, className }: { name: React.ReactNode; children: React.ReactNode; className?: string }) {\n  return (\n    <div className={cn(\"w-full overflow-hidden rounded-panel border border-line-strong bg-code text-fg-code shadow-code md:w-[88%] lg:h-78\", className)}>\n      <div className=\"flex h-7.5 items-center border-b border-line-on-code px-3.5 font-mono text-bar text-fg-code-dim\">{name}</div>\n      <pre className=\"overflow-hidden px-4 pt-3.5 pb-15 font-mono text-caption leading-code whitespace-pre md:text-snippet\">{children}</pre>\n    </div>\n  );\n}\n\n/**\n * A white card for the stage, laid over the code window's lower corner when it follows one: a mist bar with the tool's\n * name and an address, then your content (rows, steps, a conversation).\n */\nfunction IntegrationScreen({ name, address, children, className }: { name?: React.ReactNode; address?: React.ReactNode; children: React.ReactNode; className?: string }) {\n  return (\n    <div\n      className={cn(\n        \"relative z-10 -mt-11 ml-auto overflow-hidden rounded-panel border border-line-strong bg-surface text-caption text-fg shadow-raised max-md:w-[92%] md:-mt-16 md:w-[68%]\",\n        className,\n      )}\n    >\n      {(name || address) && (\n        <div className=\"flex h-7.5 items-center gap-1.5 border-b border-line bg-subtle px-3 font-mono text-bar text-fg-muted\">\n          {name && <b className=\"font-medium text-fg\">{name}</b>}\n          {address && <span className=\"ml-2 flex-1 truncate rounded-chip border border-line bg-surface px-2 py-0.5\">{address}</span>}\n        </div>\n      )}\n      <div className=\"grid gap-3 p-3.5\">{children}</div>\n    </div>\n  );\n}\n\nexport { Integrations, IntegrationCode, IntegrationScreen, type IntegrationRow, type IntegrationOption };\n"
    }
  ]
}
