({ className, shouldHideNavBg, animatedIcon = true })
| 83 | shouldHideNavBg?: boolean |
| 84 | animatedIcon?: boolean |
| 85 | }> = ({ className, shouldHideNavBg, animatedIcon = true }) => { |
| 86 | const { config: headerMenuConfig } = useHeaderConfig() |
| 87 | const pathname = usePathname() |
| 88 | |
| 89 | const mouseX = useMotionValue(0) |
| 90 | const mouseY = useMotionValue(0) |
| 91 | const radius = useMotionValue(0) |
| 92 | const handleMouseMove = React.useCallback( |
| 93 | ({ clientX, clientY, currentTarget }: React.MouseEvent) => { |
| 94 | const bounds = currentTarget.getBoundingClientRect() |
| 95 | mouseX.set(clientX - bounds.left) |
| 96 | mouseY.set(clientY - bounds.top) |
| 97 | radius.set(Math.hypot(bounds.width, bounds.height) / 2.5) |
| 98 | }, |
| 99 | [mouseX, mouseY, radius], |
| 100 | ) |
| 101 | |
| 102 | const background = useMotionTemplate`radial-gradient(${radius}px circle at ${mouseX}px ${mouseY}px, var(--spotlight-color) 0%, transparent 65%)` |
| 103 | |
| 104 | return ( |
| 105 | <m.nav |
| 106 | layout="size" |
| 107 | onMouseMove={handleMouseMove} |
| 108 | className={clsxm( |
| 109 | 'relative', |
| 110 | 'rounded-full bg-gradient-to-b from-zinc-50/70 to-white/90', |
| 111 | 'shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur-md', |
| 112 | 'dark:from-zinc-900/70 dark:to-zinc-800/90 dark:ring-zinc-100/10', |
| 113 | 'group [--spotlight-color:oklch(var(--a)_/_0.12)]', |
| 114 | 'pointer-events-auto duration-200', |
| 115 | shouldHideNavBg && '!bg-none !shadow-none !ring-transparent', |
| 116 | className, |
| 117 | )} |
| 118 | > |
| 119 | {/* Spotlight overlay */} |
| 120 | <m.div |
| 121 | className="pointer-events-none absolute -inset-px rounded-full opacity-0 transition-opacity duration-500 group-hover:opacity-100" |
| 122 | style={{ background }} |
| 123 | aria-hidden="true" |
| 124 | /> |
| 125 | <div className="flex px-4 font-medium text-zinc-800 dark:text-zinc-200"> |
| 126 | {headerMenuConfig.map((section) => { |
| 127 | const subItemActive = |
| 128 | section.subMenu?.findIndex((item) => { |
| 129 | return item.path === pathname || pathname.slice(1) === item.path |
| 130 | }) ?? -1 |
| 131 | |
| 132 | return ( |
| 133 | <HeaderMenuItem |
| 134 | iconLayout={animatedIcon} |
| 135 | section={section} |
| 136 | key={section.path} |
| 137 | subItemActive={section.subMenu?.[subItemActive]} |
| 138 | isActive={ |
| 139 | pathname === section.path || |
| 140 | (pathname.startsWith(`${section.path}/`) && |
| 141 | !section.exclude?.includes(pathname)) || |
| 142 | subItemActive > -1 || |
nothing calls this directly
no test coverage detected