{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "integration-orbit",
  "title": "Integration Orbit",
  "description": "Concentric rings of integration logos that orbit a featured brand mark on hover.",
  "registryDependencies": [],
  "files": [
    {
      "path": "payload-components/source/blocks/shared/integrationFields.ts",
      "content": "import type { Field } from 'payload'\n\n/**\n * Shared field core for the Integration block family.\n *\n * Every integration variant (integration-grid, integration-cluster,\n * integration-split, integration-connect, integration-orbit, integration-list,\n * integration-marquee, integration-testimonial, …) spreads these fields first\n * and then appends its own variant-specific shape (for example the cluster\n * variants add a featured center mark, and the testimonial variant adds a\n * quote). Editing the shared heading/integrations shape here updates every\n * installed integration block at once, so the family never drifts\n * field-by-field across a repo.\n *\n * Each integration is an editable Media upload plus an accessible name, an\n * optional supporting description, and an optional link, so editors manage the\n * wall of partner/tool logos from the admin instead of shipping hardcoded\n * brand SVGs. Logo-only variants simply ignore the per-item description/href.\n *\n * Installed once per repo at `src/blocks/shared/integrationFields.ts`; re-running\n * `payload-components add integration-*` never overwrites a copy you have already edited.\n */\nexport const integrationFields: Field[] = [\n  {\n    name: 'heading',\n    type: 'text',\n    required: true,\n  },\n  {\n    name: 'subtext',\n    type: 'textarea',\n  },\n  {\n    name: 'integrations',\n    type: 'array',\n    required: true,\n    minRows: 2,\n    maxRows: 12,\n    admin: {\n      initCollapsed: true,\n    },\n    fields: [\n      {\n        name: 'logo',\n        type: 'upload',\n        relationTo: 'media',\n        required: true,\n      },\n      {\n        name: 'name',\n        type: 'text',\n        required: true,\n      },\n      {\n        name: 'description',\n        type: 'textarea',\n      },\n      {\n        name: 'href',\n        type: 'text',\n      },\n    ],\n  },\n]\n\n/**\n * Optional center brand mark, spread by the variants that arrange the\n * integration logos around a focal point (cluster, split, connect, orbit,\n * marquee). Left empty, the variant renders without a center mark.\n */\nexport const integrationFeaturedMark: Field = {\n  name: 'featuredLogo',\n  type: 'upload',\n  relationTo: 'media',\n  admin: {\n    description: 'Optional center brand mark shown at the focal point of the integration layout.',\n  },\n}\n",
      "type": "registry:file",
      "target": "~/src/blocks/shared/integrationFields.ts"
    },
    {
      "path": "payload-components/source/blocks/IntegrationOrbit/config.ts",
      "content": "import type { Block } from 'payload'\n\nimport { integrationFeaturedMark, integrationFields } from '@/blocks/shared/integrationFields'\n\nexport const IntegrationOrbit: Block = {\n  slug: 'integrationOrbit',\n  // Existing apps must migrate stored data before adopting this identifier:\n  // https://www.payload-components.xyz/docs/registry#installed-source-and-migrations\n  dbName: 'pc_int_orb',\n  interfaceName: 'IntegrationOrbitBlock',\n  fields: [\n    // Shared integration core (heading + subtext + integrations). Edit the shared\n    // shape in @/blocks/shared/integrationFields to update every integration variant.\n    ...integrationFields,\n    // Variant-specific: a featured center brand mark the rings orbit around.\n    integrationFeaturedMark,\n  ],\n  labels: {\n    plural: 'Integration Orbit Blocks',\n    singular: 'Integration Orbit',\n  },\n}\n",
      "type": "registry:file",
      "target": "~/src/blocks/IntegrationOrbit/config.ts"
    },
    {
      "path": "payload-components/source/blocks/IntegrationOrbit/Component.tsx",
      "content": "import React from 'react'\n\nimport type { IntegrationOrbitBlock as IntegrationOrbitBlockData } from '@/payload-types'\n\nimport { Media } from '@/components/Media'\nimport { cn } from '@/utilities/ui'\n\ntype Props = IntegrationOrbitBlockData & {\n  id?: string\n  className?: string\n  disableInnerContainer?: boolean\n}\n\n/* Place an item around a ring: rotate to its slot, push out by the radius, then\n   counter-rotate the content so the logo stays upright. The animated spin lives\n   in globals.css (.integration-orbit-ring / .integration-orbit-logo) and runs\n   only on hover, so nothing animates on load. */\nconst slotStyle = (index: number, count: number, radius: string) => ({\n  transform: `rotate(${(360 / Math.max(count, 1)) * index}deg) translateY(-${radius})`,\n})\nconst uprightStyle = (index: number, count: number) => ({\n  transform: `rotate(${-(360 / Math.max(count, 1)) * index}deg)`,\n})\n\nexport const IntegrationOrbitBlock: React.FC<Props> = ({\n  className,\n  disableInnerContainer,\n  featuredLogo,\n  heading,\n  id,\n  integrations,\n  subtext,\n}) => {\n  const items = integrations ?? []\n  const outer = items.slice(0, Math.ceil(items.length / 2))\n  const inner = items.slice(Math.ceil(items.length / 2))\n\n  return (\n    <section className={cn('container', className)} id={id ? `block-${id}` : undefined}>\n      <div className=\"overflow-hidden rounded-frame border border-border/70 bg-card/35 px-6 py-14 sm:px-8 lg:px-12 lg:py-20\">\n        <div\n          className={cn('flex flex-col items-center gap-12', {\n            'mx-auto max-w-3xl': !disableInnerContainer,\n          })}\n        >\n          <div className=\"group relative mx-auto flex aspect-square w-full max-w-xs items-center justify-center\">\n            <div className=\"integration-orbit-ring absolute inset-0\">\n              <div className=\"absolute inset-0 rounded-full border border-dashed border-border/70\" />\n              {outer.map((item, index) => (\n                <div\n                  className=\"absolute left-1/2 top-1/2\"\n                  key={item.id ?? `outer-${item.name}-${index}`}\n                  style={slotStyle(index, outer.length, '7.5rem')}\n                >\n                  <div style={uprightStyle(index, outer.length)}>\n                    <div className=\"integration-orbit-logo\">\n                      <div className=\"flex size-12 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl border border-border/70 bg-background shadow-sm\">\n                        <Media resource={item.logo} imgClassName=\"size-6 w-auto object-contain\" />\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              ))}\n            </div>\n\n            <div className=\"integration-orbit-ring-reverse absolute inset-[24%]\">\n              <div className=\"absolute inset-0 rounded-full border border-dashed border-border/70\" />\n              {inner.map((item, index) => (\n                <div\n                  className=\"absolute left-1/2 top-1/2\"\n                  key={item.id ?? `inner-${item.name}-${index}`}\n                  style={slotStyle(index, inner.length, '4.25rem')}\n                >\n                  <div style={uprightStyle(index, inner.length)}>\n                    <div className=\"integration-orbit-logo\">\n                      <div className=\"flex size-10 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-xl border border-border/70 bg-background shadow-sm\">\n                        <Media resource={item.logo} imgClassName=\"size-5 w-auto object-contain\" />\n                      </div>\n                    </div>\n                  </div>\n                </div>\n              ))}\n            </div>\n\n            {featuredLogo ? (\n              <div className=\"relative z-10 flex size-16 items-center justify-center rounded-2xl border border-foreground/25 bg-card shadow-lg\">\n                <Media resource={featuredLogo} imgClassName=\"size-9 w-auto object-contain\" />\n              </div>\n            ) : null}\n          </div>\n\n          <div className=\"flex max-w-lg flex-col items-center gap-5 text-center\">\n            <h2 className=\"text-balance text-2xl font-semibold tracking-heading text-foreground sm:text-3xl\">\n              {heading}\n            </h2>\n            {subtext ? (\n              <p className=\"text-pretty text-sm text-muted-foreground sm:text-base\">{subtext}</p>\n            ) : null}\n          </div>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:file",
      "target": "~/src/blocks/IntegrationOrbit/Component.tsx"
    }
  ],
  "meta": {
    "payloadComponent": {
      "installCommand": "payload-components add integration-orbit",
      "postInstall": [
        "generate:types",
        "generate:importmap"
      ],
      "requiresPayloadComponentWrapper": true,
      "supportedTargets": [
        "payload-website-starter",
        "payload-blocks-app"
      ]
    }
  },
  "docs": "Payload Components installs this as a Payload CMS block for the Payload website starter shape.\n\nRecommended install:\n\n```bash\npnpm payload-components add integration-orbit\n```\n\nDirect shadcn install URL:\n\n```bash\npnpm dlx shadcn@latest add https://www.payload-components.xyz/r/integration-orbit.json\n```\n\nDirect shadcn installs only copy the block source files and shadcn UI dependencies. Use `payload-components add integration-orbit` when you also want Payload layout registration, `RenderBlocks` wiring, `generate:types`, and `generate:importmap` handled for you.",
  "type": "registry:block"
}