R67 A1-A6:官网风格前端 UI 刷新

这个提交包含在:
2026-04-26 14:07:11 +08:00
父节点 a15bbcbadb
当前提交 a08db8590a
共修改 20 个文件,包含 390 行新增和 185 行删除
+11 -11
查看文件
@@ -75,10 +75,10 @@ function renderNavItem(item: ResolvedNavItem, onNavigate?: () => void) {
onClick={() => onNavigate?.()}
className={({ isActive }) =>
cn(
"group flex items-center gap-3 rounded-2xl px-3 py-2.5 text-sm transition-colors",
"group flex items-center gap-3 rounded-2xl px-3 py-2.5 text-sm transition duration-200",
isActive
? "bg-zinc-900 text-white shadow-sm"
: "text-zinc-600 hover:bg-zinc-50 hover:text-zinc-900",
? "bg-primary text-white shadow-sm"
: "text-[var(--color-text-secondary)] hover:-translate-y-0.5 hover:bg-white/70 hover:text-[var(--color-text-primary)] hover:shadow-sm",
)
}
>
@@ -88,8 +88,8 @@ function renderNavItem(item: ResolvedNavItem, onNavigate?: () => void) {
className={cn(
"flex size-9 items-center justify-center rounded-xl border text-[20px] transition-colors",
isActive
? "border-white/15 bg-white/10 text-white"
: "border-zinc-200 bg-white text-zinc-500 group-hover:border-zinc-300 group-hover:text-zinc-900",
? "border-white/15 bg-white/15 text-white"
: "border-slate-200 bg-white text-[var(--color-text-tertiary)] group-hover:border-slate-300 group-hover:text-primary",
)}
>
<span className="material-symbols-outlined text-[20px]">{item.icon}</span>
@@ -109,8 +109,8 @@ function renderSection(title: string, description: string, items: ResolvedNavIte
return (
<section className="space-y-2">
<div className="px-3">
<div className="text-[11px] font-semibold uppercase tracking-[0.18em] text-zinc-400">{title}</div>
<div className="mt-1 text-xs text-zinc-500">{description}</div>
<div className="text-[11px] font-bold uppercase tracking-[0.2em] text-primary/70">{title}</div>
<div className="mt-1 text-xs leading-5 text-[var(--color-text-tertiary)]">{description}</div>
</div>
<div className="space-y-1.5">{items.map((item) => renderNavItem(item, onNavigate))}</div>
</section>
@@ -123,13 +123,13 @@ function renderBackupSection(items: ResolvedNavItem[], onNavigate?: () => void)
}
return (
<details className="rounded-2xl border border-zinc-200 bg-zinc-50/80 px-3 py-3">
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 rounded-xl px-2 py-1.5 text-sm font-semibold text-zinc-700">
<details className="rounded-2xl border border-slate-200 bg-slate-50/80 px-3 py-3">
<summary className="flex cursor-pointer list-none items-center justify-between gap-3 rounded-xl px-2 py-1.5 text-sm font-semibold text-[var(--color-text-primary)]">
<div>
<div>备用模块</div>
<div className="mt-0.5 text-xs font-normal text-zinc-500">默认收起,不干扰主路径</div>
<div className="mt-0.5 text-xs font-normal text-[var(--color-text-secondary)]">默认收起,不干扰主路径</div>
</div>
<span className="text-xs font-medium text-zinc-400">按需展开</span>
<span className="text-xs font-medium text-[var(--color-text-tertiary)]">按需展开</span>
</summary>
<div className="mt-3 space-y-1.5 pb-1">{items.map((item) => renderNavItem(item, onNavigate))}</div>
</details>
+9 -6
查看文件
@@ -3,16 +3,19 @@ import { NavLinks } from "./NavLinks";
export function Sidebar() {
return (
<aside className="fixed inset-y-0 z-20 hidden w-72 overflow-hidden border-r border-zinc-200 bg-white/95 backdrop-blur lg:flex lg:flex-col">
<div className="border-b border-zinc-200 px-6 py-6">
<aside className="fixed inset-y-0 z-20 hidden w-72 overflow-hidden border-r border-slate-200 bg-white/92 shadow-[18px_0_50px_rgba(15,23,42,0.08)] backdrop-blur-xl lg:flex lg:flex-col">
<div className="border-b border-slate-200 px-6 py-6">
<AppBrand />
<div className="mt-4 rounded-2xl border border-zinc-200 bg-zinc-50 px-4 py-3 text-sm text-zinc-600">
<div className="font-medium text-zinc-900">统一工作台</div>
<div className="mt-1">先看今天要做什么,再进入具体模块处理。</div>
<div className="mt-5 overflow-hidden rounded-3xl border border-slate-200 bg-[linear-gradient(135deg,rgba(0,57,138,0.08),rgba(19,168,184,0.10))] px-4 py-4 text-sm text-[var(--color-text-secondary)]">
<div className="flex items-center gap-2 font-semibold text-[var(--color-text-primary)]">
<span className="size-2 rounded-full bg-primary" />
今日工作台
</div>
<div className="mt-2 leading-6">先处理待办和团队状态,再进入具体模块。</div>
</div>
</div>
<div className="min-h-0 flex-1 overflow-y-auto px-4 py-5">
<div className="min-h-0 flex-1 overflow-y-auto px-4 py-5 [scrollbar-width:thin]">
<NavLinks />
</div>
</aside>
+17 -17
查看文件
@@ -135,7 +135,7 @@ export function Topbar() {
return (
<>
<header className="sticky top-0 z-10 border-b border-zinc-200/80 bg-white/90 px-4 py-4 backdrop-blur sm:px-8">
<header className="sticky top-0 z-10 border-b border-slate-200/80 bg-white/88 px-4 py-3 shadow-[0_10px_30px_rgba(15,23,42,0.06)] backdrop-blur-xl sm:px-8">
<div className="flex items-center justify-between gap-4">
<div className="flex min-w-0 items-center gap-3">
<Dialog open={mobileNavOpen} onOpenChange={setMobileNavOpen}>
@@ -145,9 +145,9 @@ export function Topbar() {
</Button>
</DialogTrigger>
<DialogContent className="left-0 top-0 h-full w-80 max-w-[84vw] rounded-none rounded-r-3xl border-r border-zinc-200 p-0">
<DialogContent className="left-0 top-0 h-full w-80 max-w-[84vw] rounded-none rounded-r-3xl border-r border-slate-200 p-0">
<div className="flex h-full flex-col bg-white">
<div className="flex items-start justify-between border-b border-zinc-200 px-5 py-5">
<div className="flex items-start justify-between border-b border-slate-200 px-5 py-5">
<AppBrand />
<DialogClose asChild>
<Button size="icon" variant="ghost" aria-label="关闭菜单" type="button">
@@ -164,9 +164,9 @@ export function Topbar() {
</Dialog>
<div className="min-w-0">
<div className="text-xs font-semibold uppercase tracking-[0.18em] text-zinc-400">{pageMeta.group}</div>
<div className="text-xs font-bold uppercase tracking-[0.2em] text-primary/70">{pageMeta.group}</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
<p className="truncate text-lg font-semibold tracking-tight text-zinc-900">{pageMeta.title}</p>
<p className="truncate text-lg font-semibold tracking-tight text-[var(--color-text-primary)]">{pageMeta.title}</p>
{wecomEntry ? (
<span
className="badge-neutral border-primary-200 bg-primary-50 text-primary"
@@ -176,7 +176,7 @@ export function Topbar() {
</span>
) : null}
</div>
<div className="mt-1 text-sm text-zinc-500">{me ? `你好,${me.name}` : "欢迎进入海音达工作台"}</div>
<div className="mt-1 text-sm text-[var(--color-text-secondary)]">{me ? `你好,${me.name}` : "欢迎进入海音达工作台"}</div>
</div>
</div>
@@ -224,11 +224,11 @@ export function Topbar() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-80 max-w-[calc(100vw-2rem)] p-0">
<div className="flex items-center justify-between border-b border-zinc-200 px-4 py-3">
<DropdownMenuContent align="end" className="w-80 max-w-[calc(100vw-2rem)] overflow-hidden rounded-2xl border-slate-200 bg-white p-0">
<div className="flex items-center justify-between border-b border-slate-200 bg-slate-50/80 px-4 py-3">
<div className="flex items-center gap-2">
<span className="text-sm font-semibold text-zinc-900">通知</span>
<span className="rounded-full bg-zinc-100 px-2 py-0.5 text-xs font-medium text-zinc-600">
<span className="text-sm font-semibold text-[var(--color-text-primary)]">通知</span>
<span className="rounded-full bg-white px-2 py-0.5 text-xs font-medium text-[var(--color-text-secondary)]">
{unreadCount}
</span>
</div>
@@ -244,7 +244,7 @@ export function Topbar() {
<div className="max-h-[400px] overflow-y-auto">
{dropdownQuery.isLoading ? (
<div className="px-4 py-6 text-sm text-zinc-500">通知加载中...</div>
<div className="px-4 py-6 text-sm text-[var(--color-text-secondary)]">通知加载中...</div>
) : null}
{dropdownQuery.isError ? (
@@ -257,7 +257,7 @@ export function Topbar() {
<button
key={item.id}
type="button"
className="flex w-full items-start gap-3 border-b border-zinc-100 px-4 py-3 text-left transition hover:bg-zinc-50 disabled:opacity-60"
className="flex w-full items-start gap-3 border-b border-slate-100 px-4 py-3 text-left transition hover:bg-slate-50 disabled:opacity-60"
disabled={markReadMutation.isPending}
onClick={() => void handleNotificationClick(item)}
>
@@ -265,20 +265,20 @@ export function Topbar() {
{!item.readAt ? <span className="h-2 w-2 rounded-full bg-sky-500" /> : null}
</span>
<span className="min-w-0 flex-1">
<span className="block truncate text-sm font-medium text-zinc-900">{item.title}</span>
<span className="mt-1 block text-xs text-zinc-500">
<span className="block truncate text-sm font-medium text-[var(--color-text-primary)]">{item.title}</span>
<span className="mt-1 block text-xs text-[var(--color-text-secondary)]">
{formatNotificationRelativeTime(item.createdAt)}
</span>
</span>
</button>
))
) : (
<div className="px-4 py-6 text-sm text-zinc-500">暂无通知</div>
<div className="px-4 py-6 text-sm text-[var(--color-text-secondary)]">暂无通知</div>
)
) : null}
</div>
<div className="border-t border-zinc-200 px-2 py-2">
<div className="border-t border-slate-200 px-2 py-2">
<Button asChild variant="ghost" className="w-full justify-between" type="button">
<Link to="/notifications" onClick={() => setNotificationsOpen(false)}>
查看全部通知
@@ -295,7 +295,7 @@ export function Topbar() {
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuContent align="end" className="w-48 rounded-2xl border-slate-200 bg-white">
<DropdownMenuItem asChild className="cursor-pointer">
<Link to="/settings/profile">个人设置</Link>
</DropdownMenuItem>