refactor: Enhance UI layout and styling with responsive design improvements

This commit is contained in:
1808837298@qq.com
2025-03-10 03:25:02 +08:00
parent 3ed50787b3
commit d9cf0885f1
4 changed files with 376 additions and 52 deletions

View File

@@ -1,5 +1,5 @@
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 { StatusContext } from '../context/Status';
import { useTranslation } from 'react-i18next';
@@ -34,7 +34,34 @@ import { stringToColor } from '../helpers/render.js';
import { useSetTheme, useTheme } from '../context/Theme/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 { t } = useTranslation();
@@ -46,8 +73,30 @@ const SiderBar = () => {
const [selectedKeys, setSelectedKeys] = useState(['home']);
const [isCollapsed, setIsCollapsed] = useState(defaultIsCollapsed);
const [chatItems, setChatItems] = useState([]);
const [openedKeys, setOpenedKeys] = useState([]);
const theme = useTheme();
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 = {
home: '/',
@@ -190,11 +239,14 @@ const SiderBar = () => {
);
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');
if (chats) {
@@ -222,7 +274,7 @@ const SiderBar = () => {
}
setIsCollapsed(localStorage.getItem('default_collapse_sidebar') === 'true');
}, []);
}, [location.pathname]);
// Custom divider style
const dividerStyle = {
@@ -235,21 +287,54 @@ const SiderBar = () => {
padding: '8px 16px',
color: 'var(--semi-color-text-2)',
fontSize: '12px',
fontWeight: 'normal',
fontWeight: 'bold',
textTransform: 'uppercase',
letterSpacing: '0.5px',
};
return (
<>
<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={
localStorage.getItem('default_collapse_sidebar') === 'true'
}
isCollapsed={isCollapsed}
onCollapseChange={(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}
itemStyle={navItemStyle}
hoverStyle={navItemHoverStyle}
selectedStyle={navItemSelectedStyle}
renderWrapper={({ itemElement, isSubNav, isInSubNav, props }) => {
let chats = localStorage.getItem('chats');
if (chats) {
@@ -284,8 +369,18 @@ const SiderBar = () => {
} else {
styleDispatch({ type: 'SET_INNER_PADDING', payload: true });
}
// 如果点击的是已经展开的子菜单的父项,则收起子菜单
if (openedKeys.includes(key.itemKey)) {
setOpenedKeys(openedKeys.filter(k => k !== key.itemKey));
}
setSelectedKeys([key.itemKey]);
}}
openKeys={openedKeys}
onOpenChange={(data) => {
setOpenedKeys(data.openKeys);
}}
>
{/* Chat Section - Only show if there are chat items */}
{chatMenuItems.map((item) => {
@@ -295,7 +390,7 @@ const SiderBar = () => {
key={item.itemKey}
itemKey={item.itemKey}
text={item.text}
icon={item.icon}
icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
>
{item.items.map((subItem) => (
<Nav.Item
@@ -312,13 +407,12 @@ const SiderBar = () => {
key={item.itemKey}
itemKey={item.itemKey}
text={item.text}
icon={item.icon}
icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
/>
);
}
})}
{/* Divider */}
<Divider style={dividerStyle} />
@@ -329,11 +423,30 @@ const SiderBar = () => {
key={item.itemKey}
itemKey={item.itemKey}
text={item.text}
icon={item.icon}
icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
className={item.className}
/>
))}
{isAdmin() && (
<>
{/* Divider */}
<Divider style={dividerStyle} />
{/* Admin Section */}
{!isCollapsed && <div style={groupLabelStyle}>{t('管理员')}</div>}
{adminItems.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}
/>
))}
</>
)}
{/* Divider */}
<Divider style={dividerStyle} />
@@ -344,31 +457,18 @@ const SiderBar = () => {
key={item.itemKey}
itemKey={item.itemKey}
text={item.text}
icon={item.icon}
icon={React.cloneElement(item.icon, { style: iconStyles[item.itemKey] })}
className={item.className}
/>
))}
{isAdmin() && (
<>
{/* Divider */}
<Divider style={dividerStyle} />
{/* Admin Section */}
{adminItems.map((item) => (
<Nav.Item
key={item.itemKey}
itemKey={item.itemKey}
text={item.text}
icon={item.icon}
className={item.className}
/>
))}
</>
)}
<Nav.Footer
collapseButton={true}
style={{
borderTop: '1px solid var(--semi-color-border)',
padding: '12px 0',
marginTop: 'auto'
}}
collapseText={(collapsed)=>
{
if(collapsed){