diff --git a/web/src/components/HeaderBar.js b/web/src/components/HeaderBar.js index de2401a1..1971ca3a 100644 --- a/web/src/components/HeaderBar.js +++ b/web/src/components/HeaderBar.js @@ -3,166 +3,82 @@ import { Link, useNavigate } from 'react-router-dom'; import { UserContext } from '../context/User'; import { useSetTheme, useTheme } from '../context/Theme'; import { useTranslation } from 'react-i18next'; - -import { API, getLogo, getSystemName, isMobile, showSuccess } from '../helpers'; -import '../index.css'; - +import { API, getLogo, getSystemName, showSuccess } from '../helpers'; import fireworks from 'react-fireworks'; +import { CN, GB } from 'country-flag-icons/react/3x2'; import { IconClose, - IconHelpCircle, - IconHome, - IconHomeStroked, - IconIndentLeft, - IconComment, - IconKey, IconMenu, - IconNoteMoneyStroked, - IconPriceTag, - IconUser, IconLanguage, - IconInfoCircle, - IconCreditCard, - IconTerminal, + IconChevronDown, + IconSun, + IconMoon, } from '@douyinfe/semi-icons'; import { Avatar, Button, Dropdown, - Layout, - Nav, - Switch, Tag, + Typography, + Skeleton, } from '@douyinfe/semi-ui'; import { stringToColor } from '../helpers/render'; -import Text from '@douyinfe/semi-ui/lib/es/typography/text'; -import { StyleContext } from '../context/Style/index.js'; import { StatusContext } from '../context/Status/index.js'; - -// 自定义顶部栏样式 -const headerStyle = { - boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)', - borderBottom: '1px solid var(--semi-color-border)', - background: 'var(--semi-color-bg-0)', - transition: 'all 0.3s ease', - width: '100%', -}; - -// 自定义顶部栏按钮样式 -const headerItemStyle = { - borderRadius: '4px', - margin: '0 4px', - transition: 'all 0.3s ease', -}; - -// 自定义顶部栏按钮悬停样式 -const headerItemHoverStyle = { - backgroundColor: 'var(--semi-color-primary-light-default)', - color: 'var(--semi-color-primary)', -}; - -// 自定义顶部栏Logo样式 -const logoStyle = { - display: 'flex', - alignItems: 'center', - gap: '10px', - padding: '0 10px', - height: '100%', -}; - -// 自定义顶部栏系统名称样式 -const systemNameStyle = { - fontWeight: 'bold', - fontSize: '18px', - background: - 'linear-gradient(45deg, var(--semi-color-primary), var(--semi-color-secondary))', - WebkitBackgroundClip: 'text', - WebkitTextFillColor: 'transparent', - padding: '0 5px', -}; - -// 自定义顶部栏按钮图标样式 -const headerIconStyle = { - fontSize: '18px', - transition: 'all 0.3s ease', -}; - -// 自定义头像样式 -const avatarStyle = { - margin: '4px', - cursor: 'pointer', - boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)', - transition: 'all 0.3s ease', -}; - -// 自定义下拉菜单样式 -const dropdownStyle = { - borderRadius: '8px', - boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)', - overflow: 'hidden', -}; - -// 自定义主题切换开关样式 -const switchStyle = { - margin: '0 8px', -}; +import { StyleContext } from '../context/Style/index.js'; const HeaderBar = () => { const { t, i18n } = useTranslation(); const [userState, userDispatch] = useContext(UserContext); - const [styleState, styleDispatch] = useContext(StyleContext); const [statusState, statusDispatch] = useContext(StatusContext); + const [styleState, styleDispatch] = useContext(StyleContext); + const [isLoading, setIsLoading] = useState(true); let navigate = useNavigate(); const [currentLang, setCurrentLang] = useState(i18n.language); + const [mobileMenuOpen, setMobileMenuOpen] = useState(false); const systemName = getSystemName(); const logo = getLogo(); const currentDate = new Date(); - // enable fireworks on new year(1.1 and 2.9-2.24) const isNewYear = currentDate.getMonth() === 0 && currentDate.getDate() === 1; - // Check if self-use mode is enabled const isSelfUseMode = statusState?.status?.self_use_mode_enabled || false; const docsLink = statusState?.status?.docs_link || ''; const isDemoSiteMode = statusState?.status?.demo_site_enabled || false; - let buttons = [ + const theme = useTheme(); + const setTheme = useSetTheme(); + + const mainNavLinks = [ { text: t('首页'), itemKey: 'home', to: '/', - icon: , }, { text: t('控制台'), itemKey: 'detail', - to: '/', - icon: , + to: '/detail', }, { text: t('定价'), itemKey: 'pricing', to: '/pricing', - icon: , }, - // Only include the docs button if docsLink exists ...(docsLink ? [ - { - text: t('文档'), - itemKey: 'docs', - isExternal: true, - externalLink: docsLink, - icon: , - }, - ] + { + text: t('文档'), + itemKey: 'docs', + isExternal: true, + externalLink: docsLink, + }, + ] : []), { text: t('关于'), itemKey: 'about', to: '/about', - icon: , }, ]; @@ -172,6 +88,7 @@ const HeaderBar = () => { userDispatch({ type: 'logout' }); localStorage.removeItem('user'); navigate('/login'); + setMobileMenuOpen(false); } const handleNewYearClick = () => { @@ -179,31 +96,24 @@ const HeaderBar = () => { fireworks.start(); setTimeout(() => { fireworks.stop(); - setTimeout(() => { - window.location.reload(); - }, 10000); }, 3000); }; - const theme = useTheme(); - const setTheme = useSetTheme(); - useEffect(() => { if (theme === 'dark') { document.body.setAttribute('theme-mode', 'dark'); + document.documentElement.classList.add('dark'); } else { document.body.removeAttribute('theme-mode'); + document.documentElement.classList.remove('dark'); } - // 发送当前主题模式给子页面 + const iframe = document.querySelector('iframe'); if (iframe) { iframe.contentWindow.postMessage({ themeMode: theme }, '*'); } - if (isNewYear) { - console.log('Happy New Year!'); - } - }, [theme]); + }, [theme, isNewYear]); useEffect(() => { const handleLanguageChanged = (lng) => { @@ -215,279 +125,309 @@ const HeaderBar = () => { }; i18n.on('languageChanged', handleLanguageChanged); - return () => { i18n.off('languageChanged', handleLanguageChanged); }; }, [i18n]); + useEffect(() => { + // 模拟加载用户状态的过程 + const timer = setTimeout(() => { + setIsLoading(false); + }, 500); + return () => clearTimeout(timer); + }, []); + const handleLanguageChange = (lang) => { i18n.changeLanguage(lang); + setMobileMenuOpen(false); + }; + + const handleNavLinkClick = (itemKey) => { + if (itemKey === 'home') { + styleDispatch({ type: 'SET_INNER_PADDING', payload: false }); + styleDispatch({ type: 'SET_SIDER', payload: false }); + } else { + styleDispatch({ type: 'SET_INNER_PADDING', payload: true }); + if (!styleState.isMobile) { + styleDispatch({ type: 'SET_SIDER', payload: true }); + } + } + setMobileMenuOpen(false); + }; + + const renderNavLinks = (isMobileView = false) => + mainNavLinks.map((link) => { + const commonLinkClasses = isMobileView + ? 'flex items-center gap-1 p-3 w-full text-gray-700 dark:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-md transition-colors font-semibold' + : 'flex items-center gap-1 p-2 text-sm text-gray-700 dark:text-gray-300 hover:text-blue-600 dark:hover:text-blue-400 transition-colors rounded-md font-semibold'; + + const linkContent = ( + {link.text} + ); + + if (link.isExternal) { + return ( + handleNavLinkClick(link.itemKey)} + > + {linkContent} + + ); + } + return ( + handleNavLinkClick(link.itemKey)} + > + {linkContent} + + ); + }); + + const renderUserArea = () => { + if (isLoading) { + return ( +
+ +
+ +
+
+ ); + } + + if (userState.user) { + return ( + + + {t('退出')} + + + } + > + + + ); + } else { + const showRegisterButton = !isSelfUseMode; + + const commonSizingAndLayoutClass = "flex items-center justify-center !py-[10px] !px-1.5"; + + const loginButtonSpecificStyling = "!bg-semi-color-fill-0 dark:!bg-semi-color-fill-1 hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-700 transition-colors"; + let loginButtonClasses = `${commonSizingAndLayoutClass} ${loginButtonSpecificStyling}`; + + let registerButtonClasses = `${commonSizingAndLayoutClass}`; + + const loginButtonTextSpanClass = "!text-xs !text-semi-color-text-1 dark:!text-gray-300 !p-1.5"; + const registerButtonTextSpanClass = "!text-xs !text-white !p-1.5"; + + if (showRegisterButton) { + if (styleState.isMobile) { + loginButtonClasses += " !rounded-full"; + } else { + loginButtonClasses += " !rounded-l-full !rounded-r-none"; + } + registerButtonClasses += " !rounded-r-full !rounded-l-none"; + } else { + loginButtonClasses += " !rounded-full"; + } + + return ( +
+ handleNavLinkClick('login')} className="flex"> + + + {showRegisterButton && ( +
+ handleNavLinkClick('register')} className="flex -ml-px"> + + +
+ )} +
+ ); + } }; return ( - <> - -
- + {isSelfUseMode ? t('自用模式') : t('演示站点')} + +
+ )} + + + + +
+ {isNewYear && ( + + + Happy New Year!!! 🎉 + + + } + > +
-
- + + +
+
+ +
+
+ ); }; diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index 916329e7..6d1d6ae1 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -162,8 +162,8 @@ "聊天": "Chat", "注销成功!": "Logout successful!", "注销": "Logout", - "登录": "Login", - "注册": "Register", + "登录": "Sign in", + "注册": "Sign up", "加载{name}中...": "Loading {name}...", "未登录或登录已过期,请重新登录!": "Not logged in or session expired. Please login again!", "用户登录": "User Login",