HeaderBar.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import React, { useContext, useEffect, useState } from 'react';
  2. import { Link, useNavigate } from 'react-router-dom';
  3. import { UserContext } from '../context/User';
  4. import { useSetTheme, useTheme } from '../context/Theme';
  5. import { API, getLogo, getSystemName, isMobile, showSuccess } from '../helpers';
  6. import '../index.css';
  7. import fireworks from 'react-fireworks';
  8. import {
  9. IconHelpCircle,
  10. IconHome,
  11. IconHomeStroked,
  12. IconComment,
  13. IconKey,
  14. IconNoteMoneyStroked,
  15. IconPriceTag,
  16. IconUser
  17. } from '@douyinfe/semi-icons';
  18. import { Avatar, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
  19. import { stringToColor } from '../helpers/render';
  20. import Text from '@douyinfe/semi-ui/lib/es/typography/text';
  21. // HeaderBar Buttons
  22. let headerButtons = [
  23. {
  24. text: '关于',
  25. itemKey: 'about',
  26. to: '/about',
  27. icon: <IconHelpCircle />,
  28. },
  29. ];
  30. let buttons = [
  31. {
  32. text: '首页',
  33. itemKey: 'home',
  34. to: '/',
  35. icon: <IconHomeStroked />,
  36. onMouseEnter: (e) => {
  37. e.currentTarget.querySelector('svg').style.color = '#0064FA';
  38. },
  39. onMouseLeave: (e) => {
  40. e.currentTarget.querySelector('svg').style.color = 'black';
  41. },
  42. },
  43. // 增加 聊天 按钮
  44. {
  45. text: '聊天',
  46. itemKey: 'chat',
  47. to: '/chat',
  48. icon: <IconComment />,
  49. onMouseEnter: (e) => {
  50. e.currentTarget.querySelector('svg').style.color = '#0064FA';
  51. },
  52. onMouseLeave: (e) => {
  53. e.currentTarget.querySelector('svg').style.color = 'black';
  54. },
  55. className: localStorage.getItem('chat_link') && !isMobile() //移动端不显示
  56. ? 'semi-navigation-item-normal'
  57. : 'tableHiddle',
  58. },
  59. // {
  60. // text: '模型价格',
  61. // itemKey: 'pricing',
  62. // to: '/pricing',
  63. // icon: <IconNoteMoneyStroked />,
  64. // },
  65. ];
  66. if (localStorage.getItem('chat_link')) {
  67. headerButtons.splice(1, 0, {
  68. name: '聊天',
  69. to: '/chat',
  70. icon: 'comments',
  71. });
  72. }
  73. const HeaderBar = () => {
  74. const [userState, userDispatch] = useContext(UserContext);
  75. let navigate = useNavigate();
  76. const [showSidebar, setShowSidebar] = useState(false);
  77. const systemName = getSystemName();
  78. const logo = getLogo();
  79. const currentDate = new Date();
  80. // enable fireworks on new year(1.1 and 2.9-2.24)
  81. const isNewYear =
  82. (currentDate.getMonth() === 0 && currentDate.getDate() === 1) ||
  83. (currentDate.getMonth() === 1 &&
  84. currentDate.getDate() >= 9 &&
  85. currentDate.getDate() <= 24);
  86. async function logout() {
  87. setShowSidebar(false);
  88. await API.get('/api/user/logout');
  89. showSuccess('注销成功!');
  90. userDispatch({ type: 'logout' });
  91. localStorage.removeItem('user');
  92. navigate('/login');
  93. }
  94. const handleNewYearClick = () => {
  95. fireworks.init('root', {});
  96. fireworks.start();
  97. setTimeout(() => {
  98. fireworks.stop();
  99. setTimeout(() => {
  100. window.location.reload();
  101. }, 10000);
  102. }, 3000);
  103. };
  104. const theme = useTheme();
  105. const setTheme = useSetTheme();
  106. useEffect(() => {
  107. if (theme === 'dark') {
  108. document.body.setAttribute('theme-mode', 'dark');
  109. } else {
  110. document.body.removeAttribute('theme-mode');
  111. }
  112. // 发送当前主题模式给子页面
  113. const iframe = document.querySelector('iframe');
  114. if (iframe) {
  115. iframe.contentWindow.postMessage({ themeMode: theme }, '*');
  116. }
  117. if (isNewYear) {
  118. console.log('Happy New Year!');
  119. }
  120. }, [theme]); // 监听 theme-mode 的变化
  121. return (
  122. <>
  123. <Layout>
  124. <div style={{ width: '100%' }}>
  125. <Nav
  126. mode={'horizontal'}
  127. // bodyStyle={{ height: 100 }}
  128. renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
  129. const routerMap = {
  130. about: '/about',
  131. login: '/login',
  132. register: '/register',
  133. home: '/',
  134. chat: '/chat',
  135. };
  136. return (
  137. <Link
  138. style={{ textDecoration: 'none' }}
  139. to={routerMap[props.itemKey]}
  140. >
  141. {itemElement}
  142. </Link>
  143. );
  144. }}
  145. selectedKeys={[]}
  146. // items={headerButtons}
  147. onSelect={(key) => {}}
  148. header={isMobile()?{
  149. logo: (
  150. <img src={logo} alt='logo' style={{ marginRight: '0.75em' }} />
  151. ),
  152. }:{
  153. logo: (
  154. <img src={logo} alt='logo' />
  155. ),
  156. text: systemName,
  157. }}
  158. items={buttons}
  159. footer={
  160. <>
  161. {isNewYear && (
  162. // happy new year
  163. <Dropdown
  164. position='bottomRight'
  165. render={
  166. <Dropdown.Menu>
  167. <Dropdown.Item onClick={handleNewYearClick}>
  168. Happy New Year!!!
  169. </Dropdown.Item>
  170. </Dropdown.Menu>
  171. }
  172. >
  173. <Nav.Item itemKey={'new-year'} text={'🏮'} />
  174. </Dropdown>
  175. )}
  176. <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} />
  177. <>
  178. {!isMobile() && (
  179. <Switch
  180. checkedText='🌞'
  181. size={'large'}
  182. checked={theme === 'dark'}
  183. uncheckedText='🌙'
  184. onChange={(checked) => {
  185. setTheme(checked);
  186. }}
  187. />
  188. )}
  189. </>
  190. {userState.user ? (
  191. <>
  192. <Dropdown
  193. position='bottomRight'
  194. render={
  195. <Dropdown.Menu>
  196. <Dropdown.Item onClick={logout}>退出</Dropdown.Item>
  197. </Dropdown.Menu>
  198. }
  199. >
  200. <Avatar
  201. size='small'
  202. color={stringToColor(userState.user.username)}
  203. style={{ margin: 4 }}
  204. >
  205. {userState.user.username[0]}
  206. </Avatar>
  207. <span>{userState.user.username}</span>
  208. </Dropdown>
  209. </>
  210. ) : (
  211. <>
  212. <Nav.Item
  213. itemKey={'login'}
  214. text={'登录'}
  215. // icon={<IconKey />}
  216. />
  217. <Nav.Item
  218. itemKey={'register'}
  219. text={'注册'}
  220. icon={<IconUser />}
  221. />
  222. </>
  223. )}
  224. </>
  225. }
  226. ></Nav>
  227. </div>
  228. </Layout>
  229. </>
  230. );
  231. };
  232. export default HeaderBar;