mirror of
				https://github.com/csunny/DB-GPT.git
				synced 2025-10-30 14:19:18 +00:00 
			
		
		
		
	Co-authored-by: Fangyin Cheng <staneyffer@gmail.com> Co-authored-by: 谨欣 <echo.cmy@antgroup.com> Co-authored-by: 严志勇 <yanzhiyong@tiansuixiansheng.com> Co-authored-by: yanzhiyong <932374019@qq.com>
		
			
				
	
	
		
			114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { ChatContext } from '@/app/chat-context';
 | |
| import { DarkSvg, SunnySvg } from '@/components/icons';
 | |
| import UserBar from '@/new-components/layout/UserBar';
 | |
| import { STORAGE_LANG_KEY, STORAGE_THEME_KEY } from '@/utils/constants/index';
 | |
| import Icon, { GlobalOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons';
 | |
| import { Layout, Popover } from 'antd';
 | |
| import moment from 'moment';
 | |
| import Image from 'next/image';
 | |
| import Link from 'next/link';
 | |
| import React, { ReactNode, useCallback, useContext, useMemo, useState } from 'react';
 | |
| import { useTranslation } from 'react-i18next';
 | |
| 
 | |
| interface SettingItem {
 | |
|   key: string;
 | |
|   name: string;
 | |
|   icon: ReactNode;
 | |
|   onClick?: () => void;
 | |
|   placement?: 'top' | 'topLeft';
 | |
| }
 | |
| 
 | |
| const Sider: React.FC = () => {
 | |
|   const { mode, setMode } = useContext(ChatContext);
 | |
|   const { t, i18n } = useTranslation();
 | |
|   const [collapsed, setCollapsed] = useState<boolean>(false);
 | |
| 
 | |
|   // 切换主题
 | |
|   const handleToggleTheme = useCallback(() => {
 | |
|     const theme = mode === 'light' ? 'dark' : 'light';
 | |
|     setMode(theme);
 | |
|     localStorage.setItem(STORAGE_THEME_KEY, theme);
 | |
|   }, [mode, setMode]);
 | |
| 
 | |
|   // 切换语言
 | |
|   const handleChangeLang = useCallback(() => {
 | |
|     const language = i18n.language === 'en' ? 'zh' : 'en';
 | |
|     i18n.changeLanguage(language);
 | |
|     if (language === 'zh') {
 | |
|       moment.locale('zh-cn');
 | |
|     }
 | |
|     if (language === 'en') {
 | |
|       moment.locale('en');
 | |
|     }
 | |
|     localStorage.setItem(STORAGE_LANG_KEY, language);
 | |
|   }, [i18n]);
 | |
| 
 | |
|   // 展开或收起
 | |
|   const handleToggleMenu = useCallback(() => {
 | |
|     setCollapsed(!collapsed);
 | |
|   }, [collapsed]);
 | |
| 
 | |
|   const settings: SettingItem[] = useMemo(() => {
 | |
|     return [
 | |
|       {
 | |
|         key: 'theme',
 | |
|         name: t('Theme'),
 | |
|         icon: mode === 'dark' ? <Icon component={DarkSvg} /> : <Icon component={SunnySvg} />,
 | |
|         onClick: handleToggleTheme,
 | |
|       },
 | |
|       {
 | |
|         key: 'language',
 | |
|         name: t('language'),
 | |
|         icon: <GlobalOutlined />,
 | |
|         onClick: handleChangeLang,
 | |
|       },
 | |
|       {
 | |
|         key: 'fold',
 | |
|         name: t(collapsed ? 'Show_Sidebar' : 'Close_Sidebar'),
 | |
|         icon: collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />,
 | |
|         onClick: handleToggleMenu,
 | |
|       },
 | |
|     ];
 | |
|   }, [collapsed, handleChangeLang, handleToggleMenu, handleToggleTheme, mode, t]);
 | |
| 
 | |
|   return (
 | |
|     <Layout.Sider
 | |
|       theme={mode}
 | |
|       width={240}
 | |
|       collapsedWidth={80}
 | |
|       collapsible={true}
 | |
|       collapsed={collapsed}
 | |
|       trigger={null}
 | |
|       className='flex flex-1 flex-col h-full justify-between  bg-bar dark:bg-[#232734] px-4 pt-4'
 | |
|     >
 | |
|       {collapsed ? (
 | |
|         <></>
 | |
|       ) : (
 | |
|         <>
 | |
|           <Link href='/' className='flex items-center justify-center p-2 pb-4'>
 | |
|             <Image src='/logo_zh_latest.png' alt='DB-GPT' width={180} height={40} />
 | |
|           </Link>
 | |
|           <div></div>
 | |
|           <div className='flex flex-col'>
 | |
|             <UserBar />
 | |
|             <div className='flex items-start justify-between border-t border-dashed border-gray-200 dark:border-gray-700'>
 | |
|               {settings.map(item => (
 | |
|                 <Popover key={item.key} content={item.name}>
 | |
|                   <div
 | |
|                     className='flex-1 flex items-center justify-center cursor-pointer text-xl'
 | |
|                     onClick={item.onClick}
 | |
|                   >
 | |
|                     {item.icon}
 | |
|                   </div>
 | |
|                 </Popover>
 | |
|               ))}
 | |
|             </div>
 | |
|           </div>
 | |
|         </>
 | |
|       )}
 | |
|     </Layout.Sider>
 | |
|   );
 | |
| };
 | |
| 
 | |
| export default Sider;
 |