feat(workspace): 侧边栏 - 主页与管理后台侧栏样式统一 (#733)

* fix(admin): 侧栏收起模式 - 修复导航图标未居中

AdminTooltip 在收起模式下用 inline-flex span 包裹 NavLink,
导致 NavLink 无法撑满容器宽度,justify-content: center 不生效。
将 span 强制为 display: block; width: 100% 修复图标居中。

* feat(workspace): 侧边栏 - 主页与管理后台侧栏样式统一

主页侧边栏:
- 顶部收起/展开按钮移除,收起时顶部展示平台 logo,logo 与文字内容居中
- 收起/展开按钮移至底部:展开时位于账户信息右侧,收起时位于其下方居中
- 按钮尺寸调整为 40px(展开)/ 48px(收起),与账户、签到按钮协调
- 修复纯图标按钮悬浮时全局规则带来的 accent 光晕,悬浮表现与导航菜单一致
- 个人信息按钮悬浮样式与导航菜单统一(--user-surface-hover,支持暗色主题)

管理后台侧边栏:
- 导航链接高度、内边距、圆角、图标尺寸对齐主页侧边栏(44px 高、12px 内边距)
- 收起态导航项自适应填满内容区,修复纵向滚动条占位导致的横向滚动
- 收起/展开按钮从侧栏边缘悬浮胶囊改为底部按钮位(与主页一致)
- 顶部品牌区改为居中布局,收起时展示 logo

* style(admin): 侧栏 - 修复 CI 格式检查

admin-chrome.css 中 cubic-bezier 数值补前导零,通过 Prettier 检查。
This commit is contained in:
俗人
2026-10-11 22:02:54 +08:00
committed by GitHub
parent 74eb83e92a
commit 7f50b4507a
5 changed files with 174 additions and 68 deletions

View File

@@ -1,5 +1,5 @@
import { Popover } from "antd";
import { Bell, ChevronDown, ChevronRight, CircleUserRound, History as HistoryIcon, Infinity as InfinityIcon, PanelLeftClose, PanelLeftOpen, Plus } from "lucide-react";
import { ChevronDown, ChevronRight, CircleUserRound, History as HistoryIcon, Infinity as InfinityIcon, PanelLeftClose, PanelLeftOpen, Plus } from "lucide-react";
import { LayoutGroup, motion, useReducedMotion } from "motion/react";
import { useEffect, useMemo, useRef, useState, type ComponentType, type CSSProperties } from "react";
import { Link, useLocation, useNavigate, useSearchParams } from "react-router";
@@ -8,7 +8,6 @@ import { BrandLogoFrame } from "@/components/brand/brand-logo";
import { Kbd } from "@/components/ui/base/kbd";
import { navigationTools, type NavigationToolSlug } from "@/constant/navigation-tools";
import { useWorkspaceLogout } from "@/hooks/use-workspace-logout";
import { SystemAnnouncementCenter } from "@/components/layout/system-announcement-center";
import { aceternityMotion } from "@/lib/aceternity-motion";
import { cn } from "@/lib/utils";
import { preloadWorkspaceRoute } from "@/lib/workspace-route-modules";
@@ -62,7 +61,7 @@ function buildNav(features: FeatureAvailability): { groups: WorkspaceNavGroup[];
return { groups, footer: [] };
}
function WorkspaceSidebarProfile({ collapsed, user }: { collapsed: boolean; user: NonNullable<ReturnType<typeof useUserStore.getState>["user"]> | null }) {
function WorkspaceSidebarProfile({ collapsed, user, onExpand, onCollapse }: { collapsed: boolean; user: NonNullable<ReturnType<typeof useUserStore.getState>["user"]> | null; onExpand: () => void; onCollapse: () => void }) {
const [failed, setFailed] = useState(false);
const [menuOpen, setMenuOpen] = useState(false);
const avatarUrl = /^https?:\/\//i.test(user?.avatarUrl || "") ? user?.avatarUrl : "";
@@ -88,21 +87,26 @@ function WorkspaceSidebarProfile({ collapsed, user }: { collapsed: boolean; user
{!collapsed ? <span className="app-workspace-sidebar-profile-copy"><strong>{profileName}</strong><span>创作工作台</span></span> : null}
</button>
</Popover>
{!collapsed ? <SystemAnnouncementCenter userId={user.id} className="app-workspace-sidebar-notification" /> : <span className="app-workspace-sidebar-notification-spacer" aria-hidden />}
{!collapsed ? <button type="button" className="app-workspace-sidebar-collapse-toggle" aria-label="收起侧栏" title="收起侧栏" onClick={onCollapse}>
<PanelLeftClose className="size-4" strokeWidth={1.7} />
</button> : null}
</div>
{collapsed ? <button type="button" className="app-workspace-sidebar-collapse-toggle is-collapsed" aria-label="展开侧栏菜单" title="展开侧栏菜单" onClick={onExpand}>
<PanelLeftOpen className="size-4" strokeWidth={1.7} />
</button> : null}
</div>
);
}
function WorkspaceSwitcher({ collapsed, onNavigate, onExpand, onCollapse }: { collapsed: boolean; onNavigate: () => void; onExpand: () => void; onCollapse: () => void }) {
function WorkspaceSwitcher({ collapsed, onNavigate }: { collapsed: boolean; onNavigate: () => void; onExpand: () => void; onCollapse: () => void }) {
const appearance = useAppearanceStore((state) => state.appearance);
if (collapsed) {
return (
<div className="app-workspace-sidebar-rail-header shrink-0">
<button type="button" className="app-workspace-sidebar-rail-button" aria-label="展开侧栏菜单" title="展开侧栏菜单" onClick={onExpand}>
<PanelLeftOpen className="size-4" strokeWidth={1.7} />
</button>
<div className="app-workspace-sidebar-brand-row relative shrink-0 flex items-center justify-center px-3 pt-3">
<Link to="/" onClick={onNavigate} className="app-workspace-sidebar-brand-button group" aria-label={`${appearance.brandName}首页`}>
<BrandLogoFrame className="app-workspace-brand-mark grid size-8 shrink-0 place-items-center rounded-[var(--r-sm)] shadow-sm" logoClassName="size-5 object-contain" alt="" fallback={<InfinityIcon className="size-4" strokeWidth={2.2} />} />
</Link>
</div>
);
}
@@ -118,9 +122,6 @@ function WorkspaceSwitcher({ collapsed, onNavigate, onExpand, onCollapse }: { co
</span>
</span>
</Link>
<button type="button" className="app-workspace-sidebar-collapse-button" aria-label="收起侧栏" title="收起侧栏" onClick={onCollapse}>
<PanelLeftClose className="size-4" strokeWidth={1.7} />
</button>
</div>
);
}
@@ -329,7 +330,7 @@ export function WorkspaceSidebarNav({ collapsed, onNavigate, onOpenSearch, onExp
</LayoutGroup>
<div className="app-workspace-sidebar-footer shrink-0 px-3 py-3">
<WorkspaceSidebarProfile collapsed={collapsed} user={user} />
<WorkspaceSidebarProfile collapsed={collapsed} user={user} onExpand={onExpand} onCollapse={onCollapse} />
{footer.length ? <div className="mt-2 flex flex-col gap-0.5">
{footer.map((item) => (
<NavItem key={item.id} item={item} activeId={activeId} onSelect={onNavigate} onOpenSearch={onOpenSearch} onLogout={() => void handleLogout()} collapsed={collapsed} />