Ver código fonte

refactor: Enhance UI layout and styling with responsive design improvements

1808837298@qq.com 1 ano atrás
pai
commit
d9cf0885f1

+ 92 - 11
web/src/components/HeaderBar.js

@@ -19,7 +19,10 @@ import {
   IconNoteMoneyStroked,
   IconNoteMoneyStroked,
   IconPriceTag,
   IconPriceTag,
   IconUser,
   IconUser,
-  IconLanguage
+  IconLanguage,
+  IconInfoCircle,
+  IconCreditCard,
+  IconTerminal
 } from '@douyinfe/semi-icons';
 } from '@douyinfe/semi-icons';
 import { Avatar, Button, Dropdown, Layout, Nav, Switch, Tag } from '@douyinfe/semi-ui';
 import { Avatar, Button, Dropdown, Layout, Nav, Switch, Tag } from '@douyinfe/semi-ui';
 import { stringToColor } from '../helpers/render';
 import { stringToColor } from '../helpers/render';
@@ -27,6 +30,73 @@ import Text from '@douyinfe/semi-ui/lib/es/typography/text';
 import { StyleContext } from '../context/Style/index.js';
 import { StyleContext } from '../context/Style/index.js';
 import { StatusContext } from '../context/Status/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'
+};
+
 const HeaderBar = () => {
 const HeaderBar = () => {
   const { t, i18n } = useTranslation();
   const { t, i18n } = useTranslation();
   const [userState, userDispatch] = useContext(UserContext);
   const [userState, userDispatch] = useContext(UserContext);
@@ -52,16 +122,19 @@ const HeaderBar = () => {
       text: t('首页'),
       text: t('首页'),
       itemKey: 'home',
       itemKey: 'home',
       to: '/',
       to: '/',
+      icon: <IconHome style={headerIconStyle} />,
     },
     },
     {
     {
       text: t('控制台'),
       text: t('控制台'),
       itemKey: 'detail',
       itemKey: 'detail',
       to: '/',
       to: '/',
+      icon: <IconTerminal style={headerIconStyle} />,
     },
     },
     {
     {
       text: t('定价'),
       text: t('定价'),
       itemKey: 'pricing',
       itemKey: 'pricing',
       to: '/pricing',
       to: '/pricing',
+      icon: <IconPriceTag style={headerIconStyle} />,
     },
     },
     // Only include the docs button if docsLink exists
     // Only include the docs button if docsLink exists
     ...(docsLink ? [{
     ...(docsLink ? [{
@@ -69,11 +142,13 @@ const HeaderBar = () => {
       itemKey: 'docs',
       itemKey: 'docs',
       isExternal: true,
       isExternal: true,
       externalLink: docsLink,
       externalLink: docsLink,
+      icon: <IconHelpCircle style={headerIconStyle} />,
     }] : []),
     }] : []),
     {
     {
       text: t('关于'),
       text: t('关于'),
       itemKey: 'about',
       itemKey: 'about',
       to: '/about',
       to: '/about',
+      icon: <IconInfoCircle style={headerIconStyle} />,
     },
     },
   ];
   ];
 
 
