Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
58b8ca90
authored
Mar 10, 2025
by
1808837298@qq.com
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
refactor: Enhance UI layout and styling with responsive design improvements
parent
f4c5ab7f
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
373 additions
and
49 deletions
+373
-49
web/src/components/HeaderBar.js
+92
-11
web/src/components/PageLayout.js
+44
-7
web/src/components/SiderBar.js
+129
-29
web/src/index.css
+108
-2
No files found.
web/src/components/HeaderBar.js
View file @
58b8ca90
...
@@ -19,7 +19,10 @@ import {
...
@@ -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';
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -336,7 +417,7 @@ const HeaderBar = () => {
<
Nav
.
Item
<
Nav
.
Item
itemKey
=
{
'register'
}
itemKey
=
{
'register'
}
text
=
{
t
(
'注册'
)}
text
=
{
t
(
'注册'
)}
icon
=
{
<
IconKey
/>
}
icon
=
{
<
IconKey
style
=
{
headerIconStyle
}
/>
}
/>
/>
)
)
}
}
...
...
web/src/components/PageLayout.js
View file @
58b8ca90
...
@@ -62,20 +62,57 @@ const PageLayout = () => {
...
@@ -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'
}}
>
<
Layout
style
=
{{
marginTop
:
'56px'
,
height
:
'calc(100vh - 56px)'
,
overflow
:
'hidden'
}}
>
<
Sider
>
{
styleState
.
showSider
&&
(
{
styleState
.
showSider
?
<
SiderBar
/>
:
null
}
<
Sider
style
=
{{
<
/Sider
>
height
:
'calc(100vh - 56px)'
,
<
Layout
>
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
>
...
...
web/src/components/SiderBar.js
View file @
58b8ca90
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';
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -190,11 +239,14 @@ const SiderBar = () => {
);
);
useEffect
(()
=>
{
useEffect
(()
=>
{
let
localKey
=
window
.
location
.
pathname
.
split
(
'/'
)[
1
];
const
currentPath
=
location
.
pathname
;
if
(
localKey
===
''
)
{
const
matchingKey
=
Object
.
keys
(
routerMap
).
find
(
key
=>
routerMap
[
key
]
===
currentPath
);
localKey
=
'home'
;
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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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 = () => {
...
@@ -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
}
icon
=
{
React
.
cloneElement
(
item
.
icon
,
{
style
:
iconStyles
[
item
.
itemKey
]
})}
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
}
className
=
{
item
.
className
}
className
=
{
item
.
className
}
/
>
/
>
))}
))}
...
@@ -355,20 +434,41 @@ const SiderBar = () => {
...
@@ -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
){
...
...
web/src/index.css
View file @
58b8ca90
body
{
body
{
margin
:
0
;
margin
:
0
;
padding-top
:
55px
;
padding-top
:
0
;
overflow
-y
:
scroll
;
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 {
...
@@ -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 {
...
@@ -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 {
...
@@ -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 {
...
@@ -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
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment