navLink.tsx 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. 'use client'
  2. import { useSelectedLayoutSegment } from 'next/navigation'
  3. import classNames from 'classnames'
  4. import Link from 'next/link'
  5. export type NavIcon = React.ComponentType<
  6. React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
  7. title?: string | undefined
  8. titleId?: string | undefined
  9. }
  10. >
  11. export type NavLinkProps = {
  12. name: string
  13. href: string
  14. iconMap: {
  15. selected: NavIcon
  16. normal: NavIcon
  17. }
  18. mode?: 'expand' | 'collapse'
  19. }
  20. export default function NavLink({
  21. name,
  22. href,
  23. iconMap,
  24. mode = 'expand',
  25. }: NavLinkProps) {
  26. const segment = useSelectedLayoutSegment()
  27. const formattedSegment = (() => {
  28. let res = segment?.toLowerCase()
  29. // logs and annotations use the same nav
  30. if (res === 'annotations')
  31. res = 'logs'
  32. return res
  33. })()
  34. const isActive = href.toLowerCase().split('/')?.pop() === formattedSegment
  35. const NavIcon = isActive ? iconMap.selected : iconMap.normal
  36. return (
  37. <Link
  38. key={name}
  39. href={href}
  40. className={classNames(
  41. isActive ? 'bg-primary-50 text-primary-600 font-semibold' : 'text-gray-700 hover:bg-gray-100 hover:text-gray-700',
  42. 'group flex items-center rounded-md px-2 py-2 text-sm font-normal',
  43. )}
  44. >
  45. <NavIcon
  46. className={classNames(
  47. 'mr-2 h-4 w-4 flex-shrink-0',
  48. isActive ? 'text-primary-600' : 'text-gray-700',
  49. )}
  50. aria-hidden="true"
  51. />
  52. {mode === 'expand' && name}
  53. </Link>
  54. )
  55. }