{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "header-2", "type": "registry:block", "description": "Elegant responsive header with scroll-based styling, mobile drawer menu, and smooth transitions.", "registryDependencies": [ "button" ], "files": [ { "path": "registry/blocks/header/2/header.tsx", "content": "\"use client\";\nimport React from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { Logo } from \"@/components/logo\";\nimport { MenuToggleIcon } from \"@/components/menu-toggle-icon\";\nimport { Button, buttonVariants } from \"@/components/ui/button\";\nimport { useScroll } from \"@/hooks/use-scroll\";\nimport { cn } from \"@/lib/utils\";\n\nexport function Header() {\n const [open, setOpen] = React.useState(false);\n const scrolled = useScroll(10);\n\n const links = [\n {\n label: \"Features\",\n href: \"#\",\n },\n {\n label: \"Pricing\",\n href: \"#\",\n },\n {\n label: \"About\",\n href: \"#\",\n },\n ];\n\n React.useEffect(() => {\n if (open) {\n // Disable scroll\n document.body.style.overflow = \"hidden\";\n } else {\n // Re-enable scroll\n document.body.style.overflow = \"\";\n }\n\n // Cleanup when component unmounts (important for Next.js)\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [open]);\n\n return (\n \n \n \n \n \n
\n {links.map((link, i) => (\n \n {link.label}\n \n ))}\n \n \n
\n setOpen(!open)}\n size=\"icon\"\n variant=\"outline\"\n >\n \n \n \n\n \n
\n {links.map((link) => (\n \n {link.label}\n \n ))}\n
\n
\n \n \n
\n
\n \n );\n}\n\ntype MobileMenuProps = React.ComponentProps<\"div\"> & {\n open: boolean;\n};\n\nfunction MobileMenu({ open, children, className, ...props }: MobileMenuProps) {\n if (!open || typeof window === \"undefined\") {\n return null;\n }\n\n return createPortal(\n \n \n {children}\n \n ,\n document.body\n );\n}\n", "type": "registry:component" }, { "path": "components/logo.tsx", "content": "import type React from \"react\";\n\nexport const LogoIcon = (props: React.ComponentProps<\"svg\">) => (\n \n \n \n \n \n \n);\n\nexport const Logo = (props: React.ComponentProps<\"svg\">) => (\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n);\n", "type": "registry:component" }, { "path": "components/menu-toggle-icon.tsx", "content": "\"use client\";\nimport type React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\ntype MenuToggleProps = React.ComponentProps<\"svg\"> & {\n open: boolean;\n duration?: number;\n};\n\nexport function MenuToggleIcon({\n open,\n className,\n fill = \"none\",\n stroke = \"currentColor\",\n strokeWidth = 2.5,\n strokeLinecap = \"round\",\n strokeLinejoin = \"round\",\n duration = 500,\n ...props\n}: MenuToggleProps) {\n return (\n \n \n \n \n );\n}\n", "type": "registry:component" }, { "path": "hooks/use-scroll.ts", "content": "\"use client\";\nimport React from \"react\";\n\nexport function useScroll(threshold: number) {\n const [scrolled, setScrolled] = React.useState(false);\n\n const onScroll = React.useCallback(() => {\n setScrolled(window.scrollY > threshold);\n }, [threshold]);\n\n React.useEffect(() => {\n window.addEventListener(\"scroll\", onScroll);\n return () => window.removeEventListener(\"scroll\", onScroll);\n }, [onScroll]);\n\n // also check on first load\n React.useEffect(() => {\n onScroll();\n }, [onScroll]);\n\n return scrolled;\n}\n", "type": "registry:hook" } ], "meta": { "height": "50vh" }, "categories": [ "header" ] }