{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "footer-4",
  "title": "Mega Sitemap With Locale",
  "description": "Mega footer with four sitemap columns and a bottom bar carrying a locale switcher dropdown and a light and dark theme toggle.",
  "dependencies": [
    "next-themes",
    "@base-ui/react"
  ],
  "registryDependencies": [
    "button",
    "dropdown-menu",
    "separator"
  ],
  "files": [
    {
      "path": "registry/blocks/footer/4/footer-block.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { useTheme } from \"next-themes\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport {\n  DropdownMenu,\n  DropdownMenuContent,\n  DropdownMenuItem,\n  DropdownMenuTrigger,\n} from \"@/components/ui/dropdown-menu\"\nimport { Separator } from \"@/components/ui/separator\"\nimport { IconPlaceholder } from \"@/components/icons/icon-placeholder\"\n\n/** Props a call site may pass through to an icon. */\ntype IconProps = { className?: string; size?: number | string }\n\nconst columns = [\n  {\n    title: \"Product\",\n    links: [\"Features\", \"Integrations\", \"Pricing\", \"Changelog\", \"Roadmap\"],\n  },\n  {\n    title: \"Company\",\n    links: [\"About\", \"Careers\", \"Blog\", \"Press\", \"Contact\"],\n  },\n  {\n    title: \"Resources\",\n    links: [\n      \"Documentation\",\n      \"Guides\",\n      \"Help Center\",\n      \"API Status\",\n      \"Community\",\n    ],\n  },\n  {\n    title: \"Legal\",\n    links: [\"Privacy\", \"Terms\", \"Security\", \"Cookies\", \"Licenses\"],\n  },\n]\n\nconst socials = [\n  { label: \"X\", icon: (p: IconProps) => <XOutlineMark {...p} /> },\n  { label: \"GitHub\", icon: (p: IconProps) => <GithubMark {...p} /> },\n  { label: \"LinkedIn\", icon: (p: IconProps) => <LinkedinBoxMark {...p} /> },\n]\n\nconst locales = [\n  { code: \"en\", label: \"English\" },\n  { code: \"es\", label: \"Español\" },\n  { code: \"de\", label: \"Deutsch\" },\n  { code: \"fr\", label: \"Français\" },\n  { code: \"ja\", label: \"日本語\" },\n]\n\nexport default function FooterBlock() {\n  const [locale, setLocale] = React.useState(locales[0])\n  const { resolvedTheme, setTheme } = useTheme()\n  // Avoid a hydration mismatch: the resolved theme is only known on the\n  // client, so render the server/first-paint state until mounted.\n  const mounted = React.useSyncExternalStore(\n    () => () => {},\n    () => true,\n    () => false\n  )\n  const isDark = mounted && resolvedTheme === \"dark\"\n\n  return (\n    <section className=\"flex w-full items-center justify-center bg-muted/30 px-6 py-16 text-foreground\">\n      <footer className=\"mx-auto w-full max-w-6xl\">\n        <div className=\"grid grid-cols-2 gap-10 sm:grid-cols-3 md:grid-cols-6\">\n          <div className=\"col-span-2 sm:col-span-3 md:col-span-2\">\n            <div className=\"flex items-center gap-2\">\n              <svg\n                viewBox=\"0 0 24 24\"\n                fill=\"currentColor\"\n                aria-hidden=\"true\"\n                className=\"size-7 shrink-0 text-primary\"\n              >\n                <rect\n                  x=\"3\"\n                  y=\"3\"\n                  width=\"8\"\n                  height=\"8\"\n                  transform=\"rotate(-6 7 7)\"\n                />\n                <rect\n                  x=\"3\"\n                  y=\"13\"\n                  width=\"8\"\n                  height=\"8\"\n                  transform=\"rotate(5 7 17)\"\n                />\n                <rect\n                  x=\"13\"\n                  y=\"13\"\n                  width=\"8\"\n                  height=\"8\"\n                  transform=\"rotate(-4 17 17)\"\n                />\n                <rect\n                  x=\"13\"\n                  y=\"3\"\n                  width=\"8\"\n                  height=\"8\"\n                  transform=\"rotate(15 17 7)\"\n                />\n              </svg>\n              <span className=\"text-lg font-semibold tracking-tight\">Acme</span>\n            </div>\n            <p className=\"mt-4 max-w-xs text-sm leading-relaxed text-muted-foreground\">\n              The composable platform teams use to ship polished products\n              faster, from first prototype to global scale.\n            </p>\n            <div className=\"mt-6 flex items-center gap-2\">\n              {socials.map((social) => (\n                <Button\n                  key={social.label}\n                  variant=\"outline\"\n                  size=\"icon\"\n                  aria-label={social.label}\n                  className=\"rounded-lg\"\n                >\n                  <social.icon className=\"size-4\" />\n                </Button>\n              ))}\n            </div>\n          </div>\n\n          {columns.map((column) => (\n            <nav key={column.title} className=\"flex flex-col gap-3\">\n              <h3 className=\"font-heading text-sm font-semibold text-foreground\">\n                {column.title}\n              </h3>\n              <ul className=\"flex flex-col gap-2.5\">\n                {column.links.map((link) => (\n                  <li key={link}>\n                    <a\n                      href=\"#\"\n                      className=\"text-sm text-muted-foreground transition-colors hover:text-foreground\"\n                    >\n                      {link}\n                    </a>\n                  </li>\n                ))}\n              </ul>\n            </nav>\n          ))}\n        </div>\n\n        <Separator className=\"my-8\" />\n\n        <div className=\"flex flex-col-reverse items-start gap-4 sm:flex-row sm:items-center sm:justify-between\">\n          <p className=\"text-sm text-muted-foreground\">\n            © <span suppressHydrationWarning>{new Date().getFullYear()}</span>{\" \"}\n            Acme, Inc. All rights reserved.\n          </p>\n\n          <div className=\"flex items-center gap-2\">\n            <DropdownMenu>\n              <DropdownMenuTrigger\n                render={\n                  <Button variant=\"outline\" size=\"sm\" className=\"rounded-lg\" />\n                }\n              >\n                {locale.label}\n                <IconPlaceholder\n                  lucide=\"ChevronDown\"\n                  tabler=\"IconChevronDown\"\n                  hugeicons=\"ArrowDown01Icon\"\n                  phosphor=\"CaretDown\"\n                  remixicon=\"RiArrowDownSLine\"\n                  className=\"size-4 text-muted-foreground\"\n                  data-icon=\"inline-start\"\n                />\n              </DropdownMenuTrigger>\n              <DropdownMenuContent align=\"end\" className=\"rounded-lg\">\n                {locales.map((item) => (\n                  <DropdownMenuItem\n                    key={item.code}\n                    onClick={() => setLocale(item)}\n                    className={cn(\n                      \"rounded-lg\",\n                      item.code === locale.code && \"font-medium text-foreground\"\n                    )}\n                  >\n                    {item.label}\n                  </DropdownMenuItem>\n                ))}\n              </DropdownMenuContent>\n            </DropdownMenu>\n\n            <Button\n              variant=\"outline\"\n              size=\"icon-sm\"\n              aria-label={\n                isDark ? \"Switch to light mode\" : \"Switch to dark mode\"\n              }\n              aria-pressed={isDark}\n              onClick={() => setTheme(isDark ? \"light\" : \"dark\")}\n              className=\"rounded-lg\"\n            >\n              {isDark ? (\n                <IconPlaceholder\n                  lucide=\"Sun\"\n                  tabler=\"IconSun\"\n                  hugeicons=\"SunIcon\"\n                  phosphor=\"Sun\"\n                  remixicon=\"RiSunLine\"\n                  className=\"size-4\"\n                />\n              ) : (\n                <IconPlaceholder\n                  lucide=\"Moon\"\n                  tabler=\"IconMoon\"\n                  hugeicons=\"MoonIcon\"\n                  phosphor=\"Moon\"\n                  remixicon=\"RiMoonLine\"\n                  className=\"size-4\"\n                />\n              )}\n            </Button>\n          </div>\n        </div>\n      </footer>\n    </section>\n  )\n}\n\n// Brand marks are inlined rather than imported from an icon library: the rest\n// of this file uses IconPlaceholder, which resolves to whichever icon set the\n// consumer already has, and one brand import would drag a whole extra package\n// into their install for a handful of glyphs.\ntype MarkProps = React.ComponentProps<\"svg\"> & { size?: number | string }\n\nfunction GithubMark({ size = 24, ...props }: MarkProps) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width={size}\n      height={size}\n      fill=\"currentColor\"\n      aria-hidden=\"true\"\n      {...props}\n    >\n      <path d=\"M12.001 2C6.47598 2 2.00098 6.475 2.00098 12C2.00098 16.425 4.86348 20.1625 8.83848 21.4875C9.33848 21.575 9.52598 21.275 9.52598 21.0125C9.52598 20.775 9.51348 19.9875 9.51348 19.15C7.00098 19.6125 6.35098 18.5375 6.15098 17.975C6.03848 17.6875 5.55098 16.8 5.12598 16.5625C4.77598 16.375 4.27598 15.9125 5.11348 15.9C5.90098 15.8875 6.46348 16.625 6.65098 16.925C7.55098 18.4375 8.98848 18.0125 9.56348 17.75C9.65098 17.1 9.91348 16.6625 10.201 16.4125C7.97598 16.1625 5.65098 15.3 5.65098 11.475C5.65098 10.3875 6.03848 9.4875 6.67598 8.7875C6.57598 8.5375 6.22598 7.5125 6.77598 6.1375C6.77598 6.1375 7.61348 5.875 9.52598 7.1625C10.326 6.9375 11.176 6.825 12.026 6.825C12.876 6.825 13.726 6.9375 14.526 7.1625C16.4385 5.8625 17.276 6.1375 17.276 6.1375C17.826 7.5125 17.476 8.5375 17.376 8.7875C18.0135 9.4875 18.401 10.375 18.401 11.475C18.401 15.3125 16.0635 16.1625 13.8385 16.4125C14.201 16.725 14.5135 17.325 14.5135 18.2625C14.5135 19.6 14.501 20.675 14.501 21.0125C14.501 21.275 14.6885 21.5875 15.1885 21.4875C19.259 20.1133 21.9999 16.2963 22.001 12C22.001 6.475 17.526 2 12.001 2Z\" />\n    </svg>\n  )\n}\n\nfunction LinkedinBoxMark({ size = 24, ...props }: MarkProps) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width={size}\n      height={size}\n      fill=\"currentColor\"\n      aria-hidden=\"true\"\n      {...props}\n    >\n      <path d=\"M18.3362 18.339H15.6707V14.1622C15.6707 13.1662 15.6505 11.8845 14.2817 11.8845C12.892 11.8845 12.6797 12.9683 12.6797 14.0887V18.339H10.0142V9.75H12.5747V10.9207H12.6092C12.967 10.2457 13.837 9.53325 15.1367 9.53325C17.8375 9.53325 18.337 11.3108 18.337 13.6245V18.339H18.3362ZM7.00373 8.57475C6.14573 8.57475 5.45648 7.88025 5.45648 7.026C5.45648 6.1725 6.14648 5.47875 7.00373 5.47875C7.85873 5.47875 8.55173 6.1725 8.55173 7.026C8.55173 7.88025 7.85798 8.57475 7.00373 8.57475ZM8.34023 18.339H5.66723V9.75H8.34023V18.339ZM19.6697 3H4.32923C3.59498 3 3.00098 3.5805 3.00098 4.29675V19.7033C3.00098 20.4202 3.59498 21 4.32923 21H19.6675C20.401 21 21.001 20.4202 21.001 19.7033V4.29675C21.001 3.5805 20.401 3 19.6675 3H19.6697Z\" />\n    </svg>\n  )\n}\n\nfunction XOutlineMark({ size = 24, ...props }: MarkProps) {\n  return (\n    <svg\n      viewBox=\"0 0 24 24\"\n      width={size}\n      height={size}\n      fill=\"currentColor\"\n      aria-hidden=\"true\"\n      {...props}\n    >\n      <path d=\"M10.4883 14.651L15.25 21H22.25L14.3917 10.5223L20.9308 3H18.2808L13.1643 8.88578L8.75 3H1.75L9.26086 13.0145L2.31915 21H4.96917L10.4883 14.651ZM16.25 19L5.75 5H7.75L18.25 19H16.25Z\" />\n    </svg>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/footer-4.tsx"
    }
  ],
  "meta": {
    "height": "421px",
    "tier": "free"
  },
  "docs": "Requires a `base-*` style in components.json (the `shadcn init` default). Legacy `new-york`/`radix-*` styles install Radix primitives, which reject the `render` prop this block uses.",
  "categories": [
    "footer"
  ],
  "type": "registry:block"
}