navLink.tsx 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. 'use client'
  2. import { useSelectedLayoutSegment } from 'next/navigation'
  3. import Link from 'next/link'
  4. import classNames from '@/utils/classnames'
  5. import type { RemixiconComponentType } from '@remixicon/react'
  6. export type NavIcon = React.ComponentType<
  7. React.PropsWithoutRef<React.ComponentProps<'svg'>> & {
  8. title?: string | undefined
  9. titleId?: string | undefined
  10. }> | RemixiconComponentType
  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-state-accent-active text-text-accent font-semibold' : 'text-components-menu-item-text hover:bg-gray-100 hover:text-components-menu-item-text-hover',
  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. mode === 'expand' ? 'mr-2' : 'mr-0',
  51. )}
  52. aria-hidden="true"
  53. />
  54. {mode === 'expand' && name}
  55. </Link>
  56. )
  57. }