Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

index.tsx 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import React, { useEffect, useState } from 'react'
  2. import { usePathname } from 'next/navigation'
  3. import { useShallow } from 'zustand/react/shallow'
  4. import { RiLayoutLeft2Line, RiLayoutRight2Line } from '@remixicon/react'
  5. import NavLink from './navLink'
  6. import type { NavIcon } from './navLink'
  7. import AppBasic from './basic'
  8. import AppInfo from './app-info'
  9. import DatasetInfo from './dataset-info'
  10. import AppSidebarDropdown from './app-sidebar-dropdown'
  11. import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
  12. import { useStore as useAppStore } from '@/app/components/app/store'
  13. import { useEventEmitterContextContext } from '@/context/event-emitter'
  14. import cn from '@/utils/classnames'
  15. export type IAppDetailNavProps = {
  16. iconType?: 'app' | 'dataset' | 'notion'
  17. title: string
  18. desc: string
  19. isExternal?: boolean
  20. icon: string
  21. icon_background: string | null
  22. navigation: Array<{
  23. name: string
  24. href: string
  25. icon: NavIcon
  26. selectedIcon: NavIcon
  27. }>
  28. extraInfo?: (modeState: string) => React.ReactNode
  29. }
  30. const AppDetailNav = ({ title, desc, isExternal, icon, icon_background, navigation, extraInfo, iconType = 'app' }: IAppDetailNavProps) => {
  31. const { appSidebarExpand, setAppSiderbarExpand } = useAppStore(useShallow(state => ({
  32. appSidebarExpand: state.appSidebarExpand,
  33. setAppSiderbarExpand: state.setAppSiderbarExpand,
  34. })))
  35. const media = useBreakpoints()
  36. const isMobile = media === MediaType.mobile
  37. const expand = appSidebarExpand === 'expand'
  38. const handleToggle = (state: string) => {
  39. setAppSiderbarExpand(state === 'expand' ? 'collapse' : 'expand')
  40. }
  41. // // Check if the current path is a workflow canvas & fullscreen
  42. const pathname = usePathname()
  43. const inWorkflowCanvas = pathname.endsWith('/workflow')
  44. const workflowCanvasMaximize = localStorage.getItem('workflow-canvas-maximize') === 'true'
  45. const [hideHeader, setHideHeader] = useState(workflowCanvasMaximize)
  46. const { eventEmitter } = useEventEmitterContextContext()
  47. eventEmitter?.useSubscription((v: any) => {
  48. if (v?.type === 'workflow-canvas-maximize')
  49. setHideHeader(v.payload)
  50. })
  51. useEffect(() => {
  52. if (appSidebarExpand) {
  53. localStorage.setItem('app-detail-collapse-or-expand', appSidebarExpand)
  54. setAppSiderbarExpand(appSidebarExpand)
  55. }
  56. }, [appSidebarExpand, setAppSiderbarExpand])
  57. if (inWorkflowCanvas && hideHeader) {
  58. return (
  59. <div className='flex w-0 shrink-0'>
  60. <AppSidebarDropdown navigation={navigation} />
  61. </div>
  62. )
  63. }
  64. return (
  65. <div
  66. className={`
  67. flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all
  68. ${expand ? 'w-[216px]' : 'w-14'}
  69. `}
  70. >
  71. <div
  72. className={`
  73. shrink-0
  74. ${expand ? 'p-2' : 'p-1'}
  75. `}
  76. >
  77. {iconType === 'app' && (
  78. <AppInfo expand={expand} />
  79. )}
  80. {iconType === 'dataset' && (
  81. <DatasetInfo
  82. name={title}
  83. description={desc}
  84. isExternal={isExternal}
  85. expand={expand}
  86. extraInfo={extraInfo && extraInfo(appSidebarExpand)}
  87. />
  88. )}
  89. {!['app', 'dataset'].includes(iconType) && (
  90. <AppBasic
  91. mode={appSidebarExpand}
  92. iconType={iconType}
  93. icon={icon}
  94. icon_background={icon_background}
  95. name={title}
  96. type={desc}
  97. isExternal={isExternal}
  98. />
  99. )}
  100. </div>
  101. <div className='px-4'>
  102. <div className={cn('mx-auto mt-1 h-[1px] bg-divider-subtle', !expand && 'w-6')} />
  103. </div>
  104. <nav
  105. className={`
  106. grow space-y-1
  107. ${expand ? 'p-4' : 'px-2.5 py-4'}
  108. `}
  109. >
  110. {navigation.map((item, index) => {
  111. return (
  112. <NavLink key={index} mode={appSidebarExpand} iconMap={{ selected: item.selectedIcon, normal: item.icon }} name={item.name} href={item.href} />
  113. )
  114. })}
  115. </nav>
  116. {
  117. !isMobile && (
  118. <div
  119. className={`
  120. shrink-0 py-3
  121. ${expand ? 'px-6' : 'px-4'}
  122. `}
  123. >
  124. <div
  125. className='flex h-6 w-6 cursor-pointer items-center justify-center'
  126. onClick={() => handleToggle(appSidebarExpand)}
  127. >
  128. {
  129. expand
  130. ? <RiLayoutRight2Line className='h-5 w-5 text-components-menu-item-text' />
  131. : <RiLayoutLeft2Line className='h-5 w-5 text-components-menu-item-text' />
  132. }
  133. </div>
  134. </div>
  135. )
  136. }
  137. </div>
  138. )
  139. }
  140. export default React.memo(AppDetailNav)