DocsMenu.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import Link from 'next/link'
  2. import { cn } from 'ui'
  3. import { ProductMenuGroup } from '@/components/ui/ProductMenu/ProductMenu.types'
  4. export const DocsMenu = ({
  5. menu,
  6. activePage,
  7. }: {
  8. menu: Array<ProductMenuGroup>
  9. activePage?: string
  10. }) => {
  11. return (
  12. <nav className="space-y-6 text-xs">
  13. {menu.map((group, idx) => (
  14. <div key={group.key || group.title || idx}>
  15. {group.title && (
  16. <div className="heading-meta mb-2 text-foreground-lighter">{group.title}</div>
  17. )}
  18. <div className="space-y-2">
  19. {group.items.map((item) => {
  20. const isActive = item.pages
  21. ? item.pages.includes(activePage ?? '')
  22. : activePage === item.key
  23. const isDisabled = !!item.disabled
  24. const content = (
  25. <span
  26. className={cn(
  27. 'flex items-center',
  28. isActive ? 'text-foreground' : 'text-foreground-light hover:text-foreground'
  29. )}
  30. >
  31. <span className="truncate">{item.name}</span>
  32. {item.rightIcon && (
  33. <span className="ml-auto text-foreground-lighter">{item.rightIcon}</span>
  34. )}
  35. </span>
  36. )
  37. if (isDisabled) {
  38. return (
  39. <span
  40. key={item.key}
  41. className="block pointer-events-none opacity-50"
  42. aria-disabled="true"
  43. tabIndex={-1}
  44. >
  45. {content}
  46. </span>
  47. )
  48. }
  49. if (item.isExternal) {
  50. return (
  51. <a
  52. key={item.key}
  53. href={item.url}
  54. target="_blank"
  55. rel="noopener noreferrer"
  56. className="block"
  57. >
  58. {content}
  59. </a>
  60. )
  61. }
  62. return (
  63. <Link
  64. key={item.key}
  65. href={item.url}
  66. className="block"
  67. aria-current={isActive ? 'page' : undefined}
  68. >
  69. {content}
  70. </Link>
  71. )
  72. })}
  73. </div>
  74. </div>
  75. ))}
  76. </nav>
  77. )
  78. }