navLink.tsx 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  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?: string
  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 h-9 rounded-md py-2 text-sm font-normal',
  43. mode === 'expand' ? 'px-3' : 'px-2.5',
  44. )}
  45. title={mode === 'collapse' ? name : ''}
  46. >
  47. <NavIcon
  48. className={classNames(
  49. 'h-4 w-4 flex-shrink-0',
  50. isActive ? 'text-primary-600' : 'text-gray-700',
  51. mode === 'expand' ? 'mr-2' : 'mr-0',
  52. )}
  53. aria-hidden="true"
  54. />
  55. {mode === 'expand' && name}
  56. </Link>
  57. )
  58. }