{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "footer",
  "type": "registry:ui",
  "dependencies": [
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "footer.tsx",
      "target": "components/ui/footer.tsx",
      "type": "registry:ui",
      "content": "import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type FooterTone = \"accent\" | \"accent-alt\";\n\nexport interface FooterLink {\n  label: React.ReactNode;\n  href: string;\n  /** Overrides the target derived from the protocol. */\n  external?: boolean;\n  icon?: React.ReactNode;\n}\n\nexport interface FooterColumn {\n  /** Doubles as the column's accessible name, so keep it a string. */\n  title: string;\n  tone?: FooterTone;\n  links: FooterLink[];\n}\n\nexport interface FooterProps extends React.HTMLAttributes<HTMLElement> {\n  brand?: React.ReactNode;\n  tagline?: React.ReactNode;\n  columns?: FooterColumn[];\n  /** `full` keeps the titled columns. `compact` flattens them into one row. */\n  variant?: \"full\" | \"compact\";\n  copyright?: React.ReactNode;\n  /** Trailing note, set opposite the copyright. */\n  note?: React.ReactNode;\n  /** Two decorative radial washes. They assume a dark page, so they are opt-in. */\n  glow?: boolean;\n}\n\nconst toneHover: Record<FooterTone, string> = {\n  accent: \"hover:text-accent\",\n  \"accent-alt\": \"hover:text-accent-alt\",\n};\n\n/** An offsite link opens a tab. `mailto:`, `tel:` and in-page anchors do not. */\nfunction isOffsite(href: string): boolean {\n  return /^https?:\\/\\//.test(href);\n}\n\nfunction FooterAnchor({\n  link,\n  tone = \"accent\",\n  compact,\n}: {\n  link: FooterLink;\n  tone?: FooterTone;\n  compact?: boolean;\n}) {\n  const offsite = link.external ?? isOffsite(link.href);\n  return (\n    <a\n      href={link.href}\n      {...(offsite ? { target: \"_blank\", rel: \"noopener noreferrer\" } : {})}\n      className={cn(\n        \"relative inline-flex items-center gap-2 text-ink outline-none [&_svg]:size-4\",\n        \"transition-tint duration-fast ease-soft motion-reduce:transition-none\",\n        \"focus-visible:ring-focus\",\n        toneHover[tone],\n        compact\n          ? \"leading-5 after:absolute after:inset-x-0 after:-inset-y-3 after:content-['']\"\n          : \"min-h-11\",\n      )}\n    >\n      {link.icon}\n      {link.label}\n      {offsite && <span className=\"sr-only\"> (opens in a new tab)</span>}\n    </a>\n  );\n}\n\n/**\n * kajo's footer pulls itself up under the section above with a negative margin. That\n * is page layout, not footer, so it stays in the consumer's className.\n */\nexport const Footer = React.forwardRef<HTMLElement, FooterProps>(\n  (\n    {\n      className,\n      brand,\n      tagline,\n      columns = [],\n      variant = \"full\",\n      copyright,\n      note,\n      glow,\n      ...props\n    },\n    ref,\n  ) => {\n    const compact = variant === \"compact\";\n    const flatLinks = compact ? columns.flatMap((c) => c.links) : [];\n    const hasBottom = copyright != null || note != null;\n\n    return (\n      <footer\n        ref={ref}\n        className={cn(\n          \"relative isolate w-full overflow-hidden px-6 py-12 text-ink sm:px-10\",\n          className,\n        )}\n        {...props}\n      >\n        <span\n          data-footer-rule=\"\"\n          aria-hidden=\"true\"\n          style={{\n            backgroundImage:\n              \"linear-gradient(90deg, transparent, color-mix(in oklab, var(--color-ink) 26%, transparent), color-mix(in oklab, var(--color-accent-alt) 24%, transparent), transparent)\",\n          }}\n          className=\"pointer-events-none absolute inset-x-0 top-0 h-px\"\n        />\n\n        {glow && (\n          <>\n            <span\n              data-footer-glow=\"\"\n              aria-hidden=\"true\"\n              style={{\n                backgroundImage:\n                  \"radial-gradient(circle, color-mix(in oklab, var(--color-accent) 20%, transparent), transparent 64%)\",\n              }}\n              className=\"pointer-events-none absolute -top-1/3 right-0 -z-10 h-[105%] w-1/2\"\n            />\n            <span\n              data-footer-glow=\"\"\n              aria-hidden=\"true\"\n              style={{\n                backgroundImage:\n                  \"radial-gradient(circle, color-mix(in oklab, var(--color-accent-alt) 16%, transparent), transparent 64%)\",\n              }}\n              className=\"pointer-events-none absolute -bottom-1/3 left-0 -z-10 h-[110%] w-1/2\"\n            />\n          </>\n        )}\n\n        <div className=\"relative mx-auto flex max-w-[72.5rem] flex-col gap-12\">\n          <div\n            className={cn(\n              \"flex flex-col gap-10\",\n              compact\n                ? \"sm:flex-row sm:items-center sm:justify-between\"\n                : \"md:flex-row md:items-start md:justify-between\",\n            )}\n          >\n            {(brand != null || tagline != null) && (\n              <div className=\"flex max-w-md flex-col gap-3\">\n                {brand}\n                {tagline != null && (\n                  <p className=\"text-[0.9375rem] leading-[1.75] text-muted\">\n                    {tagline}\n                  </p>\n                )}\n              </div>\n            )}\n\n            {compact ? (\n              <nav aria-label=\"Footer\">\n                <ul className=\"flex list-none flex-wrap items-center gap-x-6 gap-y-3 text-sm\">\n                  {flatLinks.map((link) => (\n                    <li key={link.href}>\n                      <FooterAnchor link={link} compact />\n                    </li>\n                  ))}\n                </ul>\n              </nav>\n            ) : (\n              <div className=\"grid grid-cols-2 gap-x-14 gap-y-9\">\n                {columns.map((column) => (\n                  <nav key={column.title} aria-label={column.title}>\n                    <p className=\"mb-4 font-mono text-xs uppercase tracking-[0.14em] text-muted\">\n                      {column.title}\n                    </p>\n                    <ul className=\"flex list-none flex-col text-[0.96875rem]\">\n                      {column.links.map((link) => (\n                        <li key={link.href}>\n                          <FooterAnchor link={link} tone={column.tone} />\n                        </li>\n                      ))}\n                    </ul>\n                  </nav>\n                ))}\n              </div>\n            )}\n          </div>\n\n          {hasBottom && (\n            <div\n              data-footer-bottom=\"\"\n              className=\"grid gap-3 border-t border-border pt-6 text-center font-mono text-[0.8125rem] tracking-[0.04em] text-muted md:grid-cols-[1fr_auto_1fr] md:text-left\"\n            >\n              <span>{copyright}</span>\n              {note != null && (\n                <span className=\"md:col-start-3 md:text-right\">{note}</span>\n              )}\n            </div>\n          )}\n        </div>\n      </footer>\n    );\n  },\n);\nFooter.displayName = \"Footer\";\n"
    }
  ]
}