index.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. 'use client'
  2. import { useEffect, useState } from 'react'
  3. import type { FC } from 'react'
  4. import { useTranslation } from 'react-i18next'
  5. import { useSelectedLayoutSegment } from 'next/navigation'
  6. import classNames from 'classnames'
  7. import { CommandLineIcon } from '@heroicons/react/24/solid'
  8. import Link from 'next/link'
  9. import AccountDropdown from './account-dropdown'
  10. import AppNav from './app-nav'
  11. import DatasetNav from './dataset-nav'
  12. import s from './index.module.css'
  13. import type { GithubRepo, LangGeniusVersionResponse, UserProfileResponse } from '@/models/common'
  14. import { WorkspaceProvider } from '@/context/workspace-context'
  15. import { Grid01 } from '@/app/components/base/icons/src/vender/line/layout'
  16. import { Grid01 as Grid01Solid } from '@/app/components/base/icons/src/vender/solid/layout'
  17. import { PuzzlePiece01 } from '@/app/components/base/icons/src/vender/line/development'
  18. import { PuzzlePiece01 as PuzzlePiece01Solid } from '@/app/components/base/icons/src/vender/solid/development'
  19. export type IHeaderProps = {
  20. userProfile: UserProfileResponse
  21. onLogout: () => void
  22. langeniusVersionInfo: LangGeniusVersionResponse
  23. isBordered: boolean
  24. }
  25. const navClassName = `
  26. flex items-center relative mr-3 px-3 h-8 rounded-xl
  27. font-medium text-sm
  28. cursor-pointer
  29. `
  30. const headerEnvClassName: { [k: string]: string } = {
  31. DEVELOPMENT: 'bg-[#FEC84B] border-[#FDB022] text-[#93370D]',
  32. TESTING: 'bg-[#A5F0FC] border-[#67E3F9] text-[#164C63]',
  33. }
  34. const Header: FC<IHeaderProps> = ({
  35. userProfile,
  36. onLogout,
  37. langeniusVersionInfo,
  38. isBordered,
  39. }) => {
  40. const { t } = useTranslation()
  41. const showEnvTag = langeniusVersionInfo.current_env === 'TESTING' || langeniusVersionInfo.current_env === 'DEVELOPMENT'
  42. const selectedSegment = useSelectedLayoutSegment()
  43. const isPluginsComingSoon = selectedSegment === 'plugins-coming-soon'
  44. const isExplore = selectedSegment === 'explore'
  45. const [starCount, setStarCount] = useState(0)
  46. useEffect(() => {
  47. globalThis.fetch('https://api.github.com/repos/langgenius/dify').then(res => res.json()).then((data: GithubRepo) => {
  48. setStarCount(data.stargazers_count)
  49. })
  50. }, [])
  51. return (
  52. <div className={classNames(
  53. 'sticky top-0 left-0 right-0 z-20 flex bg-gray-100 grow-0 shrink-0 basis-auto h-14',
  54. s.header,
  55. isBordered ? 'border-b border-gray-200' : '',
  56. )}
  57. >
  58. <div className={classNames(
  59. s[`header-${langeniusVersionInfo.current_env}`],
  60. 'flex flex-1 items-center justify-between px-4',
  61. )}>
  62. <div className='flex items-center'>
  63. <Link href="/apps" className='flex items-center mr-4'>
  64. <div className={s.logo} />
  65. </Link>
  66. {
  67. starCount > 0 && (
  68. <Link
  69. href='https://github.com/langgenius/dify'
  70. target='_blank'
  71. className='flex items-center leading-[18px] border border-gray-200 rounded-md text-xs text-gray-700 font-semibold overflow-hidden'>
  72. <div className='flex items-center px-2 py-1 bg-gray-100'>
  73. <div className={`${s['github-icon']} mr-1 rounded-full`} />
  74. Star
  75. </div>
  76. <div className='px-2 py-1 bg-white border-l border-gray-200'>{`${starCount}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
  77. </Link>
  78. )
  79. }
  80. </div>
  81. <div className='flex items-center'>
  82. <Link href="/explore/apps" className={classNames(
  83. navClassName, 'group',
  84. isExplore && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
  85. isExplore ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
  86. )}>
  87. {
  88. isExplore
  89. ? <Grid01Solid className='mr-2 w-4 h-4' />
  90. : <Grid01 className='mr-2 w-4 h-4' />
  91. }
  92. {t('common.menus.explore')}
  93. </Link>
  94. <AppNav />
  95. <Link href="/plugins-coming-soon" className={classNames(
  96. navClassName, 'group',
  97. isPluginsComingSoon && 'bg-white shadow-[0_2px_5px_-1px_rgba(0,0,0,0.05),0_2px_4px_-2px_rgba(0,0,0,0.05)]',
  98. isPluginsComingSoon ? 'text-primary-600' : 'text-gray-500 hover:bg-gray-200',
  99. )}>
  100. {
  101. isPluginsComingSoon
  102. ? <PuzzlePiece01Solid className='mr-2 w-4 h-4' />
  103. : <PuzzlePiece01 className='mr-2 w-4 h-4' />
  104. }
  105. {t('common.menus.plugins')}
  106. </Link>
  107. <DatasetNav />
  108. </div>
  109. <div className='flex items-center flex-shrink-0'>
  110. {
  111. showEnvTag && (
  112. <div className={`
  113. flex items-center h-[22px] mr-4 rounded-md px-2 text-xs font-medium border
  114. ${headerEnvClassName[langeniusVersionInfo.current_env]}
  115. `}>
  116. {
  117. langeniusVersionInfo.current_env === 'TESTING' && (
  118. <>
  119. <div className={s['beaker-icon']} />
  120. {t('common.environment.testing')}
  121. </>
  122. )
  123. }
  124. {
  125. langeniusVersionInfo.current_env === 'DEVELOPMENT' && (
  126. <>
  127. <CommandLineIcon className='w-3 h-3 mr-1' />
  128. {t('common.environment.development')}
  129. </>
  130. )
  131. }
  132. </div>
  133. )
  134. }
  135. <WorkspaceProvider>
  136. <AccountDropdown userProfile={userProfile} onLogout={onLogout} langeniusVersionInfo={langeniusVersionInfo} />
  137. </WorkspaceProvider>
  138. </div>
  139. </div>
  140. </div>
  141. )
  142. }
  143. export default Header