@@ -143,6 +218,9 @@ const HeaderBar = () => {
           <Nav
           <Nav
             className={'topnav'}
             className={'topnav'}
             mode={'horizontal'}
             mode={'horizontal'}
+            style={headerStyle}
+            itemStyle={headerItemStyle}
+            hoverStyle={headerItemHoverStyle}
             renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
             renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
               const routerMap = {
               const routerMap = {
                 about: '/about',
                 about: '/about',
@@ -224,11 +302,13 @@ const HeaderBar = () => {
               ),
               ),
             }:{
             }:{
               logo: (
               logo: (
-                <img src={logo} alt='logo' />
+                <div style={logoStyle}>
+                  <img src={logo} alt='logo' style={{ height: '28px' }} />
+                </div>
               ),
               ),
               text: (
               text: (
                 <div style={{ position: 'relative', display: 'inline-block' }}>
                 <div style={{ position: 'relative', display: 'inline-block' }}>
-                  {systemName}
+                  <span style={systemNameStyle}>{systemName}</span>
                   {(isSelfUseMode || isDemoSiteMode) && (
                   {(isSelfUseMode || isDemoSiteMode) && (
                     <Tag 
                     <Tag 
                       color={isSelfUseMode ? 'purple' : 'blue'}
                       color={isSelfUseMode ? 'purple' : 'blue'}
@@ -257,7 +337,7 @@ const HeaderBar = () => {
                   <Dropdown
                   <Dropdown
                     position='bottomRight'
                     position='bottomRight'
                     render={
                     render={
-                      <Dropdown.Menu>
+                      <Dropdown.Menu style={dropdownStyle}>
                         <Dropdown.Item onClick={handleNewYearClick}>
                         <Dropdown.Item onClick={handleNewYearClick}>
                           Happy New Year!!!
                           Happy New Year!!!
                         </Dropdown.Item>
                         </Dropdown.Item>
@@ -274,6 +354,7 @@ const HeaderBar = () => {
                     size={styleState.isMobile?'default':'large'}
                     size={styleState.isMobile?'default':'large'}
                     checked={theme === 'dark'}
                     checked={theme === 'dark'}
                     uncheckedText='🌙'
                     uncheckedText='🌙'
+                    style={switchStyle}
                     onChange={(checked) => {
                     onChange={(checked) => {
                       setTheme(checked);
                       setTheme(checked);
                     }}
                     }}
@@ -282,7 +363,7 @@ const HeaderBar = () => {
                 <Dropdown
                 <Dropdown
                   position='bottomRight'
                   position='bottomRight'
                   render={
                   render={
-                    <Dropdown.Menu>
+                    <Dropdown.Menu style={dropdownStyle}>
                       <Dropdown.Item
                       <Dropdown.Item
                         onClick={() => handleLanguageChange('zh')}
                         onClick={() => handleLanguageChange('zh')}
                         type={currentLang === 'zh' ? 'primary' : 'tertiary'}
                         type={currentLang === 'zh' ? 'primary' : 'tertiary'}
@@ -300,7 +381,7 @@ const HeaderBar = () => {
                 >
                 >
                   <Nav.Item
                   <Nav.Item
                     itemKey={'language'}
                     itemKey={'language'}
-                    icon={<IconLanguage />}
+                    icon={<IconLanguage style={headerIconStyle} />}
                   />
                   />
                 </Dropdown>
                 </Dropdown>
                 {userState.user ? (
                 {userState.user ? (
@@ -308,7 +389,7 @@ const HeaderBar = () => {
                     <Dropdown
                     <Dropdown
                       position='bottomRight'
                       position='bottomRight'
                       render={
                       render={
-                        <Dropdown.Menu>
+                        <Dropdown.Menu style={dropdownStyle}>
                           <Dropdown.Item onClick={logout}>{t('退出')}</Dropdown.Item>
                           <Dropdown.Item onClick={logout}>{t('退出')}</Dropdown.Item>
                         </Dropdown.Menu>
                         </Dropdown.Menu>
                       }
                       }
@@ -316,11 +397,11 @@ const HeaderBar = () => {
                       <Avatar
                       <Avatar
                         size='small'
                         size='small'
                         color={stringToColor(userState.user.username)}
                         color={stringToColor(userState.user.username)}
-                        style={{ margin: 4 }}
+                        style={avatarStyle}
                       >
                       >
                         {userState.user.username[0]}
                         {userState.user.username[0]}
                       </Avatar>
                       </Avatar>
-                      {styleState.isMobile?null:<Text>{userState.user.username}</Text>}
+                      {styleState.isMobile?null:<Text style={{ marginLeft: '4px', fontWeight: '500' }}>{userState.user.username}</Text>}
                     </Dropdown>
                     </Dropdown>
                   </>
                   </>
                 ) : (
                 ) : (
@@ -328,7 +409,7 @@ const HeaderBar = () => {
                     <Nav.Item
                     <Nav.Item
                       itemKey={'login'}
                       itemKey={'login'}
                       text={!styleState.isMobile?t('登录'):null}
                       text={!styleState.isMobile?t('登录'):null}
-                      icon={<IconUser />}
+                      icon={<IconUser style={headerIconStyle} />}
                     />
                     />
                     {
                     {
                       // Hide register option in self-use mode
                       // Hide register option in self-use mode
@@ -336,7 +417,7 @@ const HeaderBar = () => {
                         <Nav.Item
                         <Nav.Item
                           itemKey={'register'}
                           itemKey={'register'}
                           text={t('注册')}
                           text={t('注册')}
-                          icon={<IconKey />}
+                          icon={<IconKey style={headerIconStyle} />}
                         />
                         />
                       )
                       )
                     }
                     }

+ 44 - 7
web/src/components/PageLayout.js

@@ -62,20 +62,57 @@ const PageLayout = () => {
     if (savedLang) {
     if (savedLang) {
       i18n.changeLanguage(savedLang);
       i18n.changeLanguage(savedLang);
     }
     }
+    
+    // 默认显示侧边栏
+    styleDispatch({ type: 'SET_SIDER', payload: true });
   }, [i18n]);
   }, [i18n]);
 
 
+  // 获取侧边栏折叠状态
+  const isSidebarCollapsed = localStorage.getItem('default_collapse_sidebar') === 'true';
+
   return (
   return (
     <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
     <Layout style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
-      <Header>
+      <Header style={{ 
+        padding: 0, 
+        height: 'auto', 
+        lineHeight: 'normal', 
+        position: 'fixed', 
+        width: '100%', 
+        top: 0, 
+        zIndex: 100,
+        boxShadow: '0 1px 6px rgba(0, 0, 0, 0.08)'
+      }}>
         <HeaderBar />
         <HeaderBar />
       </Header>
       </Header>
-      <Layout style={{ flex: 1, overflow: 'hidden' }}>
-        <Sider>
-          {styleState.showSider ? <SiderBar /> : null}
-        </Sider>
-        <Layout>
+      <Layout style={{ marginTop: '56px', height: 'calc(100vh - 56px)', overflow: 'hidden' }}>
+        {styleState.showSider && (
+          <Sider style={{ 
+            height: 'calc(100vh - 56px)', 
+            position: 'fixed',
+            left: 0,
+            top: '56px',
+            zIndex: 90,
+            overflowY: 'auto',
+            overflowX: 'hidden',
+            width: 'auto',
+            background: 'transparent',
+            boxShadow: 'none',
+            border: 'none',
+            paddingRight: '5px'
+          }}>
+            <SiderBar />
+          </Sider>
+        )}
+        <Layout style={{ 
+          marginLeft: styleState.showSider ? (isSidebarCollapsed ? '60px' : '200px') : '0', 
+          transition: 'margin-left 0.3s ease'
+        }}>
           <Content
           <Content
-            style={{ overflowY: 'auto', padding: styleState.shouldInnerPadding? '24px': '0' }}
+            style={{ 
+              height: '100%',
+              overflowY: 'auto', 
+              padding: styleState.shouldInnerPadding? '24px': '0' 
+            }}
           >
           >
             <App />
             <App />
           </Content>
           </Content>

+ 129 - 29
web/src/components/SiderBar.js

@@ -1,5 +1,5 @@
 import React, { useContext, useEffect, useMemo, useState } from 'react';
 import React, { useContext, useEffect, useMemo, useState } from 'react';
-import { Link, useNavigate } from 'react-router-dom';
+import { Link, useNavigate, useLocation } from 'react-router-dom';
 import { UserContext } from '../context/User';
 import { UserContext } from '../context/User';
 import { StatusContext } from '../context/Status';
 import { StatusContext } from '../context/Status';
 import { useTranslation } from 'react-i18next';
 import { useTranslation } from 'react-i18next';
@@ -34,7 +34,34 @@ import { stringToColor } from '../helpers/render.js';
 import { useSetTheme, useTheme } from '../context/Theme/index.js';
 import { useSetTheme, useTheme } from '../context/Theme/index.js';
 import { StyleContext } from '../context/Style/index.js';
 import { StyleContext } from '../context/Style/index.js';
 
 
-// HeaderBar Buttons
+// 自定义侧边栏按钮样式
+const navItemStyle = {
+  borderRadius: '6px',
+  margin: '4px 8px',
+  transition: 'all 0.3s ease'
+};
+
+// 自定义侧边栏按钮悬停样式
+const navItemHoverStyle = {
+  backgroundColor: 'var(--semi-color-primary-light-default)',
+  color: 'var(--semi-color-primary)'
+};
+
+// 自定义侧边栏按钮选中样式
+const navItemSelectedStyle = {
+  backgroundColor: 'var(--semi-color-primary-light-default)',
+  color: 'var(--semi-color-primary)',
+  fontWeight: '600'
+};
+
+// 自定义图标样式
+const iconStyle = (itemKey, selectedKeys) => {
+  return {
+    fontSize: '18px',
+    color: selectedKeys.includes(itemKey) ? 'var(--semi-color-primary)' : 'var(--semi-color-text-2)',
+    transition: 'all 0.3s ease'
+  };
+};
 
 
 const SiderBar = () => {
 const SiderBar = () => {
   const { t } = useTranslation();
   const { t } = useTranslation();
@@ -46,8 +73,30 @@ const SiderBar = () => {
   const [selectedKeys, setSelectedKeys] = useState(['home']);
   const [selectedKeys, setSelectedKeys] = useState(['home']);
   const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
   const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
   const [chatItems, setChatItems] = useState([]);
   const [chatItems, setChatItems] = useState([]);
+  const [openedKeys, setOpenedKeys] = useState([]);
   const theme = useTheme();
   const theme = useTheme();
   const setTheme = useSetTheme();
   const setTheme = useSetTheme();
+  const location = useLocation();
+
+  // 预先计算所有可能的图标样式
+  const allItemKeys = useMemo(() => {
+    const keys = ['home', 'channel', 'token', 'redemption', 'topup', 'user', 'log', 'midjourney', 
+                 'setting', 'about', 'chat', 'detail', 'pricing', 'task', 'playground', 'personal'];
+    // 添加聊天项的keys
+    for (let i = 0; i < chatItems.length; i++) {
+      keys.push('chat' + i);
+    }
+    return keys;
+  }, [chatItems]);
+
+  // 使用useMemo一次性计算所有图标样式
+  const iconStyles = useMemo(() => {
+    const styles = {};
+    allItemKeys.forEach(key => {
+      styles[key] = iconStyle(key, selectedKeys);
+    });
+    return styles;
+  }, [allItemKeys, selectedKeys]);
 
 
   const routerMap = {
   const routerMap = {
     home: '/',
     home: '/',
@@ -190,11 +239,14 @@ const SiderBar = () => {
   );
   );
 
 
   useEffect(() => {
   useEffect(() => {
-    let localKey = window.location.pathname.split('/')[1];
-    if (localKey === '') {
-      localKey = 'home';
+    const currentPath = location.pathname;
+    const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
+    
+    if (matchingKey) {
+      setSelectedKeys([matchingKey]);
+    } else if (currentPath.startsWith('/chat/')) {
+      setSelectedKeys(['chat']);
     }
     }
-    setSelectedKeys([localKey]);
 
 
     let chats = localStorage.getItem('chats');
     let chats = localStorage.getItem('chats');
     if (chats) {
     if (chats) {
@@ -222,7 +274,7 @@ const SiderBar = () => {
     }
     }
 
 
     setIsCollapsed(localStorage.getItem('default_collapse_sidebar') === 'true');
     setIsCollapsed(localStorage.getItem('default_collapse_sidebar') === 'true');
-  }, []);
+  }, [location.pathname]);
 
 
   // Custom divider style
   // Custom divider style
   const dividerStyle = {
   const dividerStyle = {
@@ -235,21 +287,54 @@ const SiderBar = () => {
     padding: '8px 16px',
     padding: '8px 16px',
     color: 'var(--semi-color-text-2)',
     color: 'var(--semi-color-text-2)',
     fontSize: '12px',
     fontSize: '12px',
-    fontWeight: 'normal',
+    fontWeight: 'bold',
+    textTransform: 'uppercase',
+    letterSpacing: '0.5px',
   };
   };
 
 
   return (
   return (
     <>
     <>
       <Nav
       <Nav
-        style={{ maxWidth: 200, height: '100%' }}
+        className="custom-sidebar-nav"
+        style={{ 
+          width: isCollapsed ? '60px' : '200px',
+          height: '100%',
+          boxShadow: '0 1px 6px rgba(0, 0, 0, 0.08)',
+          borderRight: '1px solid var(--semi-color-border)',
+          background: 'var(--semi-color-bg-0)',
+          borderRadius: '0 8px 8px 0',
+          transition: 'all 0.3s ease',
+          position: 'relative',
+          zIndex: 95
+        }}
         defaultIsCollapsed={
         defaultIsCollapsed={
           localStorage.getItem('default_collapse_sidebar') === 'true'
           localStorage.getItem('default_collapse_sidebar') === 'true'
         }
         }
         isCollapsed={isCollapsed}
         isCollapsed={isCollapsed}
         onCollapseChange={(collapsed) => {
         onCollapseChange={(collapsed) => {
           setIsCollapsed(collapsed);
           setIsCollapsed(collapsed);
+          localStorage.setItem('default_collapse_sidebar', collapsed);
+          // 始终保持侧边栏显示,只是宽度不同
+          styleDispatch({ type: 'SET_SIDER', payload: true });
+          
+          // 确保在收起侧边栏时有选中的项目,避免不必要的计算
+          if (selectedKeys.length === 0) {
+            const currentPath = location.pathname;
+            const matchingKey = Object.keys(routerMap).find(key => routerMap[key] === currentPath);
+            
+            if (matchingKey) {
+              setSelectedKeys([matchingKey]);
+            } else if (currentPath.startsWith('/chat/')) {
+              setSelectedKeys(['chat']);
+            } else {
+              setSelectedKeys(['home']); // 默认选中首页
+            }
+          }
         }}
         }}
         selectedKeys={selectedKeys}
         selectedKeys={selectedKeys}
+        itemStyle={navItemStyle}
+        hoverStyle={navItemHoverStyle}
+        selectedStyle={navItemSelectedStyle}
         renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
         renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
           let chats = localStorage.getItem('chats');
           let chats = localStorage.getItem('chats');
           if (chats) {
           if (chats) {
@@ -284,8 +369,18 @@ const SiderBar = () => {
           } else {
           } else {
             styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
             styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
           }
           }
+          
+          // 如果点击的是已经展开的子菜单的父项,则收起子菜单
+          if (openedKeys.includes(key.itemKey)) {
+            setOpenedKeys(openedKeys.filter(k => k !== key.itemKey));
+          }
+          
           setSelectedKeys([key.itemKey]);
           setSelectedKeys([key.itemKey]);
         }}
         }}
+        openKeys={openedKeys}
+        onOpenChange={(data) => {
+          setOpenedKeys(data.openKeys);
+        }}
       >
       >
         {/* Chat Section - Only show if there are chat items */}
         {/* Chat Section - Only show if there are chat items */}
         {chatMenuItems.map((item) => {
         {chatMenuItems.map((item) => {
@@ -295,7 +390,7 @@ const SiderBar = () => {
                 key={item.itemKey}
                 key={item.itemKey}
                 itemKey={item.itemKey}
                 itemKey={item.itemKey}
                 text={item.text}
                 text={item.text}
-                icon={item.icon}
+                icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
               >
               >
                 {item.items.map((subItem) => (
                 {item.items.map((subItem) => (
                   <Nav.Item
                   <Nav.Item
@@ -312,13 +407,12 @@ const SiderBar = () => {
                 key={item.itemKey}
                 key={item.itemKey}
                 itemKey={item.itemKey}
                 itemKey={item.itemKey}
                 text={item.text}
                 text={item.text}
-                icon={item.icon}
+                icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
               />
               />
             );
             );
           }
           }
         })}
         })}
 
 
-
         {/* Divider */}
         {/* Divider */}
         <Divider style={dividerStyle} />
         <Divider style={dividerStyle} />
 
 
@@ -329,22 +423,7 @@ const SiderBar = () => {
             key={item.itemKey}
             key={item.itemKey}
             itemKey={item.itemKey}
             itemKey={item.itemKey}
             text={item.text}
             text={item.text}
-            icon={item.icon}
-            className={item.className}
-          />
-        ))}
-
-        {/* Divider */}
-        <Divider style={dividerStyle} />
-
-        {/* Finance Management Section */}
-        {!isCollapsed && <div style={groupLabelStyle}>{t('个人中心')}</div>}
-        {financeItems.map((item) => (
-          <Nav.Item
-            key={item.itemKey}
-            itemKey={item.itemKey}
-            text={item.text}
-            icon={item.icon}
+            icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
             className={item.className}
             className={item.className}
           />
           />
         ))}
         ))}
@@ -355,20 +434,41 @@ const SiderBar = () => {
             <Divider style={dividerStyle} />
             <Divider style={dividerStyle} />
 
 
             {/* Admin Section */}
             {/* Admin Section */}
+            {!isCollapsed && <div style={groupLabelStyle}>{t('管理员')}</div>}
             {adminItems.map((item) => (
             {adminItems.map((item) => (
               <Nav.Item
               <Nav.Item
                 key={item.itemKey}
                 key={item.itemKey}
                 itemKey={item.itemKey}
                 itemKey={item.itemKey}
                 text={item.text}
                 text={item.text}
-                icon={item.icon}
+                icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
                 className={item.className}
                 className={item.className}
               />
               />
             ))}
             ))}
           </>
           </>
         )}
         )}
 
 
+        {/* Divider */}
+        <Divider style={dividerStyle} />
+
+        {/* Finance Management Section */}
+        {!isCollapsed && <div style={groupLabelStyle}>{t('个人中心')}</div>}
+        {financeItems.map((item) => (
+          <Nav.Item
+            key={item.itemKey}
+            itemKey={item.itemKey}
+            text={item.text}
+            icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
+            className={item.className}
+          />
+        ))}
+
         <Nav.Footer
         <Nav.Footer
           collapseButton={true}
           collapseButton={true}
+          style={{
+            borderTop: '1px solid var(--semi-color-border)',
+            padding: '12px 0',
+            marginTop: 'auto'
+          }}
           collapseText={(collapsed)=>
           collapseText={(collapsed)=>
             {
             {
               if(collapsed){
               if(collapsed){

+ 108 - 2
web/src/index.css

@@ -1,7 +1,7 @@
 body {
 body {
   margin: 0;
   margin: 0;
-  padding-top: 55px;
-  overflow-y: scroll;
+  padding-top: 0;
+  overflow: hidden;
   font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei',
   font-family: Lato, 'Helvetica Neue', Arial, Helvetica, 'Microsoft YaHei',
     sans-serif;
     sans-serif;
   -webkit-font-smoothing: antialiased;
   -webkit-font-smoothing: antialiased;
@@ -15,6 +15,7 @@ body {
 #root {
 #root {
   height: 100vh;
   height: 100vh;
   flex-direction: column;
   flex-direction: column;
+  overflow: hidden;
 }
 }
 
 
 #root > section > header > section > div > div > div > div.semi-navigation-header-list-outer > div.semi-navigation-list-wrapper > ul > div > a > li > span{
 #root > section > header > section > div > div > div > div.semi-navigation-header-list-outer > div.semi-navigation-list-wrapper > ul > div > a > li > span{
@@ -29,6 +30,15 @@ body {
   /*.semi-navigation-sub-wrap .semi-navigation-sub-title, .semi-navigation-item {*/
   /*.semi-navigation-sub-wrap .semi-navigation-sub-title, .semi-navigation-item {*/
   /*  padding: 0 0;*/
   /*  padding: 0 0;*/
   /*}*/
   /*}*/
+  .topnav {
+    padding: 0 8px;
+  }
+  
+  .topnav .semi-navigation-item {
+    margin: 0 1px;
+    padding: 0 4px;
+  }
+  
   .topnav .semi-navigation-list-wrapper {
   .topnav .semi-navigation-list-wrapper {
     max-width: calc(55vw - 20px);
     max-width: calc(55vw - 20px);
     overflow-x: auto;
     overflow-x: auto;
@@ -120,6 +130,38 @@ code {
   margin-bottom: 0;
   margin-bottom: 0;
 }
 }
 
 
+/* 自定义侧边栏按钮悬停效果 */
+.semi-navigation-item:hover {
+  transform: translateX(2px);
+  box-shadow: 0 2px 8px rgba(var(--semi-color-primary-rgb), 0.2);
+}
+
+/* 自定义侧边栏按钮选中效果 */
+.semi-navigation-item-selected {
+  position: relative;
+  overflow: hidden;
+}
+
+.semi-navigation-item-selected::before {
+  content: '';
+  position: absolute;
+  left: 0;
+  top: 0;
+  height: 100%;
+  width: 4px;
+  background-color: var(--semi-color-primary);
+  animation: slideIn 0.3s ease;
+}
+
+@keyframes slideIn {
+  from {
+    transform: translateY(-100%);
+  }
+  to {
+    transform: translateY(0);
+  }
+}
+
 .semi-navigation-vertical {
 .semi-navigation-vertical {
   /*flex: 0 0 auto;*/
   /*flex: 0 0 auto;*/
   /*display: flex;*/
   /*display: flex;*/
@@ -147,3 +189,67 @@ code {
     display: none !important;
     display: none !important;
   }
   }
 }
 }
+
+/* 顶部栏样式 */
+.topnav {
+  padding: 0 16px;
+}
+
+.topnav .semi-navigation-item {
+  border-radius: 4px;
+  margin: 0 2px;
+  transition: all 0.3s ease;
+}
+
+.topnav .semi-navigation-item:hover {
+  background-color: var(--semi-color-primary-light-default);
+  transform: translateY(-2px);
+  box-shadow: 0 2px 8px rgba(var(--semi-color-primary-rgb), 0.2);
+}
+
+.topnav .semi-navigation-item-selected {
+  background-color: var(--semi-color-primary-light-default);
+  color: var(--semi-color-primary);
+  font-weight: 600;
+}
+
+/* 顶部栏文本样式 */
+.header-bar-text {
+  color: var(--semi-color-text-0);
+  font-weight: 500;
+  transition: all 0.3s ease;
+}
+
+.header-bar-text:hover {
+  color: var(--semi-color-primary);
+}
+
+/* 自定义滚动条样式 */
+.semi-layout-content::-webkit-scrollbar,
+.semi-sider::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+.semi-layout-content::-webkit-scrollbar-thumb,
+.semi-sider::-webkit-scrollbar-thumb {
+  background: var(--semi-color-tertiary-light-default);
+  border-radius: 3px;
+}
+
+.semi-layout-content::-webkit-scrollbar-thumb:hover,
+.semi-sider::-webkit-scrollbar-thumb:hover {
+  background: var(--semi-color-tertiary);
+}
+
+.semi-layout-content::-webkit-scrollbar-track,
+.semi-sider::-webkit-scrollbar-track {
+  background: transparent;
+}
+
+/* Custom sidebar shadow */
+.custom-sidebar-nav {
+  box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08) !important;
+  -webkit-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08) !important;
+  -moz-box-shadow: 0 1px 6px rgba(0, 0, 0, 0.08) !important;
+}