字号调整
This commit is contained in:
1 parent
0c5938a5a3
commit
fa41d620fd
6 files changed
+68
-28
No files matched your search
@@ -6,8 +6,10 @@ import { useLocalSettings } from "@/core/settings";
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 基准字号 = 16px,对应《深蓝色 UI 规范》§2.1.2 后台系统正文字号(16px Regular)。
|
* 基准字号 = 16px,对应《深蓝色 UI 规范》§2.1.2 后台系统正文字号(16px Regular)。
|
||||||
* 用户在「外观 → 字号」里选择的倍数作用于 <html> 根元素的 font-size;由于 Tailwind
|
* 用户在「外观 → 字号」里选择的倍数通过 CSS 变量 `--ui-font-scale` 生效:globals.css
|
||||||
* 的字号 / 间距基于 rem,整套界面会随之按比例放大 / 缩小。`fontScale === 1` 即默认 16px。
|
* 只把 Tailwind 的 `--text-*` 字号 token 乘以该倍数,**不动间距 token**,所以放大 / 缩小
|
||||||
|
* 的只有文字本身,padding / margin / 宽高等布局尺寸保持不变,不会把页面挤错位。
|
||||||
|
* `fontScale === 1` 即默认 16px。
|
||||||
*/
|
*/
|
||||||
export const BASE_FONT_PX = 16;
|
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。
|
* 不渲染任何 DOM。
|
||||||
*/
|
*/
|
||||||
export function FontScaleApplier() {
|
export function FontScaleApplier() {
|
||||||
@@ -32,7 +35,10 @@ export function FontScaleApplier() {
|
|||||||
typeof fontScale === "number" && Number.isFinite(fontScale) && fontScale > 0
|
typeof fontScale === "number" && Number.isFinite(fontScale) && fontScale > 0
|
||||||
? fontScale
|
? fontScale
|
||||||
: 1;
|
: 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]);
|
}, [fontScale]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -56,12 +56,12 @@ export function MessageBubble({
|
|||||||
{senderName}
|
{senderName}
|
||||||
</span>
|
</span>
|
||||||
{badge && (
|
{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}
|
{badge}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@@ -139,13 +139,13 @@ export const sharedMarkdownComponents = {
|
|||||||
const isBlock = /language-/.test(className ?? "");
|
const isBlock = /language-/.test(className ?? "");
|
||||||
if (isBlock) {
|
if (isBlock) {
|
||||||
return (
|
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>
|
<code>{children}</code>
|
||||||
</pre>
|
</pre>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
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}
|
{children}
|
||||||
</code>
|
</code>
|
||||||
);
|
);
|
||||||
@@ -161,7 +161,7 @@ export const sharedMarkdownComponents = {
|
|||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
table: ({ children }: { children?: React.ReactNode }) => (
|
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: ({ children }: { children?: React.ReactNode }) => (
|
||||||
<th className="border border-slate-300 px-1.5 py-0.5 bg-slate-50 font-bold text-left">
|
<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
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleToggle}
|
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")} />
|
<BrainIcon className={cn("size-3.5", streaming && "text-primary animate-pulse")} />
|
||||||
<span className={cn(streaming && "animate-pulse")}>{headerLabel}</span>
|
<span className={cn(streaming && "animate-pulse")}>{headerLabel}</span>
|
||||||
@@ -265,7 +265,7 @@ export function ReasoningBlock({
|
|||||||
{open && (
|
{open && (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
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,
|
contentClassName,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -86,10 +86,10 @@ export function MessageStepsCard({
|
|||||||
const display = getStepDisplay(lastReasoning.key, lastReasoning.label, lastReasoning.args);
|
const display = getStepDisplay(lastReasoning.key, lastReasoning.label, lastReasoning.args);
|
||||||
const Icon = display.icon;
|
const Icon = display.icon;
|
||||||
return (
|
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" />
|
<Icon className="size-3.5 text-slate-400" />
|
||||||
<span>{display.label}</span>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ export function MessageStepsCard({
|
|||||||
>
|
>
|
||||||
<ChainOfThoughtStep
|
<ChainOfThoughtStep
|
||||||
label={
|
label={
|
||||||
<span className="text-[11.5px] opacity-60">
|
<span className="text-[calc(11.5px*var(--ui-font-scale,1))] opacity-60">
|
||||||
{showAbove ? "隐藏步骤" : `查看其他 ${priorToolSteps.length} 个步骤`}
|
{showAbove ? "隐藏步骤" : `查看其他 ${priorToolSteps.length} 个步骤`}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -189,9 +189,9 @@ function ToolStep({
|
|||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
label={
|
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="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>
|
</span>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -204,10 +204,10 @@ function ReasoningStep({ step, streaming }: { step: BubbleStep; streaming: boole
|
|||||||
const display = getStepDisplay(step.key, step.label, step.args);
|
const display = getStepDisplay(step.key, step.label, step.args);
|
||||||
const Icon = display.icon;
|
const Icon = display.icon;
|
||||||
return (
|
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")} />
|
<Icon className={cn("size-3.5", streaming ? "text-primary animate-pulse" : "text-slate-400")} />
|
||||||
<span>{display.label}</span>
|
<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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
|||||||
<Cpu className="w-5 h-5 text-primary" strokeWidth={2.5} />
|
<Cpu className="w-5 h-5 text-primary" strokeWidth={2.5} />
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-sm font-extrabold text-slate-900">多智能体圆桌会商中心</h3>
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -202,7 +202,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onResumeRoundtable}
|
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
|
pauseFlash
|
||||||
? "ring-2 ring-emerald-400 ring-offset-1 animate-pulse"
|
? "ring-2 ring-emerald-400 ring-offset-1 animate-pulse"
|
||||||
: ""
|
: ""
|
||||||
@@ -215,7 +215,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onPauseRoundtable}
|
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" />
|
<Pause className="w-3.5 h-3.5" />
|
||||||
暂停会商
|
暂停会商
|
||||||
@@ -279,13 +279,13 @@ export function Step2Panel(props: Step2PanelProps) {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className="text-xs font-extrabold text-amber-900">总控协调需要澄清</span>
|
<span className="text-xs font-extrabold text-amber-900">总控协调需要澄清</span>
|
||||||
{pendingClarification.clarificationType && (
|
{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}
|
{pendingClarification.clarificationType}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{pendingClarification.context && (
|
{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">
|
<p className="text-xs text-slate-800 leading-relaxed font-medium whitespace-pre-wrap break-words">
|
||||||
{pendingClarification.question}
|
{pendingClarification.question}
|
||||||
@@ -306,7 +306,7 @@ export function Step2Panel(props: Step2PanelProps) {
|
|||||||
key={`${idx}-${label}`}
|
key={`${idx}-${label}`}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onSubmitClarification(label)}
|
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}
|
{label}
|
||||||
</button>
|
</button>
|
||||||
@@ -580,17 +580,17 @@ function PresentFileCard({
|
|||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
<FileIcon className="mt-0.5 size-4 shrink-0 text-slate-400" />
|
<FileIcon className="mt-0.5 size-4 shrink-0 text-slate-400" />
|
||||||
<span
|
<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}
|
title={filename}
|
||||||
>
|
>
|
||||||
{filename}
|
{filename}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between gap-2">
|
<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}
|
{typeLabel}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-[10px] text-slate-400">点击预览</span>
|
<span className="text-[calc(10px*var(--ui-font-scale,1))] text-slate-400">点击预览</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
@import "tailwindcss";
|
/* 注意:不要在这里 `@import "tailwindcss"`。Tailwind 已由全局 globals.css 引入,
|
||||||
|
* 本文件被打进同一份样式表,再次 import 会把整套 theme/utilities 重复发一遍
|
||||||
|
* (CSS 体积翻倍,且重复发出的 --text-* 等主题变量会和全局覆盖打架)。
|
||||||
|
* 本文件只写圆桌页自己的作用域规则即可。 */
|
||||||
|
|
||||||
/* 圆桌规划 — 浅色红色主题(对齐 docs/浅红色ui修改.md) */
|
/* 圆桌规划 — 浅色红色主题(对齐 docs/浅红色ui修改.md) */
|
||||||
.roundtable-planning {
|
.roundtable-planning {
|
||||||
|
|||||||
@@ -820,3 +820,34 @@
|
|||||||
border-color: var(--border);
|
border-color: var(--border);
|
||||||
outline-color: var(--ring);
|
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));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user