字号调整

This commit is contained in:
fengxiangdebaozi committed 2026-06-01 22:17:39 +08:00
1 parent 0c5938a5a3
commit fa41d620fd
6 files changed
+68 -28

No files matched your search

+10 -4
View File
@@ -6,8 +6,10 @@ import { useLocalSettings } from "@/core/settings";
/**
* 基准字号 = 16px,对应《深蓝色 UI 规范》§2.1.2 后台系统正文字号(16px Regular)。
* 用户在「外观 → 字号」里选择的倍数作用于 <html> 根元素的 font-size;由于 Tailwind
* 的字号 / 间距基于 rem,整套界面会随之按比例放大 / 缩小。`fontScale === 1` 即默认 16px。
* 用户在「外观 → 字号」里选择的倍数通过 CSS 变量 `--ui-font-scale` 生效:globals.css
* 只把 Tailwind 的 `--text-*` 字号 token 乘以该倍数,**不动间距 token**,所以放大 / 缩小
* 的只有文字本身,padding / margin / 宽高等布局尺寸保持不变,不会把页面挤错位。
* `fontScale === 1` 即默认 16px。
*/
export const BASE_FONT_PX = 16;
@@ -20,7 +22,8 @@ export const FONT_SCALE_OPTIONS: { value: number; label: string; px: number }[]
];
/**
* 将用户选择的字号倍数应用到 <html> 根元素。挂在应用根部,保证刷新后即时生效、全局统一。
* 把用户选择的字号倍数写到 <html> 的 `--ui-font-scale` CSS 变量。挂在应用根部,
* 保证刷新后即时生效、全局统一。只设变量、不直接改 font-size,因此布局不受影响。
* 不渲染任何 DOM。
*/
export function FontScaleApplier() {
@@ -32,7 +35,10 @@ export function FontScaleApplier() {
typeof fontScale === "number" && Number.isFinite(fontScale) && fontScale > 0
? fontScale
: 1;
document.documentElement.style.fontSize = `${BASE_FONT_PX * scale}px`;
const root = document.documentElement;
root.style.setProperty("--ui-font-scale", String(scale));
// 清掉旧实现可能残留的根级 font-size 内联样式(旧版用它做整页缩放)。
root.style.removeProperty("font-size");
}, [fontScale]);
return null;
@@ -56,12 +56,12 @@ export function MessageBubble({
{senderName}
</span>
{badge && (
<span className="text-[9px] font-mono font-black uppercase text-[var(--brand-900)] bg-[var(--brand-200)] border border-red-200 px-1.5 py-0.2 rounded">
<span className="text-[calc(9px*var(--ui-font-scale,1))] font-mono font-black uppercase text-[var(--brand-900)] bg-[var(--brand-200)] border border-red-200 px-1.5 py-0.2 rounded">
{badge}
</span>
)}
</div>
<span className="text-[10px] text-slate-400 font-mono font-medium shrink-0">{time}</span>
<span className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400 font-mono font-medium shrink-0">{time}</span>
</div>
{children}
</div>
@@ -139,13 +139,13 @@ export const sharedMarkdownComponents = {
const isBlock = /language-/.test(className ?? "");
if (isBlock) {
return (
<pre className="bg-slate-100 text-slate-800 rounded-md p-2 my-1 overflow-x-auto text-[11px] font-mono">
<pre className="bg-slate-100 text-slate-800 rounded-md p-2 my-1 overflow-x-auto text-[calc(11px*var(--ui-font-scale,1))] font-mono">
<code>{children}</code>
</pre>
);
}
return (
<code className="bg-slate-100 text-slate-800 rounded px-1 py-0.5 text-[11px] font-mono">
<code className="bg-slate-100 text-slate-800 rounded px-1 py-0.5 text-[calc(11px*var(--ui-font-scale,1))] font-mono">
{children}
</code>
);
@@ -161,7 +161,7 @@ export const sharedMarkdownComponents = {
</a>
),
table: ({ children }: { children?: React.ReactNode }) => (
<table className="my-1 border-collapse text-[11px]">{children}</table>
<table className="my-1 border-collapse text-[calc(11px*var(--ui-font-scale,1))]">{children}</table>
),
th: ({ children }: { children?: React.ReactNode }) => (
<th className="border border-slate-300 px-1.5 py-0.5 bg-slate-50 font-bold text-left">
@@ -254,7 +254,7 @@ export function ReasoningBlock({
<button
type="button"
onClick={handleToggle}
className="inline-flex items-center gap-1.5 text-[11.5px] text-slate-500 hover:text-slate-700 transition-colors cursor-pointer"
className="inline-flex items-center gap-1.5 text-[calc(11.5px*var(--ui-font-scale,1))] text-slate-500 hover:text-slate-700 transition-colors cursor-pointer"
>
<BrainIcon className={cn("size-3.5", streaming && "text-primary animate-pulse")} />
<span className={cn(streaming && "animate-pulse")}>{headerLabel}</span>
@@ -265,7 +265,7 @@ export function ReasoningBlock({
{open && (
<div
className={cn(
"rounded-md border border-slate-200 bg-slate-50/60 px-3 py-2 text-[11.5px] text-slate-600 leading-relaxed",
"rounded-md border border-slate-200 bg-slate-50/60 px-3 py-2 text-[calc(11.5px*var(--ui-font-scale,1))] text-slate-600 leading-relaxed",
contentClassName,
)}
>
@@ -86,10 +86,10 @@ export function MessageStepsCard({
const display = getStepDisplay(lastReasoning.key, lastReasoning.label, lastReasoning.args);
const Icon = display.icon;
return (
<div className={cn("flex items-center gap-2 text-[11.5px] text-slate-500 py-0.5", className)}>
<div className={cn("flex items-center gap-2 text-[calc(11.5px*var(--ui-font-scale,1))] text-slate-500 py-0.5", className)}>
<Icon className="size-3.5 text-slate-400" />
<span>{display.label}</span>
<span className="text-[10px] text-slate-400 font-mono">{lastReasoning.ts}</span>
<span className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400 font-mono">{lastReasoning.ts}</span>
</div>
);
}
@@ -108,7 +108,7 @@ export function MessageStepsCard({
>
<ChainOfThoughtStep
label={
<span className="text-[11.5px] opacity-60">
<span className="text-[calc(11.5px*var(--ui-font-scale,1))] opacity-60">
{showAbove ? "隐藏步骤" : `查看其他 ${priorToolSteps.length} 个步骤`}
</span>
}
@@ -189,9 +189,9 @@ function ToolStep({
: undefined
}
label={
<span className="text-[12px] text-slate-700">
<span className="text-[calc(12px*var(--ui-font-scale,1))] text-slate-700">
<span className="font-medium">{display.label}</span>
<span className="ml-2 text-[10px] text-slate-400 font-mono">{step.ts}</span>
<span className="ml-2 text-[calc(10px*var(--ui-font-scale,1))] text-slate-400 font-mono">{step.ts}</span>
</span>
}
>
@@ -204,10 +204,10 @@ function ReasoningStep({ step, streaming }: { step: BubbleStep; streaming: boole
const display = getStepDisplay(step.key, step.label, step.args);
const Icon = display.icon;
return (
<div className="flex items-center gap-2 text-[11.5px] text-slate-500">
<div className="flex items-center gap-2 text-[calc(11.5px*var(--ui-font-scale,1))] text-slate-500">
<Icon className={cn("size-3.5", streaming ? "text-primary animate-pulse" : "text-slate-400")} />
<span>{display.label}</span>
<span className="text-[10px] text-slate-400 font-mono">{step.ts}</span>
<span className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400 font-mono">{step.ts}</span>
</div>
);
}
@@ -167,7 +167,7 @@ export function Step2Panel(props: Step2PanelProps) {
<Cpu className="w-5 h-5 text-primary" strokeWidth={2.5} />
<div>
<h3 className="text-sm font-extrabold text-slate-900">多智能体圆桌会商中心</h3>
<p className="text-[10px] text-slate-400 font-medium">
<p className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400 font-medium">
分布式领域专家实时动态博弈与纳什协商收敛中
</p>
</div>
@@ -202,7 +202,7 @@ export function Step2Panel(props: Step2PanelProps) {
<button
type="button"
onClick={onResumeRoundtable}
className={`bg-emerald-100 hover:bg-emerald-200 text-emerald-800 text-[10px] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-emerald-200/40 shadow-sm ${
className={`bg-emerald-100 hover:bg-emerald-200 text-emerald-800 text-[calc(10px*var(--ui-font-scale,1))] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-emerald-200/40 shadow-sm ${
pauseFlash
? "ring-2 ring-emerald-400 ring-offset-1 animate-pulse"
: ""
@@ -215,7 +215,7 @@ export function Step2Panel(props: Step2PanelProps) {
<button
type="button"
onClick={onPauseRoundtable}
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-[10px] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-amber-200/40 shadow-sm"
className="bg-amber-100 hover:bg-amber-200 text-amber-800 text-[calc(10px*var(--ui-font-scale,1))] font-bold px-2.5 py-1 rounded-xl flex items-center gap-1 transition border border-amber-200/40 shadow-sm"
>
<Pause className="w-3.5 h-3.5" />
暂停会商
@@ -279,13 +279,13 @@ export function Step2Panel(props: Step2PanelProps) {
<div className="flex items-center gap-2">
<span className="text-xs font-extrabold text-amber-900">总控协调需要澄清</span>
{pendingClarification.clarificationType && (
<span className="text-[9px] font-mono font-black uppercase text-amber-900 bg-amber-200 border border-amber-300 px-1.5 py-0.2 rounded">
<span className="text-[calc(9px*var(--ui-font-scale,1))] font-mono font-black uppercase text-amber-900 bg-amber-200 border border-amber-300 px-1.5 py-0.2 rounded">
{pendingClarification.clarificationType}
</span>
)}
</div>
{pendingClarification.context && (
<p className="text-[11px] text-amber-800 italic">{pendingClarification.context}</p>
<p className="text-[calc(11px*var(--ui-font-scale,1))] text-amber-800 italic">{pendingClarification.context}</p>
)}
<p className="text-xs text-slate-800 leading-relaxed font-medium whitespace-pre-wrap break-words">
{pendingClarification.question}
@@ -306,7 +306,7 @@ export function Step2Panel(props: Step2PanelProps) {
key={`${idx}-${label}`}
type="button"
onClick={() => onSubmitClarification(label)}
className="text-[11px] font-bold px-3 py-1.5 rounded-full bg-white border border-amber-300 text-amber-900 hover:bg-amber-100 transition active:scale-95 cursor-pointer"
className="text-[calc(11px*var(--ui-font-scale,1))] font-bold px-3 py-1.5 rounded-full bg-white border border-amber-300 text-amber-900 hover:bg-amber-100 transition active:scale-95 cursor-pointer"
>
{label}
</button>
@@ -580,17 +580,17 @@ function PresentFileCard({
<div className="flex items-start gap-2">
<FileIcon className="mt-0.5 size-4 shrink-0 text-slate-400" />
<span
className="truncate text-[12px] font-medium text-slate-700"
className="truncate text-[calc(12px*var(--ui-font-scale,1))] font-medium text-slate-700"
title={filename}
>
{filename}
</span>
</div>
<div className="flex items-center justify-between gap-2">
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-[10px] font-mono font-semibold text-slate-500">
<span className="rounded bg-slate-100 px-1.5 py-0.5 text-[calc(10px*var(--ui-font-scale,1))] font-mono font-semibold text-slate-500">
{typeLabel}
</span>
<span className="text-[10px] text-slate-400">点击预览</span>
<span className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400">点击预览</span>
</div>
</button>
);
@@ -1,4 +1,7 @@
@import "tailwindcss";
/* 注意:不要在这里 `@import "tailwindcss"`。Tailwind 已由全局 globals.css 引入,
* 本文件被打进同一份样式表,再次 import 会把整套 theme/utilities 重复发一遍
* (CSS 体积翻倍,且重复发出的 --text-* 等主题变量会和全局覆盖打架)。
* 本文件只写圆桌页自己的作用域规则即可。 */
/* 圆桌规划 — 浅色红色主题(对齐 docs/浅红色ui修改.md) */
.roundtable-planning {
+31
View File
@@ -820,3 +820,34 @@
border-color: var(--border);
outline-color: var(--ring);
}
/* ─── 全局字号缩放(只改字号,不动布局)──────────────────────────────────
* 用户在「设置 → 外观 → 字号」里选的倍数由 FontScaleApplier 写到
* <html> 的 `--ui-font-scale`(默认 1)。这里只把 Tailwind 的 `--text-*`
* 字号 token 乘以该倍数 —— 间距 token(--spacing)原样不动,所以 padding /
* margin / gap / 宽高这些布局尺寸不随字号变化,避免放大字体把页面挤错位。
* 行高用 Tailwind 默认的无单位比值,会跟随字号等比变化(文字不会重叠)。
* 不在 @layer 内,优先级高于 Tailwind 的主题层变量,确保覆盖生效。 */
:root {
--ui-font-scale: 1;
--text-xs: calc(0.75rem * var(--ui-font-scale, 1));
--text-sm: calc(0.875rem * var(--ui-font-scale, 1));
--text-base: calc(1rem * var(--ui-font-scale, 1));
--text-lg: calc(1.125rem * var(--ui-font-scale, 1));
--text-xl: calc(1.25rem * var(--ui-font-scale, 1));
--text-2xl: calc(1.5rem * var(--ui-font-scale, 1));
--text-3xl: calc(1.875rem * var(--ui-font-scale, 1));
--text-4xl: calc(2.25rem * var(--ui-font-scale, 1));
--text-5xl: calc(3rem * var(--ui-font-scale, 1));
--text-6xl: calc(3.75rem * var(--ui-font-scale, 1));
--text-7xl: calc(4.5rem * var(--ui-font-scale, 1));
--text-8xl: calc(6rem * var(--ui-font-scale, 1));
--text-9xl: calc(8rem * var(--ui-font-scale, 1));
}
/* 没有显式 text-* 类的元素(继承自 body 的默认正文)也跟随缩放。
* 只设 font-size,不影响任何盒模型尺寸。 */
body {
font-size: calc(1rem * var(--ui-font-scale, 1));
}