@bytechain.cn/colamd-themes 0.3.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/.claude/skills/colamd-themes-preview.skill.md +333 -0
  2. package/.claude/skills/colamd-themes.skill.md +10 -0
  3. package/.dsh/skills/colamd-themes/SKILL.md +14 -0
  4. package/.github/supported-topics.yml +17 -0
  5. package/.hermes/skills/tools/colamd-themes/SKILL.md +14 -0
  6. package/.openclaw/skills/colamd-themes/SKILL.md +1 -37
  7. package/.opencode/skills/colamd-themes/SKILL.md +17 -0
  8. package/.trae/rules/colamd-themes.md +0 -36
  9. package/CHANGELOG.md +318 -241
  10. package/DSH_SUPPORT_SUMMARY.md +87 -0
  11. package/README.md +414 -384
  12. package/README_CN.md +412 -384
  13. package/RELEASENOTE.md +541 -389
  14. package/bytechain.cn-colamd-themes-0.5.0.tgz +0 -0
  15. package/dist/cli.js +36 -55
  16. package/dist/cli.js.map +1 -1
  17. package/dist/color-utils.d.ts +1 -0
  18. package/dist/color-utils.js +25 -6
  19. package/dist/color-utils.js.map +1 -1
  20. package/dist/extractors/pdf-extractor.js +6 -1
  21. package/dist/extractors/pdf-extractor.js.map +1 -1
  22. package/dist/extractors/url-extractor.d.ts +0 -4
  23. package/dist/extractors/url-extractor.js +13 -126
  24. package/dist/extractors/url-extractor.js.map +1 -1
  25. package/dist/generator.d.ts +1 -1
  26. package/dist/generator.js +32 -11
  27. package/dist/generator.js.map +1 -1
  28. package/dist/models.d.ts +5 -4
  29. package/dist/models.js +2 -3
  30. package/dist/models.js.map +1 -1
  31. package/dist/renderer.d.ts +4 -2
  32. package/dist/renderer.js +64 -84
  33. package/dist/renderer.js.map +1 -1
  34. package/dist/templates/template.css +220 -498
  35. package/dist/templates/theme-paradigm.md +530 -658
  36. package/dist/templates/theme-template.hbs +256 -370
  37. package/dist/theme-store.js +19 -3
  38. package/dist/theme-store.js.map +1 -1
  39. package/dist/utils/document-paradigm.d.ts +12 -0
  40. package/dist/utils/document-paradigm.js +109 -0
  41. package/dist/utils/document-paradigm.js.map +1 -0
  42. package/dist/validators.d.ts +4 -1
  43. package/dist/validators.js +115 -1
  44. package/dist/validators.js.map +1 -1
  45. package/mcp-server/dist/index.d.ts +13 -0
  46. package/mcp-server/dist/index.d.ts.map +1 -0
  47. package/mcp-server/dist/index.js +0 -0
  48. package/mcp-server/dist/index.js.map +1 -0
  49. package/mcp-server/package-lock.json +1759 -0
  50. package/mcp-server/package.json +24 -0
  51. package/mcp-server/src/index.ts +0 -0
  52. package/mcp-server/tsconfig.json +19 -0
  53. package/package.json +54 -36
  54. package/skills/build-skills.sh +30 -5
  55. package/skills/colamd-themes/SKILL.md +180 -178
  56. package/src/cli.ts +474 -487
  57. package/src/color-systems.ts +289 -289
  58. package/src/color-utils.ts +137 -120
  59. package/src/contrast.ts +66 -66
  60. package/src/docx-style-paradigm.ts +811 -811
  61. package/src/export-cli.ts +356 -356
  62. package/src/extractors/base.ts +8 -8
  63. package/src/extractors/docx-extractor.ts +417 -417
  64. package/src/extractors/pdf-extractor.ts +533 -527
  65. package/src/extractors/url-extractor.ts +846 -981
  66. package/src/generator.ts +197 -169
  67. package/src/index.ts +29 -29
  68. package/src/models.ts +212 -212
  69. package/src/renderer.ts +332 -359
  70. package/src/templates/template.css +220 -498
  71. package/src/templates/theme-paradigm.md +530 -658
  72. package/src/templates/theme-template.hbs +256 -370
  73. package/src/theme-store.ts +185 -170
  74. package/src/types/pdf-parse.d.ts +12 -12
  75. package/src/utils/cli-utils.ts +84 -84
  76. package/src/utils/document-paradigm.ts +118 -0
  77. package/src/validators.ts +298 -176
  78. package/themes/academic-paper-pt.css +353 -1805
  79. package/themes/academic-paper.css +350 -1099
  80. package/themes/academic-style.css +342 -2430
  81. package/themes/colly.css +256 -370
  82. package/themes/elegant.css +288 -671
  83. package/themes/forest-ink.css +240 -664
  84. package/themes/guizang.css +250 -732
  85. package/themes/hermes-security.css +279 -0
  86. package/themes/meeting-minutes.css +256 -370
  87. package/themes/pixso-design.css +278 -1261
  88. package/themes/salvator-blog.css +256 -370
  89. package/themes/shimo-theme.css +256 -0
  90. package/themes/swiss-design.css +285 -746
  91. package/themes/template.css +220 -498
  92. package/themes/trae-blue.css +280 -737
  93. package/themes/word-contract.css +249 -0
  94. package/themes-preview/demo-content.md +187 -187
  95. package/tsconfig.json +18 -18
  96. package/src/mermaid-presets.ts +0 -142
  97. package/themes/swiss-design copy.css +0 -746
  98. package/themes-preview/colly-preview.html +0 -623
  99. package/themes-preview/meeting-minutes-preview.html +0 -625
  100. package/themes-preview/salvator-blog-preview.html +0 -623
