作家写作

This commit is contained in:
fengxiangdebaozi committed 2026-05-29 11:42:30 +08:00
1 parent 1a122eb7fd
commit 07ad87365f
7 files changed
+380 -228

No files matched your search

+89 -2
View File
@@ -16,7 +16,9 @@
.item-nav{
width:100%;
padding:10px 0;
border:0;
border-bottom:1px solid rgba(85, 166, 254, 0.2);
background:transparent;
font-family:'Noto Sans S Chinese', sans-serif;
font-weight:500;
color:rgba(255, 255, 255, 0.8);
@@ -44,7 +46,7 @@
.item-nav-content{
width: 155px;
height: 970px;
min-height: 970px;
background: rgba(3, 38, 80, 0.8);
border: 1px solid;
border-color: rgba(43, 143, 254, 0.6);
@@ -54,6 +56,8 @@
left: 97px;
top: 0;
z-index: 1000;
padding: 14px 13px 18px 16px;
overflow-y:auto;
}
.item-nav-active{
@@ -81,4 +85,87 @@
height:45px;
background: url('../assets/icon/nav-line-logo.svg') no-repeat;
background-size: cover;
}
}
.sidebar-flyout-list{
display:flex;
flex-direction:column;
gap:2px;
position:relative;
}
.sidebar-flyout-list--level-1,
.sidebar-flyout-list--level-2,
.sidebar-flyout-list--level-3{
margin-left:19px;
padding-left:14px;
}
.sidebar-flyout-node{
position:relative;
}
.sidebar-flyout-node--has-children.sidebar-flyout-node--expanded > .sidebar-flyout-list::before{
content:'';
position:absolute;
left:0;
top:0;
width:1px;
height:100%;
background:rgba(43, 143, 254, 0.22);
}
.sidebar-flyout-item{
width:100%;
min-height:34px;
display:flex;
align-items:center;
gap:9px;
border:0;
background:transparent;
padding:3px 0;
font-family:Noto Sans S Chinese;
font-size:18px;
line-height:28px;
font-weight:500;
letter-spacing:0;
color:rgba(255, 255, 255, 0.8);
text-align:left;
cursor:pointer;
transition:color 0.2s ease, text-shadow 0.2s ease;
}
.sidebar-flyout-item:hover,
.sidebar-flyout-item--active{
color:#48ddff;
text-shadow:0 0 8px rgba(72, 221, 255, 0.25);
}
.sidebar-flyout-item--leaf{
justify-content:center;
padding-left:0;
}
.sidebar-flyout-list--level-1 > .sidebar-flyout-node > .sidebar-flyout-item--leaf,
.sidebar-flyout-list--level-2 > .sidebar-flyout-node > .sidebar-flyout-item--leaf,
.sidebar-flyout-list--level-3 > .sidebar-flyout-node > .sidebar-flyout-item--leaf{
padding-left:0;
}
.sidebar-flyout-arrow{
width:9px;
height:9px;
flex:0 0 9px;
background:url('../assets/icon/down-logo.svg') center / contain no-repeat;
transform:rotate(-90deg);
transition:transform 0.2s ease;
}
.sidebar-flyout-node--expanded > .sidebar-flyout-item > .sidebar-flyout-arrow{
transform:rotate(0deg);
}
.sidebar-flyout-label{
flex:1;
white-space:nowrap;
}
@@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useMemo, useState } from "react";
import type { ElementType } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import {
@@ -285,7 +285,10 @@ export function PageSidebarDark({
const { theme } = useTheme();
const isDark = theme === "dark";
const isAdmin = getStoredAuth()?.system_role === "admin";
const visibleMenuItems = filterMenuItemsByRole(menuItems, !!isAdmin);
const visibleMenuItems = useMemo(
() => filterMenuItemsByRole(menuItems, !!isAdmin),
[isAdmin],
);
const { t } = useI18n();
const { data: unreadCount = 0 } = useUnreadCount();
const [expandedIds, setExpandedIds] = useState<Set<string>>(defaultExpandedIds);
@@ -306,6 +309,26 @@ export function PageSidebarDark({
setSettingsOpen(true);
};
const hasActiveChild = (item: MenuItem): boolean => {
if (item.path && pathname === item.path) {
return true;
}
return item.children?.some(hasActiveChild) ?? false;
};
const initialActiveTopItem = visibleMenuItems.find(hasActiveChild) ?? visibleMenuItems[0];
const [activeTopId, setActiveTopId] = useState(initialActiveTopItem?.id ?? "qa-center");
useEffect(() => {
const matchedTopItem = visibleMenuItems.find(hasActiveChild);
if (matchedTopItem) {
setActiveTopId(matchedTopItem.id);
}
}, [pathname, visibleMenuItems]);
const activeTopItem = visibleMenuItems.find((item) => item.id === activeTopId) ?? initialActiveTopItem;
const toggleExpanded = (id: string) => {
setExpandedIds((prev) => {
const next = new Set(prev);
@@ -318,6 +341,51 @@ export function PageSidebarDark({
});
};
const handleTopItemClick = (item: MenuItem) => {
setActiveTopId(item.id);
if (!item.children?.length && item.path) {
navigate(item.path);
}
};
const handleMenuItemClick = (item: MenuItem) => {
if (item.children?.length) {
toggleExpanded(item.id);
return;
}
if (item.path) {
navigate(item.path);
}
};
const renderFlyoutMenu = (items: MenuItem[], level = 0) => (
<div className={`sidebar-flyout-list sidebar-flyout-list--level-${level}`}>
{items.map((item) => {
const hasChildren = !!item.children?.length;
const isExpanded = expandedIds.has(item.id);
const isSelected = item.path ? pathname === item.path : hasActiveChild(item);
return (
<div
key={item.id}
className={`sidebar-flyout-node sidebar-flyout-node--level-${level} ${hasChildren ? "sidebar-flyout-node--has-children" : ""} ${isExpanded ? "sidebar-flyout-node--expanded" : ""}`}
>
<button
type="button"
className={`sidebar-flyout-item ${isSelected ? "sidebar-flyout-item--active" : ""} ${hasChildren ? "sidebar-flyout-item--parent" : "sidebar-flyout-item--leaf"}`}
onClick={() => handleMenuItemClick(item)}
>
{hasChildren ? <span className="sidebar-flyout-arrow" aria-hidden="true" /> : null}
<span className="sidebar-flyout-label">{item.label}</span>
</button>
{hasChildren && isExpanded ? renderFlyoutMenu(item.children ?? [], level + 1) : null}
</div>
);
})}
</div>
);
return (
<>
<SettingsDialog
@@ -332,11 +400,18 @@ export function PageSidebarDark({
{/* TODO: 在这里编写深色主题的侧边栏 HTML 结构 */}
<div className="sidebar-contnet">
<div className="sidebar-contents">
<div className="item-nav-content"></div>
<div className="item-nav-content">
{activeTopItem?.children?.length ? renderFlyoutMenu(activeTopItem.children) : null}
</div>
{visibleMenuItems.map((item) => (
<div key={item.id} className={`item-nav ${item.id === 'qa-center' ? 'item-nav-active' : ''}`}>
<button
type="button"
key={item.id}
className={`item-nav ${item.id === activeTopId ? "item-nav-active" : ""}`}
onClick={() => handleTopItemClick(item)}
>
<span className="item-nav__label">{item.label}</span>
</div>
</button>
))}
</div>
</div>