polish(frontend): 修正中文字重发虚,并疏朗首页与数据区

补齐 Noto 600/800 并关闭伪粗;Header 加大加粗导航并加板块入口;去掉灰块底、加大列表行距,站点数据格居中缩小数字。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-16 04:10:14 +08:00
parent 5507552ca5
commit 0e61a14ea3
9 changed files with 69 additions and 28 deletions

View File

@@ -159,7 +159,7 @@ export function AdminSidebar({ user }: { user: User }) {
key={item.href} key={item.href}
href={item.href} href={item.href}
aria-current={active ? "page" : undefined} aria-current={active ? "page" : undefined}
className="flex items-center gap-2.5 px-3 py-2.5 rounded-xl text-[13.5px] transition-colors" className="flex items-center gap-2.5 px-3 py-2.5 rounded-xl text-[13.5px] font-medium transition-colors"
style={ style={
active active
? { background: "var(--nav-active-bg)", color: "var(--nav-active-ink)" } ? { background: "var(--nav-active-bg)", color: "var(--nav-active-ink)" }
@@ -190,7 +190,7 @@ export function AdminSidebar({ user }: { user: User }) {
<div className="flex items-center gap-2.5 mt-2 px-2.5 py-2.5 rounded-xl" style={{ background: "var(--panel-2)" }}> <div className="flex items-center gap-2.5 mt-2 px-2.5 py-2.5 rounded-xl" style={{ background: "var(--panel-2)" }}>
<Avatar name={user.nickname || user.username} src={user.avatar || undefined} size={32} /> <Avatar name={user.nickname || user.username} src={user.avatar || undefined} size={32} />
<div className="min-w-0 leading-tight"> <div className="min-w-0 leading-tight">
<p className="text-[13px] truncate" style={{ color: "var(--ink)" }}> <p className="text-[13px] font-medium truncate" style={{ color: "var(--ink)" }}>
{user.nickname} {user.nickname}
</p> </p>
<p className="text-[11px] truncate" style={{ color: "var(--ink-3)" }}> <p className="text-[11px] truncate" style={{ color: "var(--ink-3)" }}>

View File

@@ -670,7 +670,7 @@ export default function UsersAdmin({
<Avatar name={u.nickname || u.username} src={u.avatar || undefined} size={38} /> <Avatar name={u.nickname || u.username} src={u.avatar || undefined} size={38} />
<div className="min-w-0 flex-1 leading-tight"> <div className="min-w-0 flex-1 leading-tight">
<div className="flex items-center gap-2 flex-wrap"> <div className="flex items-center gap-2 flex-wrap">
<span className="text-[14px] truncate" style={{ color: "var(--ink)" }}> <span className="text-[14px] font-medium truncate" style={{ color: "var(--ink)" }}>
{u.nickname} {u.nickname}
</span> </span>
{u.role !== ROLES.USER && ( {u.role !== ROLES.USER && (

View File

@@ -109,8 +109,10 @@ body {
background-color: var(--bg); background-color: var(--bg);
color: var(--ink); color: var(--ink);
font-family: var(--font-sans); font-family: var(--font-sans);
-webkit-font-smoothing: antialiased; /* 亚像素渲染在 Windows 高分屏更实;强制 grayscale 会让 400/500 中文偏虚 */
-webkit-font-smoothing: auto;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
font-synthesis: none; /* 禁止伪粗,避免缺档字重糊成一团 */
} }
/* 全站悬停即显提示气泡(配合 TipHost + data-tip,替代原生 title 延迟) */ /* 全站悬停即显提示气泡(配合 TipHost + data-tip,替代原生 title 延迟) */
@@ -282,7 +284,23 @@ body {
padding: 14px 16px; padding: 14px 16px;
border-radius: 14px; border-radius: 14px;
border: 1px solid var(--line); border: 1px solid var(--line);
background: color-mix(in srgb, var(--tint) 65%, var(--panel)); background: var(--panel);
}
.j13-interact-card.is-unsolved {
background: color-mix(in srgb, var(--danger) 7%, var(--panel));
border-color: color-mix(in srgb, var(--danger) 22%, var(--line));
}
.j13-interact-card.is-solved {
background: color-mix(in srgb, var(--ok) 8%, var(--panel));
border-color: color-mix(in srgb, var(--ok) 22%, var(--line));
}
.dark .j13-interact-card.is-unsolved {
background: color-mix(in srgb, var(--danger) 14%, var(--panel));
border-color: color-mix(in srgb, var(--danger) 32%, var(--line));
}
.dark .j13-interact-card.is-solved {
background: color-mix(in srgb, var(--ok) 14%, var(--panel));
border-color: color-mix(in srgb, var(--ok) 30%, var(--line));
} }
.j13-compose-field { .j13-compose-field {
@@ -924,7 +942,7 @@ a.j13-mention-token:hover {
.field { .field {
width: 100%; width: 100%;
padding: 12px 15px; padding: 12px 15px;
background: var(--bg); background: var(--panel);
border: 1px solid var(--line-2); border: 1px solid var(--line-2);
border-radius: var(--r-sm); border-radius: var(--r-sm);
color: var(--ink); color: var(--ink);
@@ -1374,6 +1392,7 @@ a.j13-mention-token:hover {
.j13-bcard-name { .j13-bcard-name {
color: var(--ink); color: var(--ink);
font-size: 14px; font-size: 14px;
font-weight: 500;
} }
.j13-bcard[aria-current="page"] .j13-bcard-name { .j13-bcard[aria-current="page"] .j13-bcard-name {
color: var(--nav-active-ink); color: var(--nav-active-ink);
@@ -1407,26 +1426,26 @@ a.j13-mention-token:hover {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 7px; gap: 7px;
font-size: 13px; font-size: 13.5px;
font-weight: 500; font-weight: 600;
letter-spacing: 0.02em; letter-spacing: 0.02em;
color: var(--ink); color: var(--ink);
} }
/* 统计数字格 */ /* 统计数字格:白底细线,避免灰块 */
.j13-stat { .j13-stat {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 3px; gap: 3px;
min-width: 0; min-width: 0;
padding: 11px 13px; padding: 11px 13px;
background: var(--panel-2); background: transparent;
border: 1px solid var(--line); border: 1px solid var(--line);
border-radius: var(--r-sm); border-radius: var(--r-sm);
} }
.j13-stat .j13-stat-num { .j13-stat .j13-stat-num {
font-size: 22px; font-size: 22px;
font-weight: 800; font-weight: 500;
line-height: 1.15; line-height: 1.15;
letter-spacing: -0.015em; letter-spacing: -0.015em;
color: var(--ink); color: var(--ink);
@@ -1453,7 +1472,12 @@ a.j13-mention-token:hover {
} }
.j13-pulse-cell { .j13-pulse-cell {
min-width: 0; min-width: 0;
padding: 12px 14px 11px; display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
padding: 14px 12px;
background: transparent; background: transparent;
border: 0; border: 0;
border-radius: 0; border-radius: 0;
@@ -1467,6 +1491,7 @@ a.j13-mention-token:hover {
.j13-pulse-lab { .j13-pulse-lab {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
gap: 5px; gap: 5px;
font-size: 11.5px; font-size: 11.5px;
font-weight: 400; font-weight: 400;
@@ -1475,7 +1500,7 @@ a.j13-mention-token:hover {
} }
.j13-pulse-num { .j13-pulse-num {
margin-top: 6px; margin-top: 6px;
font-size: 22px; font-size: 18px;
font-weight: 500; font-weight: 500;
line-height: 1.05; line-height: 1.05;
letter-spacing: -0.015em; letter-spacing: -0.015em;
@@ -1485,6 +1510,7 @@ a.j13-mention-token:hover {
.j13-pulse-foot { .j13-pulse-foot {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center;
gap: 3px; gap: 3px;
margin-top: 6px; margin-top: 6px;
font-size: 10.5px; font-size: 10.5px;

View File

@@ -24,7 +24,8 @@ const jakarta = Plus_Jakarta_Sans({
}); });
const notoSC = Noto_Sans_SC({ const notoSC = Noto_Sans_SC({
weight: ["400", "500", "700", "900"], // 须覆盖站内实际用到的字重:缺档时浏览器会伪粗(synthetic bold),中文在 2K 屏发虚发糊
weight: ["400", "500", "600", "700", "800", "900"],
variable: "--font-noto-sc", variable: "--font-noto-sc",
display: "swap", display: "swap",
}); });

View File

@@ -486,8 +486,8 @@ export default function CommentSection({
</form> </form>
) : ( ) : (
<div <div
className="mb-8 px-5 py-4 rounded-2xl flex items-center justify-between gap-4 flex-wrap" className="mb-8 px-5 py-4 rounded-2xl flex items-center justify-between gap-4 flex-wrap border"
style={{ background: "var(--panel-2)" }} style={{ borderColor: "var(--line)", background: "transparent" }}
> >
<span className="text-sm" style={{ color: "var(--ink-2)" }}> <span className="text-sm" style={{ color: "var(--ink-2)" }}>
登录后参与讨论 登录后参与讨论

View File

@@ -20,6 +20,7 @@ import {
ChevronDown, ChevronDown,
ShieldCheck, ShieldCheck,
MessageSquare, MessageSquare,
LayoutGrid,
} from "lucide-react"; } from "lucide-react";
import { apiLogout, apiMe, apiChatUnreadSummary, type User } from "@/lib/api"; import { apiLogout, apiMe, apiChatUnreadSummary, type User } from "@/lib/api";
import { hasAuthCookieHint } from "@/lib/cookies"; import { hasAuthCookieHint } from "@/lib/cookies";
@@ -233,14 +234,21 @@ export default function Header({
</span> </span>
</span> </span>
</Link> </Link>
<nav className="hidden lg:flex items-center gap-1 pl-3" style={{ borderLeft: "1px solid var(--line)" }}> <nav className="hidden lg:flex items-center gap-1.5 pl-3" style={{ borderLeft: "1px solid var(--line)" }}>
<NavPill href="/" active={pathname === "/"} icon={<Home size={14} />}> <NavPill href="/" active={pathname === "/"} icon={<Home size={15} />}>
首页 首页
</NavPill> </NavPill>
<NavPill
href="/boards"
active={pathname === "/boards" || pathname?.startsWith("/board/") === true}
icon={<LayoutGrid size={15} />}
>
板块
</NavPill>
</nav> </nav>
</div> </div>
{/* 中部留白:为后续主导航菜单项预留位置 */} {/* 中部弹性留白,把搜索与操作区推到右侧 */}
<div className="hidden lg:block flex-1" aria-hidden /> <div className="hidden lg:block flex-1" aria-hidden />
{/* 右侧操作区:搜索靠右停靠 + 桌面/移动共用铃铛(仅挂载一次,避免重复轮询), {/* 右侧操作区:搜索靠右停靠 + 桌面/移动共用铃铛(仅挂载一次,避免重复轮询),
@@ -370,6 +378,12 @@ export default function Header({
</form> </form>
<div className="flex flex-col"> <div className="flex flex-col">
<MobileLink href="/" active={pathname === "/"}>首页</MobileLink> <MobileLink href="/" active={pathname === "/"}>首页</MobileLink>
<MobileLink
href="/boards"
active={pathname === "/boards" || pathname?.startsWith("/board/") === true}
>
板块
</MobileLink>
{user && <MobileLink href="/compose">发帖</MobileLink>} {user && <MobileLink href="/compose">发帖</MobileLink>}
{user && ( {user && (
<MobileLink href="/chat" active={pathname?.startsWith("/chat") ?? false}> <MobileLink href="/chat" active={pathname?.startsWith("/chat") ?? false}>
@@ -431,11 +445,11 @@ function NavPill({
return ( return (
<Link <Link
href={href} href={href}
className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full text-[13.5px] transition-colors" className="inline-flex items-center gap-1.5 px-3.5 py-2 rounded-full text-[15px] font-semibold transition-colors"
style={ style={
active active
? { background: "var(--accent-soft)", color: "var(--accent)" } ? { background: "var(--accent-soft)", color: "var(--accent)" }
: { color: "var(--ink-2)" } : { color: "var(--ink)" }
} }
> >
{icon} {icon}
@@ -456,7 +470,7 @@ function MobileLink({
return ( return (
<Link <Link
href={href} href={href}
className="px-3 py-3 rounded-2xl text-[15px] transition-colors" className="px-3 py-3 rounded-2xl text-[16px] font-semibold transition-colors"
style={{ style={{
color: active ? "var(--accent)" : "var(--ink)", color: active ? "var(--accent)" : "var(--ink)",
background: active ? "var(--accent-soft)" : "transparent", background: active ? "var(--accent-soft)" : "transparent",

View File

@@ -72,10 +72,10 @@ function QuestionPanel({ postId, state }: { postId: number; state: QuestionState
}; };
return ( return (
<section className="j13-interact-card"> <section className={`j13-interact-card${state.solved ? " is-solved" : " is-unsolved"}`}>
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
<div> <div>
<h2 className="font-semibold text-[15px]" style={{ color: "var(--ink)" }}> <h2 className="text-[15px] font-medium" style={{ color: "var(--ink)" }}>
问答 · {state.solved ? "已解决" : "未解决"} 问答 · {state.solved ? "已解决" : "未解决"}
</h2> </h2>
<p className="meta text-[12.5px] mt-1"> <p className="meta text-[12.5px] mt-1">

View File

@@ -40,8 +40,8 @@ export default function PostRow({
}`} }`}
style={{ style={{
borderColor: "var(--line)", borderColor: "var(--line)",
paddingTop: compact ? 11 : 18, paddingTop: compact ? 15 : 22,
paddingBottom: compact ? 11 : 18, paddingBottom: compact ? 15 : 22,
animationDelay: `${Math.min(index, 9) * 35}ms`, animationDelay: `${Math.min(index, 9) * 35}ms`,
}} }}
> >

View File

@@ -154,7 +154,7 @@ function HotRanking({ posts }: { posts: PostListItem[] }) {
<span className="j13-rank-no">{i + 1}</span> <span className="j13-rank-no">{i + 1}</span>
<span className="min-w-0 flex-1"> <span className="min-w-0 flex-1">
<span <span
className="block truncate text-[13px] font-normal leading-snug transition-colors group-hover:text-[var(--accent)]" className="block truncate text-[13px] font-medium leading-snug transition-colors group-hover:text-[var(--accent)]"
style={{ color: "var(--ink)" }} style={{ color: "var(--ink)" }}
> >
{p.title} {p.title}
@@ -235,7 +235,7 @@ function ActiveUsers({ users }: { users: ActiveUser[] }) {
<Avatar name={name} src={u.avatar} size={30} /> <Avatar name={name} src={u.avatar} size={30} />
<span className="flex-1 min-w-0"> <span className="flex-1 min-w-0">
<span <span
className="block truncate text-[13px] leading-tight" className="block truncate text-[13px] font-medium leading-tight"
style={{ color: "var(--ink)" }} style={{ color: "var(--ink)" }}
> >
{name} {name}