diff --git a/web/src/components/layout/PageLayout.jsx b/web/src/components/layout/PageLayout.jsx
index adb57306..f8cdfb0c 100644
--- a/web/src/components/layout/PageLayout.jsx
+++ b/web/src/components/layout/PageLayout.jsx
@@ -17,7 +17,7 @@ along with this program. If not, see .
For commercial licensing, please contact support@quantumnous.com
*/
-import HeaderBar from './headerbar/index.jsx';
+import HeaderBar from './headerbar';
import { Layout } from '@douyinfe/semi-ui';
import SiderBar from './SiderBar';
import App from '../../App';
diff --git a/web/src/components/layout/headerbar/ActionButtons.jsx b/web/src/components/layout/headerbar/ActionButtons.jsx
new file mode 100644
index 00000000..545b5227
--- /dev/null
+++ b/web/src/components/layout/headerbar/ActionButtons.jsx
@@ -0,0 +1,74 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import NewYearButton from './NewYearButton';
+import NotificationButton from './NotificationButton';
+import ThemeToggle from './ThemeToggle';
+import LanguageSelector from './LanguageSelector';
+import UserArea from './UserArea';
+
+const ActionButtons = ({
+ isNewYear,
+ unreadCount,
+ onNoticeOpen,
+ theme,
+ onThemeToggle,
+ currentLang,
+ onLanguageChange,
+ userState,
+ isLoading,
+ isMobile,
+ isSelfUseMode,
+ logout,
+ navigate,
+ t,
+}) => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ActionButtons;
diff --git a/web/src/components/layout/headerbar/HeaderLogo.jsx b/web/src/components/layout/headerbar/HeaderLogo.jsx
new file mode 100644
index 00000000..73be0516
--- /dev/null
+++ b/web/src/components/layout/headerbar/HeaderLogo.jsx
@@ -0,0 +1,81 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Typography, Tag } from '@douyinfe/semi-ui';
+import SkeletonWrapper from '../components/SkeletonWrapper';
+
+const HeaderLogo = ({
+ isMobile,
+ isConsoleRoute,
+ logo,
+ logoLoaded,
+ isLoading,
+ systemName,
+ isSelfUseMode,
+ isDemoSiteMode,
+ t,
+}) => {
+ if (isMobile && isConsoleRoute) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+};
+
+export default HeaderLogo;
diff --git a/web/src/components/layout/headerbar/LanguageSelector.jsx b/web/src/components/layout/headerbar/LanguageSelector.jsx
new file mode 100644
index 00000000..cbfd69b3
--- /dev/null
+++ b/web/src/components/layout/headerbar/LanguageSelector.jsx
@@ -0,0 +1,59 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Button, Dropdown } from '@douyinfe/semi-ui';
+import { Languages } from 'lucide-react';
+import { CN, GB } from 'country-flag-icons/react/3x2';
+
+const LanguageSelector = ({ currentLang, onLanguageChange, t }) => {
+ return (
+
+ onLanguageChange('zh')}
+ className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'zh' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`}
+ >
+
+ 中文
+
+ onLanguageChange('en')}
+ className={`!flex !items-center !gap-2 !px-3 !py-1.5 !text-sm !text-semi-color-text-0 dark:!text-gray-200 ${currentLang === 'en' ? '!bg-semi-color-primary-light-default dark:!bg-blue-600 !font-semibold' : 'hover:!bg-semi-color-fill-1 dark:hover:!bg-gray-600'}`}
+ >
+
+ English
+
+
+ }
+ >
+ }
+ aria-label={t('切换语言')}
+ theme='borderless'
+ type='tertiary'
+ className='!p-1.5 !text-current focus:!bg-semi-color-fill-1 dark:focus:!bg-gray-700 !rounded-full !bg-semi-color-fill-0 dark:!bg-semi-color-fill-1 hover:!bg-semi-color-fill-1 dark:hover:!bg-semi-color-fill-2'
+ />
+
+ );
+};
+
+export default LanguageSelector;
diff --git a/web/src/components/layout/headerbar/MobileMenuButton.jsx b/web/src/components/layout/headerbar/MobileMenuButton.jsx
new file mode 100644
index 00000000..7cf7e4aa
--- /dev/null
+++ b/web/src/components/layout/headerbar/MobileMenuButton.jsx
@@ -0,0 +1,56 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Button } from '@douyinfe/semi-ui';
+import { IconClose, IconMenu } from '@douyinfe/semi-icons';
+
+const MobileMenuButton = ({
+ isConsoleRoute,
+ isMobile,
+ drawerOpen,
+ collapsed,
+ onToggle,
+ t,
+}) => {
+ if (!isConsoleRoute || !isMobile) {
+ return null;
+ }
+
+ return (
+
+ ) : (
+
+ )
+ }
+ aria-label={
+ (isMobile ? drawerOpen : collapsed) ? t('关闭侧边栏') : t('打开侧边栏')
+ }
+ onClick={onToggle}
+ theme='borderless'
+ type='tertiary'
+ className='!p-2 !text-current focus:!bg-semi-color-fill-1 dark:focus:!bg-gray-700'
+ />
+ );
+};
+
+export default MobileMenuButton;
diff --git a/web/src/components/layout/headerbar/Navigation.jsx b/web/src/components/layout/headerbar/Navigation.jsx
new file mode 100644
index 00000000..e2a4a696
--- /dev/null
+++ b/web/src/components/layout/headerbar/Navigation.jsx
@@ -0,0 +1,88 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import SkeletonWrapper from '../components/SkeletonWrapper';
+
+const Navigation = ({
+ mainNavLinks,
+ isMobile,
+ isLoading,
+ userState,
+ pricingRequireAuth,
+}) => {
+ const renderNavLinks = () => {
+ const baseClasses =
+ 'flex-shrink-0 flex items-center gap-1 font-semibold rounded-md transition-all duration-200 ease-in-out';
+ const hoverClasses = 'hover:text-semi-color-primary';
+ const spacingClasses = isMobile ? 'p-1' : 'p-2';
+
+ const commonLinkClasses = `${baseClasses} ${spacingClasses} ${hoverClasses}`;
+
+ return mainNavLinks.map((link) => {
+ const linkContent = {link.text};
+
+ if (link.isExternal) {
+ return (
+
+ {linkContent}
+
+ );
+ }
+
+ let targetPath = link.to;
+ if (link.itemKey === 'console' && !userState.user) {
+ targetPath = '/login';
+ }
+ if (link.itemKey === 'pricing' && pricingRequireAuth && !userState.user) {
+ targetPath = '/login';
+ }
+
+ return (
+
+ {linkContent}
+
+ );
+ });
+ };
+
+ return (
+
+ );
+};
+
+export default Navigation;
diff --git a/web/src/components/layout/headerbar/NewYearButton.jsx b/web/src/components/layout/headerbar/NewYearButton.jsx
new file mode 100644
index 00000000..4f007c51
--- /dev/null
+++ b/web/src/components/layout/headerbar/NewYearButton.jsx
@@ -0,0 +1,62 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Button, Dropdown } from '@douyinfe/semi-ui';
+import fireworks from 'react-fireworks';
+
+const NewYearButton = ({ isNewYear }) => {
+ if (!isNewYear) {
+ return null;
+ }
+
+ const handleNewYearClick = () => {
+ fireworks.init('root', {});
+ fireworks.start();
+ setTimeout(() => {
+ fireworks.stop();
+ }, 3000);
+ };
+
+ return (
+
+
+ Happy New Year!!! 🎉
+
+
+ }
+ >
+
+ );
+};
+
+export default NewYearButton;
diff --git a/web/src/components/layout/headerbar/NotificationButton.jsx b/web/src/components/layout/headerbar/NotificationButton.jsx
new file mode 100644
index 00000000..54ab9dd9
--- /dev/null
+++ b/web/src/components/layout/headerbar/NotificationButton.jsx
@@ -0,0 +1,46 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Button, Badge } from '@douyinfe/semi-ui';
+import { Bell } from 'lucide-react';
+
+const NotificationButton = ({ unreadCount, onNoticeOpen, t }) => {
+ const buttonProps = {
+ icon: ,
+ 'aria-label': t('系统公告'),
+ onClick: onNoticeOpen,
+ theme: 'borderless',
+ type: 'tertiary',
+ className:
+ '!p-1.5 !text-current focus:!bg-semi-color-fill-1 dark:focus:!bg-gray-700 !rounded-full !bg-semi-color-fill-0 dark:!bg-semi-color-fill-1 hover:!bg-semi-color-fill-1 dark:hover:!bg-semi-color-fill-2',
+ };
+
+ if (unreadCount > 0) {
+ return (
+
+
+
+ );
+ }
+
+ return ;
+};
+
+export default NotificationButton;
diff --git a/web/src/components/layout/headerbar/ThemeToggle.jsx b/web/src/components/layout/headerbar/ThemeToggle.jsx
new file mode 100644
index 00000000..45e7918d
--- /dev/null
+++ b/web/src/components/layout/headerbar/ThemeToggle.jsx
@@ -0,0 +1,109 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React, { useMemo } from 'react';
+import { Button, Dropdown } from '@douyinfe/semi-ui';
+import { Sun, Moon, Monitor } from 'lucide-react';
+import { useActualTheme } from '../../../context/Theme';
+
+const ThemeToggle = ({ theme, onThemeToggle, t }) => {
+ const actualTheme = useActualTheme();
+
+ const themeOptions = useMemo(
+ () => [
+ {
+ key: 'light',
+ icon: ,
+ buttonIcon: ,
+ label: t('浅色模式'),
+ description: t('始终使用浅色主题'),
+ },
+ {
+ key: 'dark',
+ icon: ,
+ buttonIcon: ,
+ label: t('深色模式'),
+ description: t('始终使用深色主题'),
+ },
+ {
+ key: 'auto',
+ icon: ,
+ buttonIcon: ,
+ label: t('自动模式'),
+ description: t('跟随系统主题设置'),
+ },
+ ],
+ [t],
+ );
+
+ const getItemClassName = (isSelected) =>
+ isSelected
+ ? '!bg-semi-color-primary-light-default !font-semibold'
+ : 'hover:!bg-semi-color-fill-1';
+
+ const currentButtonIcon = useMemo(() => {
+ const currentOption = themeOptions.find((option) => option.key === theme);
+ return currentOption?.buttonIcon || themeOptions[2].buttonIcon;
+ }, [theme, themeOptions]);
+
+ return (
+
+ {themeOptions.map((option) => (
+ onThemeToggle(option.key)}
+ className={getItemClassName(theme === option.key)}
+ >
+
+ >
+ )}
+
+ }
+ >
+
+
+ );
+};
+
+export default ThemeToggle;
diff --git a/web/src/components/layout/headerbar/UserArea.jsx b/web/src/components/layout/headerbar/UserArea.jsx
new file mode 100644
index 00000000..8ea70f47
--- /dev/null
+++ b/web/src/components/layout/headerbar/UserArea.jsx
@@ -0,0 +1,196 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Avatar, Button, Dropdown, Typography } from '@douyinfe/semi-ui';
+import { ChevronDown } from 'lucide-react';
+import {
+ IconExit,
+ IconUserSetting,
+ IconCreditCard,
+ IconKey,
+} from '@douyinfe/semi-icons';
+import { stringToColor } from '../../../helpers';
+import SkeletonWrapper from '../components/SkeletonWrapper';
+
+const UserArea = ({
+ userState,
+ isLoading,
+ isMobile,
+ isSelfUseMode,
+ logout,
+ navigate,
+ t,
+}) => {
+ if (isLoading) {
+ return (
+
+ );
+ }
+
+ if (userState.user) {
+ return (
+
+ {
+ navigate('/console/personal');
+ }}
+ className='!px-3 !py-1.5 !text-sm !text-semi-color-text-0 hover:!bg-semi-color-fill-1 dark:!text-gray-200 dark:hover:!bg-blue-500 dark:hover:!text-white'
+ >
+
+ );
+ }
+};
+
+export default UserArea;
diff --git a/web/src/components/layout/headerbar/index.jsx b/web/src/components/layout/headerbar/index.jsx
new file mode 100644
index 00000000..81b51d7f
--- /dev/null
+++ b/web/src/components/layout/headerbar/index.jsx
@@ -0,0 +1,132 @@
+/*
+Copyright (C) 2025 QuantumNous
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU Affero General Public License as
+published by the Free Software Foundation, either version 3 of the
+License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License
+along with this program. If not, see .
+
+For commercial licensing, please contact support@quantumnous.com
+*/
+
+import React from 'react';
+import { useHeaderBar } from '../../../hooks/common/useHeaderBar';
+import { useNotifications } from '../../../hooks/common/useNotifications';
+import { useNavigation } from '../../../hooks/common/useNavigation';
+import NoticeModal from '../NoticeModal';
+import MobileMenuButton from './MobileMenuButton';
+import HeaderLogo from './HeaderLogo';
+import Navigation from './Navigation';
+import ActionButtons from './ActionButtons';
+
+const HeaderBar = ({ onMobileMenuToggle, drawerOpen }) => {
+ const {
+ userState,
+ statusState,
+ isMobile,
+ collapsed,
+ logoLoaded,
+ currentLang,
+ isLoading,
+ systemName,
+ logo,
+ isNewYear,
+ isSelfUseMode,
+ docsLink,
+ isDemoSiteMode,
+ isConsoleRoute,
+ theme,
+ headerNavModules,
+ pricingRequireAuth,
+ logout,
+ handleLanguageChange,
+ handleThemeToggle,
+ handleMobileMenuToggle,
+ navigate,
+ t,
+ } = useHeaderBar({ onMobileMenuToggle, drawerOpen });
+
+ const {
+ noticeVisible,
+ unreadCount,
+ handleNoticeOpen,
+ handleNoticeClose,
+ getUnreadKeys,
+ } = useNotifications(statusState);
+
+ const { mainNavLinks } = useNavigation(t, docsLink, headerNavModules);
+
+ return (
+
+ 0 ? 'system' : 'inApp'}
+ unreadKeys={getUnreadKeys()}
+ />
+
+