HeaderBar.js 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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 { useTranslation } from 'react-i18next';
  6. import { API, getLogo, getSystemName, isMobile, showSuccess } from '../helpers';
  7. import '../index.css';
  8. import fireworks from 'react-fireworks';
  9. import {
  10. IconClose,
  11. IconHelpCircle,
  12. IconHome,
  13. IconHomeStroked, IconIndentLeft,
  14. IconKey, IconMenu,
  15. IconNoteMoneyStroked,
  16. IconPriceTag,
  17. IconUser,
  18. IconLanguage
  19. } from '@douyinfe/semi-icons';
  20. import { Avatar, Button, Dropdown, Layout, Nav, Switch } from '@douyinfe/semi-ui';
  21. import { stringToColor } from '../helpers/render';
  22. import Text from '@douyinfe/semi-ui/lib/es/typography/text';
  23. import { StyleContext } from '../context/Style/index.js';
  24. // HeaderBar Buttons
  25. let headerButtons = [
  26. {
  27. text: '关于',
  28. itemKey: 'about',
  29. to: '/about',
  30. icon: <IconHelpCircle />,
  31. },
  32. ];
  33. if (localStorage.getItem('chat_link')) {
  34. headerButtons.splice(1, 0, {
  35. name: '聊天',
  36. to: '/chat',
  37. icon: 'comments',
  38. });
  39. }
  40. const HeaderBar = () => {
  41. const { t, i18n } = useTranslation();
  42. const [userState, userDispatch] = useContext(UserContext);
  43. const [styleState, styleDispatch] = useContext(StyleContext);
  44. let navigate = useNavigate();
  45. const [currentLang, setCurrentLang] = useState(i18n.language);
  46. const systemName = getSystemName();
  47. const logo = getLogo();
  48. const currentDate = new Date();
  49. // enable fireworks on new year(1.1 and 2.9-2.24)
  50. const isNewYear =
  51. (currentDate.getMonth() === 0 && currentDate.getDate() === 1);
  52. let buttons = [
  53. {
  54. text: t('首页'),
  55. itemKey: 'home',
  56. to: '/',
  57. },
  58. {
  59. text: t('控制台'),
  60. itemKey: 'detail',
  61. to: '/',
  62. },
  63. {
  64. text: t('定价'),
  65. itemKey: 'pricing',
  66. to: '/pricing',
  67. },
  68. {
  69. text: t('关于'),
  70. itemKey: 'about',
  71. to: '/about',
  72. },
  73. ];
  74. async function logout() {
  75. await API.get('/api/user/logout');
  76. showSuccess(t('注销成功!'));
  77. userDispatch({ type: 'logout' });
  78. localStorage.removeItem('user');
  79. navigate('/login');
  80. }
  81. const handleNewYearClick = () => {
  82. fireworks.init('root', {});
  83. fireworks.start();
  84. setTimeout(() => {
  85. fireworks.stop();
  86. setTimeout(() => {
  87. window.location.reload();
  88. }, 10000);
  89. }, 3000);
  90. };
  91. const theme = useTheme();
  92. const setTheme = useSetTheme();
  93. useEffect(() => {
  94. if (theme === 'dark') {
  95. document.body.setAttribute('theme-mode', 'dark');
  96. }
  97. if (isNewYear) {
  98. console.log('Happy New Year!');
  99. }
  100. }, []);
  101. useEffect(() => {
  102. const handleLanguageChanged = (lng) => {
  103. setCurrentLang(lng);
  104. };
  105. i18n.on('languageChanged', handleLanguageChanged);
  106. return () => {
  107. i18n.off('languageChanged', handleLanguageChanged);
  108. };
  109. }, [i18n]);
  110. const handleLanguageChange = (lang) => {
  111. i18n.changeLanguage(lang);
  112. };
  113. return (
  114. <>
  115. <Layout>
  116. <div style={{ width: '100%' }}>
  117. <Nav
  118. className={'topnav'}
  119. mode={'horizontal'}
  120. renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
  121. const routerMap = {
  122. about: '/about',
  123. login: '/login',
  124. register: '/register',
  125. pricing: '/pricing',
  126. detail: '/detail',
  127. home: '/',
  128. };
  129. return (
  130. <div onClick={(e) => {
  131. if (props.itemKey === 'home') {
  132. styleDispatch({ type: 'SET_INNER_PADDING', payload: false });
  133. styleDispatch({ type: 'SET_SIDER', payload: false });
  134. } else {
  135. styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
  136. if (!styleState.isMobile) {
  137. styleDispatch({ type: 'SET_SIDER', payload: true });
  138. }
  139. }
  140. }}>
  141. <Link
  142. className="header-bar-text"
  143. style={{ textDecoration: 'none' }}
  144. to={routerMap[props.itemKey]}
  145. >
  146. {itemElement}
  147. </Link>
  148. </div>
  149. );
  150. }}
  151. selectedKeys={[]}
  152. // items={headerButtons}
  153. onSelect={(key) => {}}
  154. header={styleState.isMobile?{
  155. logo: (
  156. <>
  157. {
  158. !styleState.showSider ?
  159. <Button icon={<IconMenu />} theme="light" aria-label={t('展开侧边栏')} onClick={
  160. () => styleDispatch({ type: 'SET_SIDER', payload: true })
  161. } />:
  162. <Button icon={<IconIndentLeft />} theme="light" aria-label={t('闭侧边栏')} onClick={
  163. () => styleDispatch({ type: 'SET_SIDER', payload: false })
  164. } />
  165. }
  166. </>
  167. ),
  168. }:{
  169. logo: (
  170. <img src={logo} alt='logo' />
  171. ),
  172. text: systemName,
  173. }}
  174. items={buttons}
  175. footer={
  176. <>
  177. {isNewYear && (
  178. // happy new year
  179. <Dropdown
  180. position='bottomRight'
  181. render={
  182. <Dropdown.Menu>
  183. <Dropdown.Item onClick={handleNewYearClick}>
  184. Happy New Year!!!
  185. </Dropdown.Item>
  186. </Dropdown.Menu>
  187. }
  188. >
  189. <Nav.Item itemKey={'new-year'} text={'🏮'} />
  190. </Dropdown>
  191. )}
  192. {/* <Nav.Item itemKey={'about'} icon={<IconHelpCircle />} /> */}
  193. <>
  194. <Switch
  195. checkedText='🌞'
  196. size={styleState.isMobile?'default':'large'}
  197. checked={theme === 'dark'}
  198. uncheckedText='🌙'
  199. onChange={(checked) => {
  200. setTheme(checked);
  201. }}
  202. />
  203. </>
  204. <Dropdown
  205. position='bottomRight'
  206. render={
  207. <Dropdown.Menu>
  208. <Dropdown.Item
  209. onClick={() => handleLanguageChange('zh')}
  210. type={currentLang === 'zh' ? 'primary' : 'tertiary'}
  211. >
  212. 中文
  213. </Dropdown.Item>
  214. <Dropdown.Item
  215. onClick={() => handleLanguageChange('en')}
  216. type={currentLang === 'en' ? 'primary' : 'tertiary'}
  217. >
  218. English
  219. </Dropdown.Item>
  220. </Dropdown.Menu>
  221. }
  222. >
  223. <Nav.Item
  224. itemKey={'language'}
  225. icon={<IconLanguage />}
  226. />
  227. </Dropdown>
  228. {userState.user ? (
  229. <>
  230. <Dropdown
  231. position='bottomRight'
  232. render={
  233. <Dropdown.Menu>
  234. <Dropdown.Item onClick={logout}>{t('退出')}</Dropdown.Item>
  235. </Dropdown.Menu>
  236. }
  237. >
  238. <Avatar
  239. size='small'
  240. color={stringToColor(userState.user.username)}
  241. style={{ margin: 4 }}
  242. >
  243. {userState.user.username[0]}
  244. </Avatar>
  245. {styleState.isMobile?null:<Text>{userState.user.username}</Text>}
  246. </Dropdown>
  247. </>
  248. ) : (
  249. <>
  250. <Nav.Item
  251. itemKey={'login'}
  252. text={!styleState.isMobile?t('登录'):null}
  253. icon={<IconUser />}
  254. />
  255. {
  256. !styleState.isMobile && (
  257. <Nav.Item
  258. itemKey={'register'}
  259. text={t('注册')}
  260. icon={<IconKey />}
  261. />
  262. )
  263. }
  264. </>
  265. )}
  266. </>
  267. }
  268. ></Nav>
  269. </div>
  270. </Layout>
  271. </>
  272. );
  273. };
  274. export default HeaderBar;