@@ -1,811 +1,811 @@
1
- /**
2
- * DOCX 文档样式规范体系 — v1.0
3
- *
4
- * 核心功能:
5
- * 1. 定义完整的文档元素样式层级(标题 H1-H6、正文、表格等)
6
- * 2. 提供 WCAG 2.1 AAA 级对比度合规的标准参考值
7
- * 3. 实现打印友好型灰度/低饱和度配色方案
8
- * 4. 提供样式提取 fallback 与规范化工具
9
- *
10
- * 设计原则:
11
- * - 文字色使用灰度轴(HSL S ≤ 0.05)或极低饱和度(S ≤ 0.15)
12
- * - 背景色保持近白/近黑中性,饱和度 ≤ 0.03
13
- * - 所有前景/背景对比度满足 WCAG AA (4.5:1) 或 AAA (7:1)
14
- * - 行间距遵循中文排版规范(正文 1.5-1.9,标题 1.25-1.4)
15
- */
16
-
17
- import { hexToRgb, rgbToHex, lighten, darken } from "./color-utils.js";
18
- import { relativeLuminance, contrastRatio, hslSaturation, hslLightness } from "./contrast.js";
19
-
20
- // ═══════════════════════════════════════════════════════════
21
- // 类型定义
22
- // ═══════════════════════════════════════════════════════════
23
-
24
- /** 单个字体样式的完整定义 */
25
- export interface FontStyleDefinition {
26
- /** 字体家族(CSS font-family 值) */
27
- fontFamily: string;
28
- /** 字号(px) */
29
- fontSize: number;
30
- /** 字重(100-900) */
31
- fontWeight: number;
32
- /** 文字颜色(hex) */
33
- color: string;
34
- /** 行高倍率 */
35
- lineHeight: number;
36
- /** 字间距(em,可选) */
37
- letterSpacing?: number;
38
- /** 段后间距(em,可选) */
39
- marginBottom?: number;
40
- }
41
-
42
- /** 表格单元格样式定义 */
43
- export interface TableCellStyle {
44
- /** 表头字体家族 */
45
- headerFontFamily: string;
46
- /** 表头字号(px) */
47
- headerFontSize: number;
48
- /** 表头字重 */
49
- headerFontWeight: number;
50
- /** 表头文字颜色 */
51
- headerColor: string;
52
- /** 表头背景颜色 */
53
- headerBgColor: string;
54
- /** 表头行高 */
55
- headerLineHeight: number;
56
-
57
- /** 单元格字体家族 */
58
- cellFontFamily: string;
59
- /** 单元格字号(px) */
60
- cellFontSize: number;
61
- /** 单元格文字颜色 */
62
- cellColor: string;
63
- /** 单元格背景颜色 */
64
- cellBgColor: string;
65
- /** 单元格行高 */
66
- cellLineHeight: number;
67
- /** 单元格内边距 */
68
- cellPadding: string;
69
- /** 边框颜色 */
70
- borderColor: string;
71
- /** 边框宽度 */
72
- borderWidth: string;
73
- }
74
-
75
- /** 完整的文档样式规范 */
76
- export interface DocumentStyleParadigm {
77
- /** 文档背景颜色 */
78
- pageBackground: string;
79
- /** 各级标题样式映射 */
80
- headings: Record<"h1" | "h2" | "h3" | "h4" | "h5" | "h6", FontStyleDefinition>;
81
- /** 正文样式 */
82
- body: FontStyleDefinition;
83
- /** 引用块样式 */
84
- blockquote: FontStyleDefinition & { borderLeftColor: string; bgColor: string };
85
- /** 代码块样式 */
86
- codeBlock: FontStyleDefinition & { bgColor: string };
87
- /** 内联代码样式 */
88
- inlineCode: { fontSize: number; color: string; bgColor: string };
89
- /** 表格样式 */
90
- table: TableCellStyle;
91
- /** 链接/强调色 */
92
- accentColor: string;
93
- /** 弱化文字颜色(脚注、辅助信息) */
94
- mutedTextColor: string;
95
- /** 选区高亮色 */
96
- selectionBg: string;
97
- }
98
-
99
- /** 打印优化配置 */
100
- export interface PrintOptimization {
101
- /** 是否启用纯灰度模式(强制所有彩色转灰度) */
102
- forceGrayscale: boolean;
103
- /** 最大文字饱和度阈值(0-1) */
104
- maxTextSaturation: number;
105
- /** 最小对比度要求(WCAG 级别) */
106
- minContrastRatio: "AA" | "AAA";
107
- /** 背景色亮度调整(-1 到 1,负值变亮) */
108
- bgBrightnessOffset: number;
109
- }
110
-
111
- // ═══════════════════════════════════════════════════════════
112
- // 常量:标准参考值(Fallback Defaults)
113
- // ═══════════════════════════════════════════════════════════
114
-
115
- /**
116
- * 学术论文标准参考值
117
- * 基于 GB/T 7713-1987 中文学术论文编排规则 + WCAG AAA
118
- */
119
- export const ACADEMIC_PAPER_DEFAULTS: DocumentStyleParadigm = {
120
- pageBackground: "#ffffff",
121
-
122
- headings: {
123
- h1: {
124
- fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
125
- fontSize: 22,
126
- fontWeight: 700,
127
- color: "#1a1a1a",
128
- lineHeight: 1.35,
129
- marginBottom: 0.8,
130
- },
131
- h2: {
132
- fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
133
- fontSize: 18,
134
- fontWeight: 700,
135
- color: "#1a1a1a",
136
- lineHeight: 1.35,
137
- marginBottom: 0.7,
138
- },
139
- h3: {
140
- fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
141
- fontSize: 16,
142
- fontWeight: 600,
143
- color: "#2a2a2a",
144
- lineHeight: 1.4,
145
- marginBottom: 0.6,
146
- },
147
- h4: {
148
- fontFamily: '"SimSun", "Songti SC", serif',
149
- fontSize: 14,
150
- fontWeight: 600,
151
- color: "#333333",
152
- lineHeight: 1.4,
153
- marginBottom: 0.5,
154
- },
155
- h5: {
156
- fontFamily: '"SimSun", "Songti SC", serif',
157
- fontSize: 13,
158
- fontWeight: 600,
159
- color: "#444444",
160
- lineHeight: 1.45,
161
- marginBottom: 0.4,
162
- },
163
- h6: {
164
- fontFamily: '"SimSun", "Songti SC", serif',
165
- fontSize: 12,
166
- fontWeight: 600,
167
- color: "#555555",
168
- lineHeight: 1.5,
169
- marginBottom: 0.3,
170
- },
171
- },
172
-
173
- body: {
174
- fontFamily: '"SimSun", "Songti SC", "Noto Serif SC", Georgia, serif',
175
- fontSize: 16,
176
- fontWeight: 400,
177
- color: "#222222",
178
- lineHeight: 1.75,
179
- letterSpacing: 0.02,
180
- },
181
-
182
- blockquote: {
183
- fontFamily: '"SimSun", "Songti SC", serif',
184
- fontSize: 14,
185
- fontWeight: 400,
186
- color: "#555555",
187
- lineHeight: 1.65,
188
- borderLeftColor: "#888888",
189
- bgColor: "#fafafa",
190
- },
191
-
192
- codeBlock: {
193
- fontFamily: '"Courier New", Consolas, monospace',
194
- fontSize: 13,
195
- fontWeight: 400,
196
- color: "#333333",
197
- lineHeight: 1.5,
198
- bgColor: "#f5f5f5",
199
- },
200
-
201
- inlineCode: {
202
- fontSize: 13,
203
- color: "#c7254e",
204
- bgColor: "#f9f2f4",
205
- },
206
-
207
- table: {
208
- headerFontFamily: '"SimHei", "Heiti SC", sans-serif',
209
- headerFontSize: 13,
210
- headerFontWeight: 700,
211
- headerColor: "#ffffff",
212
- headerBgColor: "#4a4a4a",
213
- headerLineHeight: 1.4,
214
-
215
- cellFontFamily: '"SimSun", "Songti SC", serif',
216
- cellFontSize: 12,
217
- cellColor: "#333333",
218
- cellBgColor: "#ffffff",
219
- cellLineHeight: 1.5,
220
- cellPadding: "8px 12px",
221
- borderColor: "#cccccc",
222
- borderWidth: "1px",
223
- },
224
-
225
- accentColor: "#2b579a",
226
- mutedTextColor: "#666666",
227
- selectionBg: "rgba(43, 87, 154, 0.15)",
228
- };
229
-
230
- /**
231
- * 商务报告标准参考值
232
- * 现代、简洁、打印友好
233
- */
234
- export const BUSINESS_REPORT_DEFAULTS: DocumentStyleParadigm = {
235
- pageBackground: "#ffffff",
236
-
237
- headings: {
238
- h1: {
239
- fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
240
- fontSize: 24,
241
- fontWeight: 700,
242
- color: "#1f2937",
243
- lineHeight: 1.3,
244
- marginBottom: 1.0,
245
- },
246
- h2: {
247
- fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
248
- fontSize: 20,
249
- fontWeight: 600,
250
- color: "#374151",
251
- lineHeight: 1.35,
252
- marginBottom: 0.8,
253
- },
254
- h3: {
255
- fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
256
- fontSize: 17,
257
- fontWeight: 600,
258
- color: "#4b5563",
259
- lineHeight: 1.38,
260
- marginBottom: 0.6,
261
- },
262
- h4: {
263
- fontFamily: '"Inter", -apple-system, sans-serif',
264
- fontSize: 15,
265
- fontWeight: 600,
266
- color: "#6b7280",
267
- lineHeight: 1.4,
268
- marginBottom: 0.5,
269
- },
270
- h5: {
271
- fontFamily: '"Inter", -apple-system, sans-serif',
272
- fontSize: 14,
273
- fontWeight: 500,
274
- color: "#6b7280",
275
- lineHeight: 1.45,
276
- marginBottom: 0.4,
277
- },
278
- h6: {
279
- fontFamily: '"Inter", -apple-system, sans-serif',
280
- fontSize: 13,
281
- fontWeight: 500,
282
- color: "#9ca3af",
283
- lineHeight: 1.5,
284
- marginBottom: 0.3,
285
- },
286
- },
287
-
288
- body: {
289
- fontFamily: '"Inter", "SF Pro Text", -apple-system, "Noto Sans SC", sans-serif',
290
- fontSize: 15,
291
- fontWeight: 400,
292
- color: "#374151",
293
- lineHeight: 1.7,
294
- letterSpacing: 0.01,
295
- },
296
-
297
- blockquote: {
298
- fontFamily: '"Inter", sans-serif',
299
- fontSize: 14,
300
- fontWeight: 400,
301
- color: "#6b7280",
302
- lineHeight: 1.6,
303
- borderLeftColor: "#9ca3af",
304
- bgColor: "#f9fafb",
305
- },
306
-
307
- codeBlock: {
308
- fontFamily: '"JetBrains Mono", "Fira Code", monospace',
309
- fontSize: 12.5,
310
- fontWeight: 400,
311
- color: "#374151",
312
- lineHeight: 1.55,
313
- bgColor: "#f3f4f6",
314
- },
315
-
316
- inlineCode: {
317
- fontSize: 12.5,
318
- color: "#dc2626",
319
- bgColor: "#fef2f2",
320
- },
321
-
322
- table: {
323
- headerFontFamily: '"Inter", -apple-system, sans-serif',
324
- headerFontSize: 12.5,
325
- headerFontWeight: 600,
326
- headerColor: "#ffffff",
327
- headerBgColor: "#4b5563",
328
- headerLineHeight: 1.4,
329
-
330
- cellFontFamily: '"Inter", sans-serif',
331
- cellFontSize: 12,
332
- cellColor: "#374151",
333
- cellBgColor: "#ffffff",
334
- cellLineHeight: 1.5,
335
- cellPadding: "10px 14px",
336
- borderColor: "#e5e7eb",
337
- borderWidth: "1px",
338
- },
339
-
340
- accentColor: "#2563eb",
341
- mutedTextColor: "#9ca3af",
342
- selectionBg: "rgba(37, 99, 235, 0.12)",
343
- };
344
-
345
- /**
346
- * 技术文档标准参考值
347
- * 适合 API 文档、技术手册
348
- */
349
- export const TECHNICAL_DOC_DEFAULTS: DocumentStyleParadigm = {
350
- pageBackground: "#fefefe",
351
-
352
- headings: {
353
- h1: {
354
- fontFamily: '"Inter", "SF Pro Display", system-ui, sans-serif',
355
- fontSize: 28,
356
- fontWeight: 800,
357
- color: "#111827",
358
- lineHeight: 1.25,
359
- marginBottom: 1.2,
360
- },
361
- h2: {
362
- fontFamily: '"Inter", system-ui, sans-serif',
363
- fontSize: 22,
364
- fontWeight: 700,
365
- color: "#1f2937",
366
- lineHeight: 1.3,
367
- marginBottom: 0.9,
368
- },
369
- h3: {
370
- fontFamily: '"Inter", system-ui, sans-serif',
371
- fontSize: 18,
372
- fontWeight: 600,
373
- color: "#374151",
374
- lineHeight: 1.35,
375
- marginBottom: 0.7,
376
- },
377
- h4: {
378
- fontFamily: '"Inter", system-ui, sans-serif',
379
- fontSize: 16,
380
- fontWeight: 600,
381
- color: "#4b5563",
382
- lineHeight: 1.38,
383
- marginBottom: 0.5,
384
- },
385
- h5: {
386
- fontFamily: '"Inter", system-ui, sans-serif',
387
- fontSize: 14,
388
- fontWeight: 500,
389
- color: "#6b7280",
390
- lineHeight: 1.42,
391
- marginBottom: 0.4,
392
- },
393
- h6: {
394
- fontFamily: '"JetBrains Mono", monospace',
395
- fontSize: 13,
396
- fontWeight: 500,
397
- color: "#9ca3af",
398
- lineHeight: 1.5,
399
- marginBottom: 0.3,
400
- },
401
- },
402
-
403
- body: {
404
- fontFamily: '"Inter", "SF Pro Text", system-ui, "Noto Sans SC", sans-serif',
405
- fontSize: 16,
406
- fontWeight: 400,
407
- color: "#1f2937",
408
- lineHeight: 1.75,
409
- },
410
-
411
- blockquote: {
412
- fontFamily: '"Inter", system-ui, sans-serif',
413
- fontSize: 14.5,
414
- fontWeight: 400,
415
- color: "#6b7280",
416
- lineHeight: 1.65,
417
- borderLeftColor: "#d1d5db",
418
- bgColor: "#f9fafb",
419
- },
420
-
421
- codeBlock: {
422
- fontFamily: '"JetBrains Mono", "SF Mono", "Fira Code", monospace',
423
- fontSize: 13.5,
424
- fontWeight: 400,
425
- color: "#e5e7eb",
426
- lineHeight: 1.6,
427
- bgColor: "#1f2937",
428
- },
429
-
430
- inlineCode: {
431
- fontSize: 13,
432
- color: "#dc2626",
433
- bgColor: "#fef2f2",
434
- },
435
-
436
- table: {
437
- headerFontFamily: '"Inter", system-ui, sans-serif',
438
- headerFontSize: 13,
439
- headerFontWeight: 600,
440
- headerColor: "#f9fafb",
441
- headerBgColor: "#374151",
442
- headerLineHeight: 1.4,
443
-
444
- cellFontFamily: '"Inter", sans-serif',
445
- cellFontSize: 13,
446
- cellColor: "#374151",
447
- cellBgColor: "#ffffff",
448
- cellLineHeight: 1.55,
449
- cellPadding: "10px 14px",
450
- borderColor: "#e5e7eb",
451
- borderWidth: "1px",
452
- },
453
-
454
- accentColor: "#2563eb",
455
- mutedTextColor: "#9ca3af",
456
- selectionBg: "rgba(37, 99, 235, 0.15)",
457
- };
458
-
459
- // ═══════════════════════════════════════════════════════════
460
- // 打印友好型灰度/低饱和度配色生成器
461
- // ═══════════════════════════════════════════════════════════
462
-
463
- /**
464
- * 生成打印优化的灰度色板
465
- * @param baseBrightness 页面基础亮度(0=纯黑,1=纯白)
466
- * @param options 打印优化配置
467
- */
468
- export function generatePrintFriendlyGrayscale(
469
- baseBrightness: number = 0.97,
470
- options?: Partial<PrintOptimization>
471
- ): DocumentStyleParadigm {
472
- const opts: PrintOptimization = {
473
- forceGrayscale: true,
474
- maxTextSaturation: 0.05,
475
- minContrastRatio: "AAA",
476
- bgBrightnessOffset: 0,
477
- ...options,
478
- };
479
-
480
- const surfaceValue = Math.round(baseBrightness * 255);
481
- const surfaceHex = rgbToHex(surfaceValue, surfaceValue, surfaceValue);
482
-
483
- const inkValue = Math.max(0, Math.round((1 - baseBrightness) * 255 * 0.92));
484
- const inkHex = rgbToHex(inkValue, inkValue, inkValue);
485
-
486
- const mutedValue = Math.round(inkValue + (surfaceValue - inkValue) * 0.55);
487
- const mutedHex = rgbToHex(mutedValue, mutedValue, mutedValue);
488
-
489
- const dimValue = Math.round(inkValue + (surfaceValue - inkValue) * 0.75);
490
- const dimHex = rgbToHex(dimValue, dimValue, dimValue);
491
-
492
- const panelValue = Math.max(0, Math.round(surfaceValue - 12));
493
- const panelHex = rgbToHex(panelValue, panelValue, panelValue);
494
-
495
- const panelAltValue = Math.max(0, Math.round(surfaceValue - 24));
496
- const panelAltHex = rgbToHex(panelAltValue, panelAltValue, panelAltValue);
497
-
498
- const accentGray = opts.forceGrayscale
499
- ? rgbToHex(Math.round(inkValue * 0.4), Math.round(inkValue * 0.4), Math.round(inkValue * 0.4))
500
- : "#4a5568";
501
-
502
- return {
503
- pageBackground: surfaceHex,
504
-
505
- headings: {
506
- h1: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h1.fontFamily, fontSize: 22, fontWeight: 700, color: inkHex, lineHeight: 1.35, marginBottom: 0.8 },
507
- h2: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily, fontSize: 18, fontWeight: 700, color: inkHex, lineHeight: 1.35, marginBottom: 0.7 },
508
- h3: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h3.fontFamily, fontSize: 16, fontWeight: 600, color: mutedHex, lineHeight: 1.4, marginBottom: 0.6 },
509
- h4: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h4.fontFamily, fontSize: 14, fontWeight: 600, color: mutedHex, lineHeight: 1.4, marginBottom: 0.5 },
510
- h5: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h5.fontFamily, fontSize: 13, fontWeight: 600, color: dimHex, lineHeight: 1.45, marginBottom: 0.4 },
511
- h6: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h6.fontFamily, fontSize: 12, fontWeight: 600, color: dimHex, lineHeight: 1.5, marginBottom: 0.3 },
512
- },
513
-
514
- body: {
515
- fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
516
- fontSize: 16,
517
- fontWeight: 400,
518
- color: rgbToHex(Math.round(inkValue * 0.88), Math.round(inkValue * 0.88), Math.round(inkValue * 0.88)),
519
- lineHeight: 1.75,
520
- letterSpacing: 0.02,
521
- },
522
-
523
- blockquote: {
524
- fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
525
- fontSize: 14,
526
- fontWeight: 400,
527
- color: mutedHex,
528
- lineHeight: 1.65,
529
- borderLeftColor: dimHex,
530
- bgColor: panelHex,
531
- },
532
-
533
- codeBlock: {
534
- fontFamily: '"Courier New", Consolas, monospace',
535
- fontSize: 13,
536
- fontWeight: 400,
537
- color: inkHex,
538
- lineHeight: 1.5,
539
- bgColor: panelAltHex,
540
- },
541
-
542
- inlineCode: {
543
- fontSize: 13,
544
- color: accentGray,
545
- bgColor: lighten(panelAltHex, 0.3),
546
- },
547
-
548
- table: {
549
- headerFontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily,
550
- headerFontSize: 13,
551
- headerFontWeight: 700,
552
- headerColor: surfaceHex,
553
- headerBgColor: rgbToHex(
554
- Math.round(inkValue * 0.72),
555
- Math.round(inkValue * 0.72),
556
- Math.round(inkValue * 0.72)
557
- ),
558
- headerLineHeight: 1.4,
559
-
560
- cellFontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
561
- cellFontSize: 12,
562
- cellColor: rgbToHex(Math.round(inkValue * 0.82), Math.round(inkValue * 0.82), Math.round(inkValue * 0.82)),
563
- cellBgColor: surfaceHex,
564
- cellLineHeight: 1.5,
565
- cellPadding: "8px 12px",
566
- borderColor: rgbToHex(
567
- Math.round(surfaceValue - 40),
568
- Math.round(surfaceValue - 40),
569
- Math.round(surfaceValue - 40)
570
- ),
571
- borderWidth: "1px",
572
- },
573
-
574
- accentColor: accentGray,
575
- mutedTextColor: mutedHex,
576
- selectionBg: `rgba(${Math.round(inkValue * 0.4)}, ${Math.round(inkValue * 0.4)}, ${Math.round(inkValue * 0.4)}, 0.15)`,
577
- };
578
- }
579
-
580
- /**
581
- * 生成低饱和度莫兰迪风格色板(适合打印)
582
- * 保持微弱色相但大幅降低饱和度
583
- */
584
- export function generateMorandiPrintPalette(
585
- hueDeg: number = 210,
586
- saturation: number = 0.08,
587
- ): DocumentStyleParadigm {
588
- const hslToRgb = (h: number, s: number, l: number): [number, number, number] => {
589
- const c = (1 - Math.abs(2 * l - 1)) * s;
590
- const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
591
- const m = l - c / 2;
592
- let r = 0, g = 0, b = 0;
593
- if (h < 60) { r = c; g = x; }
594
- else if (h < 120) { r = x; g = c; }
595
- else if (h < 180) { g = c; b = x; }
596
- else if (h < 240) { g = x; b = c; }
597
- else if (h < 300) { r = x; b = c; }
598
- else { r = c; b = x; }
599
- return [
600
- Math.round((r + m) * 255),
601
- Math.round((g + m) * 255),
602
- Math.round((b + m) * 255),
603
- ];
604
- };
605
-
606
- const surface = rgbToHex(...hslToRgb(hueDeg, 0.01, 0.98));
607
- const ink = rgbToRgbString(hslToRgb(hueDeg, 0.04, 0.12));
608
- const muted = rgbToRgbString(hslToRgb(hueDeg, 0.03, 0.42));
609
- const dim = rgbToRgbString(hslToRgb(hueDeg, 0.02, 0.58));
610
- const panel = rgbToRgbString(hslToRgb(hueDeg, 0.02, 0.95));
611
- const panelAlt = rgbToRgbString(hslToRgb(hueDeg, 0.03, 0.91));
612
- const accent = rgbToRgbString(hslToRgb(hueDeg, saturation, 0.38));
613
- const headerBg = rgbToRgbString(hslToRgb(hueDeg, 0.06, 0.32));
614
-
615
- return {
616
- pageBackground: surface,
617
- headings: {
618
- h1: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h1.fontFamily, fontSize: 22, fontWeight: 700, color: ink, lineHeight: 1.35, marginBottom: 0.8 },
619
- h2: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily, fontSize: 18, fontWeight: 700, color: ink, lineHeight: 1.35, marginBottom: 0.7 },
620
- h3: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h3.fontFamily, fontSize: 16, fontWeight: 600, color: muted, lineHeight: 1.4, marginBottom: 0.6 },
621
- h4: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h4.fontFamily, fontSize: 14, fontWeight: 600, color: muted, lineHeight: 1.4, marginBottom: 0.5 },
622
- h5: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h5.fontFamily, fontSize: 13, fontWeight: 600, color: dim, lineHeight: 1.45, marginBottom: 0.4 },
623
- h6: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h6.fontFamily, fontSize: 12, fontWeight: 600, color: dim, lineHeight: 1.5, marginBottom: 0.3 },
624
- },
625
- body: {
626
- fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
627
- fontSize: 16,
628
- fontWeight: 400,
629
- color: ink,
630
- lineHeight: 1.75,
631
- letterSpacing: 0.02,
632
- },
633
- blockquote: {
634
- fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
635
- fontSize: 14,
636
- fontWeight: 400,
637
- color: muted,
638
- lineHeight: 1.65,
639
- borderLeftColor: dim,
640
- bgColor: panel,
641
- },
642
- codeBlock: {
643
- fontFamily: '"Courier New", Consolas, monospace',
644
- fontSize: 13,
645
- fontWeight: 400,
646
- color: ink,
647
- lineHeight: 1.5,
648
- bgColor: panelAlt,
649
- },
650
- inlineCode: { fontSize: 13, color: accent, bgColor: lighten(panelAlt, 0.4) },
651
- table: {
652
- headerFontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily,
653
- headerFontSize: 13,
654
- headerFontWeight: 700,
655
- headerColor: surface,
656
- headerBgColor: headerBg,
657
- headerLineHeight: 1.4,
658
- cellFontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
659
- cellFontSize: 12,
660
- cellColor: muted,
661
- cellBgColor: surface,
662
- cellLineHeight: 1.5,
663
- cellPadding: "8px 12px",
664
- borderColor: rgbToRgbString(hslToRgb(hueDeg, 0.04, 0.85)),
665
- borderWidth: "1px",
666
- },
667
- accentColor: accent,
668
- mutedTextColor: muted,
669
- selectionBg: `rgba(${hexToRgb(accent).join(",")}, 0.12)`,
670
- };
671
- }
672
-
673
- function rgbToRgbString(rgb: [number, number, number]): string {
674
- return rgbToHex(rgb[0], rgb[1], rgb[2]);
675
- }
676
-
677
- // ═══════════════════════════════════════════════════════════
678
- // 样式验证工具
679
- // ═══════════════════════════════════════════════════════════
680
-
681
- export interface StyleValidationIssue {
682
- level: "error" | "warning" | "info";
683
- element: string;
684
- message: string;
685
- actualValue?: string;
686
- expectedRange?: string;
687
- }
688
-
689
- /**
690
- * 验证文档样式是否满足 WCAG 对比度要求和打印友好性
691
- */
692
- export function validateDocumentStyle(style: DocumentStyleParadigm): StyleValidationIssue[] {
693
- const issues: StyleValidationIssue[] = [];
694
- const bg = style.pageBackground;
695
-
696
- const checkContrast = (
697
- fg: string,
698
- label: string,
699
- minRatio: number,
700
- requiredLevel: string
701
- ) => {
702
- const ratio = contrastRatio(fg, bg);
703
- if (ratio < minRatio) {
704
- issues.push({
705
- level: "error",
706
- element: label,
707
- message: `${label} 对比度 ${ratio.toFixed(1)}:1 不满足 ${requiredLevel} 要求 (≥${minRatio}:1)`,
708
- actualValue: `${ratio.toFixed(1)}:1`,
709
- expectedRange: `≥${minRatio}:1`,
710
- });
711
- }
712
- };
713
-
714
- checkContrast(style.body.color, "正文", 7.0, "WCAG AAA");
715
- checkContrast(style.headings.h1.color, "H1标题", 7.0, "WCAG AAA");
716
- checkContrast(style.headings.h2.color, "H2标题", 7.0, "WCAG AAA");
717
- checkContrast(style.mutedTextColor, "弱化文字", 4.5, "WCAG AA");
718
-
719
- const checkSaturation = (color: string, label: string, maxSat: number) => {
720
- const sat = hslSaturation(color);
721
- if (sat > maxSat) {
722
- issues.push({
723
- level: "warning",
724
- element: label,
725
- message: `${label} 饱和度 ${(sat * 100).toFixed(0)}% 超过打印建议值 (${(maxSat * 100).toFixed(0)}%)`,
726
- actualValue: `${(sat * 100).toFixed(0)}%`,
727
- expectedRange: `≤${(maxSat * 100).toFixed(0)}%`,
728
- });
729
- }
730
- };
731
-
732
- checkSaturation(style.body.color, "正文颜色", 0.08);
733
- checkSaturation(style.headings.h1.color, "H1颜色", 0.08);
734
- checkSaturation(style.table.headerBgColor, "表头背景", 0.20);
735
-
736
- if (style.codeBlock.bgColor !== "#1f2937" && style.codeBlock.bgColor !== "#000000") {
737
- const codeBgLum = relativeLuminance(style.codeBlock.bgColor);
738
- const surfLum = relativeLuminance(bg);
739
- const diff = Math.abs(codeBgLum - surfLum);
740
- if (diff < 0.06) {
741
- issues.push({
742
- level: "warning",
743
- element: "代码块背景",
744
- message: "代码块背景与页面底色区分度过低",
745
- actualValue: `ΔL=${diff.toFixed(3)}`,
746
- expectedRange: "ΔL ≥ 0.06",
747
- });
748
- }
749
- }
750
-
751
- return issues;
752
- }
753
-
754
- /**
755
- * 强制将样式规范化为打印友好格式
756
- * 降低饱和度、确保对比度达标
757
- */
758
- export function normalizeForPrinting(
759
- style: DocumentStyleParadigm,
760
- forceGrayscale: boolean = false
761
- ): DocumentStyleParadigm {
762
- const normalized = JSON.parse(JSON.stringify(style)) as DocumentStyleParadigm;
763
-
764
- const desaturateColor = (hex: string, targetSat: number = 0.05): string => {
765
- if (forceGrayscale) {
766
- const [r, g, b] = hexToRgb(hex);
767
- const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
768
- return rgbToHex(gray, gray, gray);
769
- }
770
- return hex;
771
- };
772
-
773
- normalized.body.color = desaturateColor(normalized.body.color);
774
- normalized.headings.h1.color = desaturateColor(normalized.headings.h1.color);
775
- normalized.headings.h2.color = desaturateColor(normalized.headings.h2.color);
776
- normalized.headings.h3.color = desaturateColor(normalized.headings.h3.color);
777
- normalized.mutedTextColor = desaturateColor(normalized.mutedTextColor);
778
-
779
- return normalized;
780
- }
781
-
782
- // ═══════════════════════════════════════════════════════════
783
- // 预设模板注册表
784
- // ═══════════════════════════════════════════════════════════
785
-
786
- export const DOCUMENT_STYLE_PRESETS: Record<string, DocumentStyleParadigm> = {
787
- "academic-paper": ACADEMIC_PAPER_DEFAULTS,
788
- "business-report": BUSINESS_REPORT_DEFAULTS,
789
- "technical-doc": TECHNICAL_DOC_DEFAULTS,
790
- "print-grayscale": generatePrintFriendlyGrayscale(),
791
- "print-morandi-blue": generateMorandiPrintPalette(210),
792
- "print-morandi-green": generateMorandiPrintPalette(140),
793
- "print-morandi-warm": generateMorandiPrintPalette(30),
794
- };
795
-
796
- /**
797
- * 根据文档类型获取推荐预设
798
- */
799
- export function getRecommendedPreset(docType?: string): DocumentStyleParadigm {
800
- const type = (docType || "").toLowerCase();
801
- if (type.includes("学术") || type.includes("论文") || type.includes("paper")) {
802
- return ACADEMIC_PAPER_DEFAULTS;
803
- }
804
- if (type.includes("商务") || type.includes("报告") || type.includes("report")) {
805
- return BUSINESS_REPORT_DEFAULTS;
806
- }
807
- if (type.includes("技术") || type.includes("api") || type.includes("tech")) {
808
- return TECHNICAL_DOC_DEFAULTS;
809
- }
810
- return ACADEMIC_PAPER_DEFAULTS;
811
- }
1
+ /**
2
+ * DOCX 文档样式规范体系 — v1.0
3
+ *
4
+ * 核心功能:
5
+ * 1. 定义完整的文档元素样式层级(标题 H1-H6、正文、表格等)
6
+ * 2. 提供 WCAG 2.1 AAA 级对比度合规的标准参考值
7
+ * 3. 实现打印友好型灰度/低饱和度配色方案
8
+ * 4. 提供样式提取 fallback 与规范化工具
9
+ *
10
+ * 设计原则:
11
+ * - 文字色使用灰度轴(HSL S ≤ 0.05)或极低饱和度(S ≤ 0.15)
12
+ * - 背景色保持近白/近黑中性,饱和度 ≤ 0.03
13
+ * - 所有前景/背景对比度满足 WCAG AA (4.5:1) 或 AAA (7:1)
14
+ * - 行间距遵循中文排版规范(正文 1.5-1.9,标题 1.25-1.4)
15
+ */
16
+
17
+ import { hexToRgb, rgbToHex, lighten, darken } from "./color-utils.js";
18
+ import { relativeLuminance, contrastRatio, hslSaturation, hslLightness } from "./contrast.js";
19
+
20
+ // ═══════════════════════════════════════════════════════════
21
+ // 类型定义
22
+ // ═══════════════════════════════════════════════════════════
23
+
24
+ /** 单个字体样式的完整定义 */
25
+ export interface FontStyleDefinition {
26
+ /** 字体家族(CSS font-family 值) */
27
+ fontFamily: string;
28
+ /** 字号(px) */
29
+ fontSize: number;
30
+ /** 字重(100-900) */
31
+ fontWeight: number;
32
+ /** 文字颜色(hex) */
33
+ color: string;
34
+ /** 行高倍率 */
35
+ lineHeight: number;
36
+ /** 字间距(em,可选) */
37
+ letterSpacing?: number;
38
+ /** 段后间距(em,可选) */
39
+ marginBottom?: number;
40
+ }
41
+
42
+ /** 表格单元格样式定义 */
43
+ export interface TableCellStyle {
44
+ /** 表头字体家族 */
45
+ headerFontFamily: string;
46
+ /** 表头字号(px) */
47
+ headerFontSize: number;
48
+ /** 表头字重 */
49
+ headerFontWeight: number;
50
+ /** 表头文字颜色 */
51
+ headerColor: string;
52
+ /** 表头背景颜色 */
53
+ headerBgColor: string;
54
+ /** 表头行高 */
55
+ headerLineHeight: number;
56
+
57
+ /** 单元格字体家族 */
58
+ cellFontFamily: string;
59
+ /** 单元格字号(px) */
60
+ cellFontSize: number;
61
+ /** 单元格文字颜色 */
62
+ cellColor: string;
63
+ /** 单元格背景颜色 */
64
+ cellBgColor: string;
65
+ /** 单元格行高 */
66
+ cellLineHeight: number;
67
+ /** 单元格内边距 */
68
+ cellPadding: string;
69
+ /** 边框颜色 */
70
+ borderColor: string;
71
+ /** 边框宽度 */
72
+ borderWidth: string;
73
+ }
74
+
75
+ /** 完整的文档样式规范 */
76
+ export interface DocumentStyleParadigm {
77
+ /** 文档背景颜色 */
78
+ pageBackground: string;
79
+ /** 各级标题样式映射 */
80
+ headings: Record<"h1" | "h2" | "h3" | "h4" | "h5" | "h6", FontStyleDefinition>;
81
+ /** 正文样式 */
82
+ body: FontStyleDefinition;
83
+ /** 引用块样式 */
84
+ blockquote: FontStyleDefinition & { borderLeftColor: string; bgColor: string };
85
+ /** 代码块样式 */
86
+ codeBlock: FontStyleDefinition & { bgColor: string };
87
+ /** 内联代码样式 */
88
+ inlineCode: { fontSize: number; color: string; bgColor: string };
89
+ /** 表格样式 */
90
+ table: TableCellStyle;
91
+ /** 链接/强调色 */
92
+ accentColor: string;
93
+ /** 弱化文字颜色(脚注、辅助信息) */
94
+ mutedTextColor: string;
95
+ /** 选区高亮色 */
96
+ selectionBg: string;
97
+ }
98
+
99
+ /** 打印优化配置 */
100
+ export interface PrintOptimization {
101
+ /** 是否启用纯灰度模式(强制所有彩色转灰度) */
102
+ forceGrayscale: boolean;
103
+ /** 最大文字饱和度阈值(0-1) */
104
+ maxTextSaturation: number;
105
+ /** 最小对比度要求(WCAG 级别) */
106
+ minContrastRatio: "AA" | "AAA";
107
+ /** 背景色亮度调整(-1 到 1,负值变亮) */
108
+ bgBrightnessOffset: number;
109
+ }
110
+
111
+ // ═══════════════════════════════════════════════════════════
112
+ // 常量:标准参考值(Fallback Defaults)
113
+ // ═══════════════════════════════════════════════════════════
114
+
115
+ /**
116
+ * 学术论文标准参考值
117
+ * 基于 GB/T 7713-1987 中文学术论文编排规则 + WCAG AAA
118
+ */
119
+ export const ACADEMIC_PAPER_DEFAULTS: DocumentStyleParadigm = {
120
+ pageBackground: "#ffffff",
121
+
122
+ headings: {
123
+ h1: {
124
+ fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
125
+ fontSize: 22,
126
+ fontWeight: 700,
127
+ color: "#1a1a1a",
128
+ lineHeight: 1.35,
129
+ marginBottom: 0.8,
130
+ },
131
+ h2: {
132
+ fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
133
+ fontSize: 18,
134
+ fontWeight: 700,
135
+ color: "#1a1a1a",
136
+ lineHeight: 1.35,
137
+ marginBottom: 0.7,
138
+ },
139
+ h3: {
140
+ fontFamily: '"SimHei", "Heiti SC", "Source Han Sans SC", sans-serif',
141
+ fontSize: 16,
142
+ fontWeight: 600,
143
+ color: "#2a2a2a",
144
+ lineHeight: 1.4,
145
+ marginBottom: 0.6,
146
+ },
147
+ h4: {
148
+ fontFamily: '"SimSun", "Songti SC", serif',
149
+ fontSize: 14,
150
+ fontWeight: 600,
151
+ color: "#333333",
152
+ lineHeight: 1.4,
153
+ marginBottom: 0.5,
154
+ },
155
+ h5: {
156
+ fontFamily: '"SimSun", "Songti SC", serif',
157
+ fontSize: 13,
158
+ fontWeight: 600,
159
+ color: "#444444",
160
+ lineHeight: 1.45,
161
+ marginBottom: 0.4,
162
+ },
163
+ h6: {
164
+ fontFamily: '"SimSun", "Songti SC", serif',
165
+ fontSize: 12,
166
+ fontWeight: 600,
167
+ color: "#555555",
168
+ lineHeight: 1.5,
169
+ marginBottom: 0.3,
170
+ },
171
+ },
172
+
173
+ body: {
174
+ fontFamily: '"SimSun", "Songti SC", "Noto Serif SC", Georgia, serif',
175
+ fontSize: 16,
176
+ fontWeight: 400,
177
+ color: "#222222",
178
+ lineHeight: 1.75,
179
+ letterSpacing: 0.02,
180
+ },
181
+
182
+ blockquote: {
183
+ fontFamily: '"SimSun", "Songti SC", serif',
184
+ fontSize: 14,
185
+ fontWeight: 400,
186
+ color: "#555555",
187
+ lineHeight: 1.65,
188
+ borderLeftColor: "#888888",
189
+ bgColor: "#fafafa",
190
+ },
191
+
192
+ codeBlock: {
193
+ fontFamily: '"Courier New", Consolas, monospace',
194
+ fontSize: 13,
195
+ fontWeight: 400,
196
+ color: "#333333",
197
+ lineHeight: 1.5,
198
+ bgColor: "#f5f5f5",
199
+ },
200
+
201
+ inlineCode: {
202
+ fontSize: 13,
203
+ color: "#c7254e",
204
+ bgColor: "#f9f2f4",
205
+ },
206
+
207
+ table: {
208
+ headerFontFamily: '"SimHei", "Heiti SC", sans-serif',
209
+ headerFontSize: 13,
210
+ headerFontWeight: 700,
211
+ headerColor: "#ffffff",
212
+ headerBgColor: "#4a4a4a",
213
+ headerLineHeight: 1.4,
214
+
215
+ cellFontFamily: '"SimSun", "Songti SC", serif',
216
+ cellFontSize: 12,
217
+ cellColor: "#333333",
218
+ cellBgColor: "#ffffff",
219
+ cellLineHeight: 1.5,
220
+ cellPadding: "8px 12px",
221
+ borderColor: "#cccccc",
222
+ borderWidth: "1px",
223
+ },
224
+
225
+ accentColor: "#2b579a",
226
+ mutedTextColor: "#666666",
227
+ selectionBg: "rgba(43, 87, 154, 0.15)",
228
+ };
229
+
230
+ /**
231
+ * 商务报告标准参考值
232
+ * 现代、简洁、打印友好
233
+ */
234
+ export const BUSINESS_REPORT_DEFAULTS: DocumentStyleParadigm = {
235
+ pageBackground: "#ffffff",
236
+
237
+ headings: {
238
+ h1: {
239
+ fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
240
+ fontSize: 24,
241
+ fontWeight: 700,
242
+ color: "#1f2937",
243
+ lineHeight: 1.3,
244
+ marginBottom: 1.0,
245
+ },
246
+ h2: {
247
+ fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
248
+ fontSize: 20,
249
+ fontWeight: 600,
250
+ color: "#374151",
251
+ lineHeight: 1.35,
252
+ marginBottom: 0.8,
253
+ },
254
+ h3: {
255
+ fontFamily: '"Inter", "SF Pro Display", -apple-system, sans-serif',
256
+ fontSize: 17,
257
+ fontWeight: 600,
258
+ color: "#4b5563",
259
+ lineHeight: 1.38,
260
+ marginBottom: 0.6,
261
+ },
262
+ h4: {
263
+ fontFamily: '"Inter", -apple-system, sans-serif',
264
+ fontSize: 15,
265
+ fontWeight: 600,
266
+ color: "#6b7280",
267
+ lineHeight: 1.4,
268
+ marginBottom: 0.5,
269
+ },
270
+ h5: {
271
+ fontFamily: '"Inter", -apple-system, sans-serif',
272
+ fontSize: 14,
273
+ fontWeight: 500,
274
+ color: "#6b7280",
275
+ lineHeight: 1.45,
276
+ marginBottom: 0.4,
277
+ },
278
+ h6: {
279
+ fontFamily: '"Inter", -apple-system, sans-serif',
280
+ fontSize: 13,
281
+ fontWeight: 500,
282
+ color: "#9ca3af",
283
+ lineHeight: 1.5,
284
+ marginBottom: 0.3,
285
+ },
286
+ },
287
+
288
+ body: {
289
+ fontFamily: '"Inter", "SF Pro Text", -apple-system, "Noto Sans SC", sans-serif',
290
+ fontSize: 15,
291
+ fontWeight: 400,
292
+ color: "#374151",
293
+ lineHeight: 1.7,
294
+ letterSpacing: 0.01,
295
+ },
296
+
297
+ blockquote: {
298
+ fontFamily: '"Inter", sans-serif',
299
+ fontSize: 14,
300
+ fontWeight: 400,
301
+ color: "#6b7280",
302
+ lineHeight: 1.6,
303
+ borderLeftColor: "#9ca3af",
304
+ bgColor: "#f9fafb",
305
+ },
306
+
307
+ codeBlock: {
308
+ fontFamily: '"JetBrains Mono", "Fira Code", monospace',
309
+ fontSize: 12.5,
310
+ fontWeight: 400,
311
+ color: "#374151",
312
+ lineHeight: 1.55,
313
+ bgColor: "#f3f4f6",
314
+ },
315
+
316
+ inlineCode: {
317
+ fontSize: 12.5,
318
+ color: "#dc2626",
319
+ bgColor: "#fef2f2",
320
+ },
321
+
322
+ table: {
323
+ headerFontFamily: '"Inter", -apple-system, sans-serif',
324
+ headerFontSize: 12.5,
325
+ headerFontWeight: 600,
326
+ headerColor: "#ffffff",
327
+ headerBgColor: "#4b5563",
328
+ headerLineHeight: 1.4,
329
+
330
+ cellFontFamily: '"Inter", sans-serif',
331
+ cellFontSize: 12,
332
+ cellColor: "#374151",
333
+ cellBgColor: "#ffffff",
334
+ cellLineHeight: 1.5,
335
+ cellPadding: "10px 14px",
336
+ borderColor: "#e5e7eb",
337
+ borderWidth: "1px",
338
+ },
339
+
340
+ accentColor: "#2563eb",
341
+ mutedTextColor: "#9ca3af",
342
+ selectionBg: "rgba(37, 99, 235, 0.12)",
343
+ };
344
+
345
+ /**
346
+ * 技术文档标准参考值
347
+ * 适合 API 文档、技术手册
348
+ */
349
+ export const TECHNICAL_DOC_DEFAULTS: DocumentStyleParadigm = {
350
+ pageBackground: "#fefefe",
351
+
352
+ headings: {
353
+ h1: {
354
+ fontFamily: '"Inter", "SF Pro Display", system-ui, sans-serif',
355
+ fontSize: 28,
356
+ fontWeight: 800,
357
+ color: "#111827",
358
+ lineHeight: 1.25,
359
+ marginBottom: 1.2,
360
+ },
361
+ h2: {
362
+ fontFamily: '"Inter", system-ui, sans-serif',
363
+ fontSize: 22,
364
+ fontWeight: 700,
365
+ color: "#1f2937",
366
+ lineHeight: 1.3,
367
+ marginBottom: 0.9,
368
+ },
369
+ h3: {
370
+ fontFamily: '"Inter", system-ui, sans-serif',
371
+ fontSize: 18,
372
+ fontWeight: 600,
373
+ color: "#374151",
374
+ lineHeight: 1.35,
375
+ marginBottom: 0.7,
376
+ },
377
+ h4: {
378
+ fontFamily: '"Inter", system-ui, sans-serif',
379
+ fontSize: 16,
380
+ fontWeight: 600,
381
+ color: "#4b5563",
382
+ lineHeight: 1.38,
383
+ marginBottom: 0.5,
384
+ },
385
+ h5: {
386
+ fontFamily: '"Inter", system-ui, sans-serif',
387
+ fontSize: 14,
388
+ fontWeight: 500,
389
+ color: "#6b7280",
390
+ lineHeight: 1.42,
391
+ marginBottom: 0.4,
392
+ },
393
+ h6: {
394
+ fontFamily: '"JetBrains Mono", monospace',
395
+ fontSize: 13,
396
+ fontWeight: 500,
397
+ color: "#9ca3af",
398
+ lineHeight: 1.5,
399
+ marginBottom: 0.3,
400
+ },
401
+ },
402
+
403
+ body: {
404
+ fontFamily: '"Inter", "SF Pro Text", system-ui, "Noto Sans SC", sans-serif',
405
+ fontSize: 16,
406
+ fontWeight: 400,
407
+ color: "#1f2937",
408
+ lineHeight: 1.75,
409
+ },
410
+
411
+ blockquote: {
412
+ fontFamily: '"Inter", system-ui, sans-serif',
413
+ fontSize: 14.5,
414
+ fontWeight: 400,
415
+ color: "#6b7280",
416
+ lineHeight: 1.65,
417
+ borderLeftColor: "#d1d5db",
418
+ bgColor: "#f9fafb",
419
+ },
420
+
421
+ codeBlock: {
422
+ fontFamily: '"JetBrains Mono", "SF Mono", "Fira Code", monospace',
423
+ fontSize: 13.5,
424
+ fontWeight: 400,
425
+ color: "#e5e7eb",
426
+ lineHeight: 1.6,
427
+ bgColor: "#1f2937",
428
+ },
429
+
430
+ inlineCode: {
431
+ fontSize: 13,
432
+ color: "#dc2626",
433
+ bgColor: "#fef2f2",
434
+ },
435
+
436
+ table: {
437
+ headerFontFamily: '"Inter", system-ui, sans-serif',
438
+ headerFontSize: 13,
439
+ headerFontWeight: 600,
440
+ headerColor: "#f9fafb",
441
+ headerBgColor: "#374151",
442
+ headerLineHeight: 1.4,
443
+
444
+ cellFontFamily: '"Inter", sans-serif',
445
+ cellFontSize: 13,
446
+ cellColor: "#374151",
447
+ cellBgColor: "#ffffff",
448
+ cellLineHeight: 1.55,
449
+ cellPadding: "10px 14px",
450
+ borderColor: "#e5e7eb",
451
+ borderWidth: "1px",
452
+ },
453
+
454
+ accentColor: "#2563eb",
455
+ mutedTextColor: "#9ca3af",
456
+ selectionBg: "rgba(37, 99, 235, 0.15)",
457
+ };
458
+
459
+ // ═══════════════════════════════════════════════════════════
460
+ // 打印友好型灰度/低饱和度配色生成器
461
+ // ═══════════════════════════════════════════════════════════
462
+
463
+ /**
464
+ * 生成打印优化的灰度色板
465
+ * @param baseBrightness 页面基础亮度(0=纯黑,1=纯白)
466
+ * @param options 打印优化配置
467
+ */
468
+ export function generatePrintFriendlyGrayscale(
469
+ baseBrightness: number = 0.97,
470
+ options?: Partial<PrintOptimization>
471
+ ): DocumentStyleParadigm {
472
+ const opts: PrintOptimization = {
473
+ forceGrayscale: true,
474
+ maxTextSaturation: 0.05,
475
+ minContrastRatio: "AAA",
476
+ bgBrightnessOffset: 0,
477
+ ...options,
478
+ };
479
+
480
+ const surfaceValue = Math.round(baseBrightness * 255);
481
+ const surfaceHex = rgbToHex(surfaceValue, surfaceValue, surfaceValue);
482
+
483
+ const inkValue = Math.max(0, Math.round((1 - baseBrightness) * 255 * 0.92));
484
+ const inkHex = rgbToHex(inkValue, inkValue, inkValue);
485
+
486
+ const mutedValue = Math.round(inkValue + (surfaceValue - inkValue) * 0.55);
487
+ const mutedHex = rgbToHex(mutedValue, mutedValue, mutedValue);
488
+
489
+ const dimValue = Math.round(inkValue + (surfaceValue - inkValue) * 0.75);
490
+ const dimHex = rgbToHex(dimValue, dimValue, dimValue);
491
+
492
+ const panelValue = Math.max(0, Math.round(surfaceValue - 12));
493
+ const panelHex = rgbToHex(panelValue, panelValue, panelValue);
494
+
495
+ const panelAltValue = Math.max(0, Math.round(surfaceValue - 24));
496
+ const panelAltHex = rgbToHex(panelAltValue, panelAltValue, panelAltValue);
497
+
498
+ const accentGray = opts.forceGrayscale
499
+ ? rgbToHex(Math.round(inkValue * 0.4), Math.round(inkValue * 0.4), Math.round(inkValue * 0.4))
500
+ : "#4a5568";
501
+
502
+ return {
503
+ pageBackground: surfaceHex,
504
+
505
+ headings: {
506
+ h1: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h1.fontFamily, fontSize: 22, fontWeight: 700, color: inkHex, lineHeight: 1.35, marginBottom: 0.8 },
507
+ h2: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily, fontSize: 18, fontWeight: 700, color: inkHex, lineHeight: 1.35, marginBottom: 0.7 },
508
+ h3: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h3.fontFamily, fontSize: 16, fontWeight: 600, color: mutedHex, lineHeight: 1.4, marginBottom: 0.6 },
509
+ h4: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h4.fontFamily, fontSize: 14, fontWeight: 600, color: mutedHex, lineHeight: 1.4, marginBottom: 0.5 },
510
+ h5: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h5.fontFamily, fontSize: 13, fontWeight: 600, color: dimHex, lineHeight: 1.45, marginBottom: 0.4 },
511
+ h6: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h6.fontFamily, fontSize: 12, fontWeight: 600, color: dimHex, lineHeight: 1.5, marginBottom: 0.3 },
512
+ },
513
+
514
+ body: {
515
+ fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
516
+ fontSize: 16,
517
+ fontWeight: 400,
518
+ color: rgbToHex(Math.round(inkValue * 0.88), Math.round(inkValue * 0.88), Math.round(inkValue * 0.88)),
519
+ lineHeight: 1.75,
520
+ letterSpacing: 0.02,
521
+ },
522
+
523
+ blockquote: {
524
+ fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
525
+ fontSize: 14,
526
+ fontWeight: 400,
527
+ color: mutedHex,
528
+ lineHeight: 1.65,
529
+ borderLeftColor: dimHex,
530
+ bgColor: panelHex,
531
+ },
532
+
533
+ codeBlock: {
534
+ fontFamily: '"Courier New", Consolas, monospace',
535
+ fontSize: 13,
536
+ fontWeight: 400,
537
+ color: inkHex,
538
+ lineHeight: 1.5,
539
+ bgColor: panelAltHex,
540
+ },
541
+
542
+ inlineCode: {
543
+ fontSize: 13,
544
+ color: accentGray,
545
+ bgColor: lighten(panelAltHex, 0.3),
546
+ },
547
+
548
+ table: {
549
+ headerFontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily,
550
+ headerFontSize: 13,
551
+ headerFontWeight: 700,
552
+ headerColor: surfaceHex,
553
+ headerBgColor: rgbToHex(
554
+ Math.round(inkValue * 0.72),
555
+ Math.round(inkValue * 0.72),
556
+ Math.round(inkValue * 0.72)
557
+ ),
558
+ headerLineHeight: 1.4,
559
+
560
+ cellFontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
561
+ cellFontSize: 12,
562
+ cellColor: rgbToHex(Math.round(inkValue * 0.82), Math.round(inkValue * 0.82), Math.round(inkValue * 0.82)),
563
+ cellBgColor: surfaceHex,
564
+ cellLineHeight: 1.5,
565
+ cellPadding: "8px 12px",
566
+ borderColor: rgbToHex(
567
+ Math.round(surfaceValue - 40),
568
+ Math.round(surfaceValue - 40),
569
+ Math.round(surfaceValue - 40)
570
+ ),
571
+ borderWidth: "1px",
572
+ },
573
+
574
+ accentColor: accentGray,
575
+ mutedTextColor: mutedHex,
576
+ selectionBg: `rgba(${Math.round(inkValue * 0.4)}, ${Math.round(inkValue * 0.4)}, ${Math.round(inkValue * 0.4)}, 0.15)`,
577
+ };
578
+ }
579
+
580
+ /**
581
+ * 生成低饱和度莫兰迪风格色板(适合打印)
582
+ * 保持微弱色相但大幅降低饱和度
583
+ */
584
+ export function generateMorandiPrintPalette(
585
+ hueDeg: number = 210,
586
+ saturation: number = 0.08,
587
+ ): DocumentStyleParadigm {
588
+ const hslToRgb = (h: number, s: number, l: number): [number, number, number] => {
589
+ const c = (1 - Math.abs(2 * l - 1)) * s;
590
+ const x = c * (1 - Math.abs(((h / 60) % 2) - 1));
591
+ const m = l - c / 2;
592
+ let r = 0, g = 0, b = 0;
593
+ if (h < 60) { r = c; g = x; }
594
+ else if (h < 120) { r = x; g = c; }
595
+ else if (h < 180) { g = c; b = x; }
596
+ else if (h < 240) { g = x; b = c; }
597
+ else if (h < 300) { r = x; b = c; }
598
+ else { r = c; b = x; }
599
+ return [
600
+ Math.round((r + m) * 255),
601
+ Math.round((g + m) * 255),
602
+ Math.round((b + m) * 255),
603
+ ];
604
+ };
605
+
606
+ const surface = rgbToHex(...hslToRgb(hueDeg, 0.01, 0.98));
607
+ const ink = rgbToRgbString(hslToRgb(hueDeg, 0.04, 0.12));
608
+ const muted = rgbToRgbString(hslToRgb(hueDeg, 0.03, 0.42));
609
+ const dim = rgbToRgbString(hslToRgb(hueDeg, 0.02, 0.58));
610
+ const panel = rgbToRgbString(hslToRgb(hueDeg, 0.02, 0.95));
611
+ const panelAlt = rgbToRgbString(hslToRgb(hueDeg, 0.03, 0.91));
612
+ const accent = rgbToRgbString(hslToRgb(hueDeg, saturation, 0.38));
613
+ const headerBg = rgbToRgbString(hslToRgb(hueDeg, 0.06, 0.32));
614
+
615
+ return {
616
+ pageBackground: surface,
617
+ headings: {
618
+ h1: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h1.fontFamily, fontSize: 22, fontWeight: 700, color: ink, lineHeight: 1.35, marginBottom: 0.8 },
619
+ h2: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily, fontSize: 18, fontWeight: 700, color: ink, lineHeight: 1.35, marginBottom: 0.7 },
620
+ h3: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h3.fontFamily, fontSize: 16, fontWeight: 600, color: muted, lineHeight: 1.4, marginBottom: 0.6 },
621
+ h4: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h4.fontFamily, fontSize: 14, fontWeight: 600, color: muted, lineHeight: 1.4, marginBottom: 0.5 },
622
+ h5: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h5.fontFamily, fontSize: 13, fontWeight: 600, color: dim, lineHeight: 1.45, marginBottom: 0.4 },
623
+ h6: { fontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h6.fontFamily, fontSize: 12, fontWeight: 600, color: dim, lineHeight: 1.5, marginBottom: 0.3 },
624
+ },
625
+ body: {
626
+ fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
627
+ fontSize: 16,
628
+ fontWeight: 400,
629
+ color: ink,
630
+ lineHeight: 1.75,
631
+ letterSpacing: 0.02,
632
+ },
633
+ blockquote: {
634
+ fontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
635
+ fontSize: 14,
636
+ fontWeight: 400,
637
+ color: muted,
638
+ lineHeight: 1.65,
639
+ borderLeftColor: dim,
640
+ bgColor: panel,
641
+ },
642
+ codeBlock: {
643
+ fontFamily: '"Courier New", Consolas, monospace',
644
+ fontSize: 13,
645
+ fontWeight: 400,
646
+ color: ink,
647
+ lineHeight: 1.5,
648
+ bgColor: panelAlt,
649
+ },
650
+ inlineCode: { fontSize: 13, color: accent, bgColor: lighten(panelAlt, 0.4) },
651
+ table: {
652
+ headerFontFamily: ACADEMIC_PAPER_DEFAULTS.headings.h2.fontFamily,
653
+ headerFontSize: 13,
654
+ headerFontWeight: 700,
655
+ headerColor: surface,
656
+ headerBgColor: headerBg,
657
+ headerLineHeight: 1.4,
658
+ cellFontFamily: ACADEMIC_PAPER_DEFAULTS.body.fontFamily,
659
+ cellFontSize: 12,
660
+ cellColor: muted,
661
+ cellBgColor: surface,
662
+ cellLineHeight: 1.5,
663
+ cellPadding: "8px 12px",
664
+ borderColor: rgbToRgbString(hslToRgb(hueDeg, 0.04, 0.85)),
665
+ borderWidth: "1px",
666
+ },
667
+ accentColor: accent,
668
+ mutedTextColor: muted,
669
+ selectionBg: `rgba(${hexToRgb(accent).join(",")}, 0.12)`,
670
+ };
671
+ }
672
+
673
+ function rgbToRgbString(rgb: [number, number, number]): string {
674
+ return rgbToHex(rgb[0], rgb[1], rgb[2]);
675
+ }
676
+
677
+ // ═══════════════════════════════════════════════════════════
678
+ // 样式验证工具
679
+ // ═══════════════════════════════════════════════════════════
680
+
681
+ export interface StyleValidationIssue {
682
+ level: "error" | "warning" | "info";
683
+ element: string;
684
+ message: string;
685
+ actualValue?: string;
686
+ expectedRange?: string;
687
+ }
688
+
689
+ /**
690
+ * 验证文档样式是否满足 WCAG 对比度要求和打印友好性
691
+ */
692
+ export function validateDocumentStyle(style: DocumentStyleParadigm): StyleValidationIssue[] {
693
+ const issues: StyleValidationIssue[] = [];
694
+ const bg = style.pageBackground;
695
+
696
+ const checkContrast = (
697
+ fg: string,
698
+ label: string,
699
+ minRatio: number,
700
+ requiredLevel: string
701
+ ) => {
702
+ const ratio = contrastRatio(fg, bg);
703
+ if (ratio < minRatio) {
704
+ issues.push({
705
+ level: "error",
706
+ element: label,
707
+ message: `${label} 对比度 ${ratio.toFixed(1)}:1 不满足 ${requiredLevel} 要求 (≥${minRatio}:1)`,
708
+ actualValue: `${ratio.toFixed(1)}:1`,
709
+ expectedRange: `≥${minRatio}:1`,
710
+ });
711
+ }
712
+ };
713
+
714
+ checkContrast(style.body.color, "正文", 7.0, "WCAG AAA");
715
+ checkContrast(style.headings.h1.color, "H1标题", 7.0, "WCAG AAA");
716
+ checkContrast(style.headings.h2.color, "H2标题", 7.0, "WCAG AAA");
717
+ checkContrast(style.mutedTextColor, "弱化文字", 4.5, "WCAG AA");
718
+
719
+ const checkSaturation = (color: string, label: string, maxSat: number) => {
720
+ const sat = hslSaturation(color);
721
+ if (sat > maxSat) {
722
+ issues.push({
723
+ level: "warning",
724
+ element: label,
725
+ message: `${label} 饱和度 ${(sat * 100).toFixed(0)}% 超过打印建议值 (${(maxSat * 100).toFixed(0)}%)`,
726
+ actualValue: `${(sat * 100).toFixed(0)}%`,
727
+ expectedRange: `≤${(maxSat * 100).toFixed(0)}%`,
728
+ });
729
+ }
730
+ };
731
+
732
+ checkSaturation(style.body.color, "正文颜色", 0.08);
733
+ checkSaturation(style.headings.h1.color, "H1颜色", 0.08);
734
+ checkSaturation(style.table.headerBgColor, "表头背景", 0.20);
735
+
736
+ if (style.codeBlock.bgColor !== "#1f2937" && style.codeBlock.bgColor !== "#000000") {
737
+ const codeBgLum = relativeLuminance(style.codeBlock.bgColor);
738
+ const surfLum = relativeLuminance(bg);
739
+ const diff = Math.abs(codeBgLum - surfLum);
740
+ if (diff < 0.06) {
741
+ issues.push({
742
+ level: "warning",
743
+ element: "代码块背景",
744
+ message: "代码块背景与页面底色区分度过低",
745
+ actualValue: `ΔL=${diff.toFixed(3)}`,
746
+ expectedRange: "ΔL ≥ 0.06",
747
+ });
748
+ }
749
+ }
750
+
751
+ return issues;
752
+ }
753
+
754
+ /**
755
+ * 强制将样式规范化为打印友好格式
756
+ * 降低饱和度、确保对比度达标
757
+ */
758
+ export function normalizeForPrinting(
759
+ style: DocumentStyleParadigm,
760
+ forceGrayscale: boolean = false
761
+ ): DocumentStyleParadigm {
762
+ const normalized = JSON.parse(JSON.stringify(style)) as DocumentStyleParadigm;
763
+
764
+ const desaturateColor = (hex: string, targetSat: number = 0.05): string => {
765
+ if (forceGrayscale) {
766
+ const [r, g, b] = hexToRgb(hex);
767
+ const gray = Math.round(0.299 * r + 0.587 * g + 0.114 * b);
768
+ return rgbToHex(gray, gray, gray);
769
+ }
770
+ return hex;
771
+ };
772
+
773
+ normalized.body.color = desaturateColor(normalized.body.color);
774
+ normalized.headings.h1.color = desaturateColor(normalized.headings.h1.color);
775
+ normalized.headings.h2.color = desaturateColor(normalized.headings.h2.color);
776
+ normalized.headings.h3.color = desaturateColor(normalized.headings.h3.color);
777
+ normalized.mutedTextColor = desaturateColor(normalized.mutedTextColor);
778
+
779
+ return normalized;
780
+ }
781
+
782
+ // ═══════════════════════════════════════════════════════════
783
+ // 预设模板注册表
784
+ // ═══════════════════════════════════════════════════════════
785
+
786
+ export const DOCUMENT_STYLE_PRESETS: Record<string, DocumentStyleParadigm> = {
787
+ "academic-paper": ACADEMIC_PAPER_DEFAULTS,
788
+ "business-report": BUSINESS_REPORT_DEFAULTS,
789
+ "technical-doc": TECHNICAL_DOC_DEFAULTS,
790
+ "print-grayscale": generatePrintFriendlyGrayscale(),
791
+ "print-morandi-blue": generateMorandiPrintPalette(210),
792
+ "print-morandi-green": generateMorandiPrintPalette(140),
793
+ "print-morandi-warm": generateMorandiPrintPalette(30),
794
+ };
795
+
796
+ /**
797
+ * 根据文档类型获取推荐预设
798
+ */
799
+ export function getRecommendedPreset(docType?: string): DocumentStyleParadigm {
800
+ const type = (docType || "").toLowerCase();
801
+ if (type.includes("学术") || type.includes("论文") || type.includes("paper")) {
802
+ return ACADEMIC_PAPER_DEFAULTS;
803
+ }
804
+ if (type.includes("商务") || type.includes("报告") || type.includes("report")) {
805
+ return BUSINESS_REPORT_DEFAULTS;
806
+ }
807
+ if (type.includes("技术") || type.includes("api") || type.includes("tech")) {
808
+ return TECHNICAL_DOC_DEFAULTS;
809
+ }
810
+ return ACADEMIC_PAPER_DEFAULTS;
811
+ }