diff --git a/web/src/components/layout/workspace-sidebar-nav.tsx b/web/src/components/layout/workspace-sidebar-nav.tsx
index e81a4e9dd..e5c45c1de 100644
--- a/web/src/components/layout/workspace-sidebar-nav.tsx
+++ b/web/src/components/layout/workspace-sidebar-nav.tsx
@@ -266,6 +266,62 @@ function NavItem({ item, activeId, onSelect, onOpenSearch, onLogout, level = 0 }
);
}
+function NavGroup({ group, activeId, onNavigate, onOpenSearch, onLogout }: {
+ group: WorkspaceNavGroup;
+ activeId: string;
+ onNavigate: () => void;
+ onOpenSearch: () => void;
+ onLogout: () => void;
+}) {
+ const [isOpen, setIsOpen] = useState(true);
+ const hasActive = group.items.some((item) => item.id === activeId || (item.id === "settings" && activeId.startsWith("settings:")));
+
+ // 激活项所在分组自动展开,保证当前位置可见。
+ useEffect(() => {
+ if (hasActive) setIsOpen(true);
+ }, [hasActive]);
+
+ const content = (
+
+ {group.items.map((item) => (
+
+ ))}
+
+ );
+
+ // 无标题分组(核心导航入口)常驻展示,不做折叠。
+ if (!group.heading) {
+ return {content}
;
+ }
+
+ return (
+
+
+
+
+ );
+}
+
export function WorkspaceSidebarNav({ onNavigate, onOpenSearch }: { onNavigate: () => void; onOpenSearch: () => void }) {
const { pathname } = useLocation();
const [searchParams] = useSearchParams();
@@ -325,21 +381,14 @@ export function WorkspaceSidebarNav({ onNavigate, onOpenSearch }: { onNavigate:
)}
>
{groups.map((group, index) => (
-
- {group.heading ?
{group.heading} : null}
-
- {group.items.map((item) => (
- void handleLogout()}
- />
- ))}
-
-
+ void handleLogout()}
+ />
))}
diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css
index a2d26fc38..cec08d8e9 100644
--- a/web/src/styles/globals.css
+++ b/web/src/styles/globals.css
@@ -941,15 +941,44 @@
pointer-events: none;
}
- /* 分组标题:小号大写标签,弱化但可读 */
+ /* 分组标题:小号大写标签,弱化但可读;有标题的分组支持折叠,padding/间距由折叠按钮接管 */
.app-workspace-nav-group-label {
display: block;
- padding: 0 10px 6px;
font-size: var(--fs-label);
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: color-mix(in srgb, var(--foreground) 36%, transparent);
+ transition: color var(--motion-instant) ease-out;
+ }
+
+ .app-workspace-nav-group-toggle {
+ display: flex;
+ width: 100%;
+ min-height: 28px;
+ align-items: center;
+ justify-content: space-between;
+ gap: 8px;
+ padding: 0 8px;
+ border-radius: var(--r-sm);
+ text-align: left;
+ color: inherit;
+ transition: background-color var(--motion-instant) ease-out;
+ }
+
+ .app-workspace-nav-group-toggle:hover,
+ .app-workspace-nav-group-toggle:focus-visible {
+ background: var(--surface-hover);
+ }
+
+ .app-workspace-nav-group-toggle:hover .app-workspace-nav-group-label,
+ .app-workspace-nav-group-toggle:focus-visible .app-workspace-nav-group-label {
+ color: color-mix(in srgb, var(--foreground) 55%, transparent);
+ }
+
+ .app-workspace-nav-group-toggle:hover svg,
+ .app-workspace-nav-group-toggle:focus-visible svg {
+ color: color-mix(in srgb, var(--foreground) 70%, transparent);
}
/* 工作区切换器下拉浮层 */