@bytechain.cn/colamd-themes 0.3.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 (108) hide show
  1. package/.claude/skills/colamd-themes-preview.skill.md +333 -0
  2. package/.claude/skills/colamd-themes.skill.md +155 -0
  3. package/.hermes/skills/tools/colamd-themes/SKILL.md +159 -0
  4. package/.openclaw/skills/colamd-themes/SKILL.md +166 -0
  5. package/.opencode/skills/colamd-themes/SKILL.md +162 -0
  6. package/.trae/rules/colamd-themes.md +150 -0
  7. package/CHANGELOG.md +102 -0
  8. package/README.md +373 -0
  9. package/README_CN.md +373 -0
  10. package/RELEASENOTE.md +177 -0
  11. package/dist/cli.d.ts +2 -0
  12. package/dist/cli.js +208 -0
  13. package/dist/cli.js.map +1 -0
  14. package/dist/color-systems.d.ts +17 -0
  15. package/dist/color-systems.js +251 -0
  16. package/dist/color-systems.js.map +1 -0
  17. package/dist/color-utils.d.ts +9 -0
  18. package/dist/color-utils.js +112 -0
  19. package/dist/color-utils.js.map +1 -0
  20. package/dist/contrast.d.ts +15 -0
  21. package/dist/contrast.js +63 -0
  22. package/dist/contrast.js.map +1 -0
  23. package/dist/docx-style-paradigm.d.ts +153 -0
  24. package/dist/docx-style-paradigm.js +640 -0
  25. package/dist/docx-style-paradigm.js.map +1 -0
  26. package/dist/export-cli.d.ts +10 -0
  27. package/dist/export-cli.js +266 -0
  28. package/dist/export-cli.js.map +1 -0
  29. package/dist/extractors/base.d.ts +6 -0
  30. package/dist/extractors/base.js +3 -0
  31. package/dist/extractors/base.js.map +1 -0
  32. package/dist/extractors/docx-extractor.d.ts +52 -0
  33. package/dist/extractors/docx-extractor.js +370 -0
  34. package/dist/extractors/docx-extractor.js.map +1 -0
  35. package/dist/extractors/pdf-extractor.d.ts +66 -0
  36. package/dist/extractors/pdf-extractor.js +430 -0
  37. package/dist/extractors/pdf-extractor.js.map +1 -0
  38. package/dist/extractors/url-extractor.d.ts +104 -0
  39. package/dist/extractors/url-extractor.js +761 -0
  40. package/dist/extractors/url-extractor.js.map +1 -0
  41. package/dist/generator.d.ts +4 -0
  42. package/dist/generator.js +71 -0
  43. package/dist/generator.js.map +1 -0
  44. package/dist/index.d.ts +10 -0
  45. package/dist/index.js +9 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/mermaid-presets.d.ts +14 -0
  48. package/dist/mermaid-presets.js +122 -0
  49. package/dist/mermaid-presets.js.map +1 -0
  50. package/dist/models.d.ts +106 -0
  51. package/dist/models.js +92 -0
  52. package/dist/models.js.map +1 -0
  53. package/dist/renderer.d.ts +70 -0
  54. package/dist/renderer.js +204 -0
  55. package/dist/renderer.js.map +1 -0
  56. package/dist/templates/template.css +498 -0
  57. package/dist/templates/theme-paradigm.md +658 -0
  58. package/dist/templates/theme-template.hbs +370 -0
  59. package/dist/theme-store.d.ts +37 -0
  60. package/dist/theme-store.js +90 -0
  61. package/dist/theme-store.js.map +1 -0
  62. package/dist/validators.d.ts +26 -0
  63. package/dist/validators.js +144 -0
  64. package/dist/validators.js.map +1 -0
  65. package/package.json +36 -0
  66. package/skills/build-skills.sh +166 -0
  67. package/skills/colamd-themes/SKILL.md +148 -0
  68. package/src/cli.ts +200 -0
  69. package/src/color-systems.ts +289 -0
  70. package/src/color-utils.ts +120 -0
  71. package/src/contrast.ts +66 -0
  72. package/src/docx-style-paradigm.ts +811 -0
  73. package/src/export-cli.ts +301 -0
  74. package/src/extractors/base.ts +8 -0
  75. package/src/extractors/docx-extractor.ts +417 -0
  76. package/src/extractors/pdf-extractor.ts +527 -0
  77. package/src/extractors/url-extractor.ts +927 -0
  78. package/src/generator.ts +88 -0
  79. package/src/index.ts +29 -0
  80. package/src/mermaid-presets.ts +142 -0
  81. package/src/models.ts +212 -0
  82. package/src/renderer.ts +277 -0
  83. package/src/templates/template.css +498 -0
  84. package/src/templates/theme-paradigm.md +658 -0
  85. package/src/templates/theme-template.hbs +370 -0
  86. package/src/theme-store.ts +112 -0
  87. package/src/types/pdf-parse.d.ts +12 -0
  88. package/src/validators.ts +176 -0
  89. package/themes/.gitkeep +0 -0
  90. package/themes/academic-paper-pt.css +1805 -0
  91. package/themes/academic-paper.css +1099 -0
  92. package/themes/academic-style.css +2430 -0
  93. package/themes/colly.css +370 -0
  94. package/themes/elegant.css +671 -0
  95. package/themes/forest-ink.css +664 -0
  96. package/themes/guizang.css +732 -0
  97. package/themes/meeting-minutes.css +370 -0
  98. package/themes/pixso-design.css +1261 -0
  99. package/themes/salvator-blog.css +370 -0
  100. package/themes/swiss-design copy.css +746 -0
  101. package/themes/swiss-design.css +746 -0
  102. package/themes/template.css +498 -0
  103. package/themes/trae-blue.css +737 -0
  104. package/themes-preview/colly-preview.html +623 -0
  105. package/themes-preview/demo-content.md +187 -0
  106. package/themes-preview/meeting-minutes-preview.html +625 -0
  107. package/themes-preview/salvator-blog-preview.html +623 -0
  108. package/tsconfig.json +18 -0
@@ -0,0 +1,527 @@
1
+ /**
2
+ * PDF 文档样式提取器 — v2.0
3
+ *
4
+ * 增强功能:
5
+ * 1. 基于文本结构启发式分析提取各级标题样式
6
+ * 2. 检测正文字体、字号、行间距特征
7
+ * 3. 识别表格、代码块等特殊元素
8
+ * 4. 集成 DocxStyleParadigm 标准参考值填充缺失字段
9
+ * 5. 自动验证 WCAG 对比度合规性
10
+ *
11
+ * 技术说明:
12
+ * pdf-parse 默认不提供字体元数据,因此采用多层启发式策略:
13
+ * - 层级1:文本结构分析(短行/大写/编号 = 标题候选)
14
+ * - 层级2:格式特征检测(等宽文本 = 代码块)
15
+ * - 层级3:DocxStyleParadigm 标准参考值 fallback
16
+ */
17
+
18
+ import { readFileSync } from "node:fs";
19
+ import { basename } from "node:path";
20
+ import type { Extractor } from "./base.js";
21
+ import {
22
+ makeThemeStyle,
23
+ type ThemeStyle,
24
+ type ColorPalette,
25
+ } from "../models.js";
26
+ import { normalizeThemeStyle } from "../color-utils.js";
27
+ import {
28
+ ACADEMIC_PAPER_DEFAULTS,
29
+ BUSINESS_REPORT_DEFAULTS,
30
+ TECHNICAL_DOC_DEFAULTS,
31
+ getRecommendedPreset,
32
+ validateDocumentStyle,
33
+ type DocumentStyleParadigm,
34
+ } from "../docx-style-paradigm.js";
35
+
36
+ /** PDF 解析结果数据类型 */
37
+ type PDFData = {
38
+ text: string;
39
+ numpages: number;
40
+ info: Record<string, unknown>;
41
+ metadata: Record<string, unknown>;
42
+ };
43
+
44
+ /** 从文本行中推断的字体信息 */
45
+ interface InferredFontInfo {
46
+ fontName: string;
47
+ fontSize: number;
48
+ isBold: boolean;
49
+ isHeading: boolean;
50
+ headingLevel: number | null;
51
+ }
52
+
53
+ /** 文本行分析结果 */
54
+ interface LineAnalysis {
55
+ text: string;
56
+ length: number;
57
+ isAllUppercase: boolean;
58
+ isShortLine: boolean;
59
+ hasNumbering: boolean;
60
+ hasBullet: boolean;
61
+ looksLikeHeading: boolean;
62
+ looksLikeCode: boolean;
63
+ indentLevel: number;
64
+ }
65
+
66
+ export class PdfExtractor implements Extractor {
67
+ canHandle(source: string): boolean {
68
+ return /\.pdf$/i.test(source);
69
+ }
70
+
71
+ async extract(source: string): Promise<ThemeStyle> {
72
+ const name = basename(source).replace(/\.pdf$/i, "");
73
+ const theme = makeThemeStyle(name, "pdf", source);
74
+
75
+ try {
76
+ const pdfParse = (await import("pdf-parse")).default;
77
+ const buffer = readFileSync(source);
78
+ const data: PDFData = await pdfParse(buffer);
79
+
80
+ if (data.text) {
81
+ this.analyzeTextStructure(theme, data.text);
82
+ }
83
+
84
+ if (data.metadata) {
85
+ this.populateFromMetadata(theme, data.metadata);
86
+ }
87
+
88
+ if (data.info) {
89
+ this.detectDocumentType(theme, data.text, data.numpages);
90
+ }
91
+ } catch (err) {
92
+ if ((err as NodeJS.ErrnoException).code === "ERR_MODULE_NOT_FOUND") {
93
+ throw new Error("pdf-parse 未安装,请运行: npm install pdf-parse");
94
+ }
95
+ throw err;
96
+ }
97
+
98
+ this.applyParadigmDefaults(theme);
99
+ normalizeThemeStyle(theme);
100
+ return theme;
101
+ }
102
+
103
+ /**
104
+ * 分析 PDF 文本结构,推断文档元素样式
105
+ */
106
+ private analyzeTextStructure(theme: ThemeStyle, text: string): void {
107
+ const lines = text.split("\n").filter((l) => l.trim().length > 0);
108
+ const analyzedLines = lines.map((line) => this.analyzeLine(line));
109
+
110
+ this.detectHeadings(theme, analyzedLines);
111
+ this.detectBodyText(theme, analyzedLines);
112
+ this.detectCodeBlocks(theme, analyzedLines);
113
+ this.detectTables(theme, analyzedLines);
114
+ this.inferColorPalette(theme, analyzedLines);
115
+ }
116
+
117
+ /**
118
+ * 单行文本特征分析
119
+ */
120
+ private analyzeLine(line: string): LineAnalysis {
121
+ const trimmed = line.trim();
122
+ return {
123
+ text: trimmed,
124
+ length: trimmed.length,
125
+ isAllUppercase:
126
+ trimmed.length > 3 &&
127
+ trimmed.length < 80 &&
128
+ /^[A-Z0-9\s\-:.,!?()]+$/.test(trimmed) &&
129
+ /[A-Z]/.test(trimmed) &&
130
+ trimmed.split("").filter((c) => /[a-z]/.test(c)).length === 0,
131
+ isShortLine: trimmed.length < 60,
132
+ hasNumbering: /^\s*(\d+[\.\)]\s*|[一二三四五六七八九十]+[\.\、]\s*|[IVX]+\.\s*)/.test(
133
+ trimmed
134
+ ),
135
+ hasBullet: /^\s*[\-\•\*\·\◦\‣]\s*/.test(trimmed),
136
+ looksLikeHeading: false,
137
+ looksLikeCode: false,
138
+ indentLevel: line.search(/\S/),
139
+ };
140
+ }
141
+
142
+ /**
143
+ * 基于启发式规则检测标题层级
144
+ */
145
+ private detectHeadings(theme: ThemeStyle, lines: LineAnalysis[]): void {
146
+ const headingCandidates: { level: number; confidence: number; line: LineAnalysis }[] = [];
147
+
148
+ for (const line of lines) {
149
+ let confidence = 0;
150
+
151
+ if (line.isAllUppercase && line.isShortLine) {
152
+ confidence += 4;
153
+ }
154
+ if (line.hasNumbering && line.isShortLine) {
155
+ confidence += 3;
156
+ }
157
+ if (line.indentLevel === 0 && line.isShortLine && line.length > 5) {
158
+ confidence += 2;
159
+ }
160
+ if (/^(摘要|ABSTRACT|目录|TABLE OF CONTENTS|引言|INTRODUCTION|结论|CONCLUSION|参考文献|REFERENCES)$/i.test(line.text)) {
161
+ confidence += 5;
162
+ }
163
+ if (/^第[一二三四五六七八九十]+[章节部分]|^Chapter\s+\d+/i.test(line.text)) {
164
+ confidence += 4;
165
+ }
166
+ if (line.length < 30 && line.length > 3 && /^[^\s]{2,}$/.test(line.text)) {
167
+ confidence += 1;
168
+ }
169
+
170
+ if (confidence >= 4) {
171
+ line.looksLikeHeading = true;
172
+ let level = 2;
173
+ if (confidence >= 6 || /^(摘要|ABSTRACT|标题|TITLE)$/i.test(line.text)) {
174
+ level = 1;
175
+ } else if (confidence >= 5 || line.hasNumbering) {
176
+ level = 2;
177
+ } else if (line.indentLevel > 0) {
178
+ level = Math.min(4, 2 + Math.floor(line.indentLevel / 2));
179
+ }
180
+ headingCandidates.push({ level, confidence, line });
181
+ }
182
+ }
183
+
184
+ if (headingCandidates.length > 0) {
185
+ theme.palette.headingColor = theme.palette.headingColor || ACADEMIC_PAPER_DEFAULTS.headings.h1.color;
186
+ theme.typography.headingWeight = 700;
187
+
188
+ const h1Count = headingCandidates.filter((c) => c.level === 1).length;
189
+ const h2Count = headingCandidates.filter((c) => c.level === 2).length;
190
+
191
+ if (h1Count > 0) {
192
+ theme.seedTypography.fontScaleH1 = ACADEMIC_PAPER_DEFAULTS.headings.h1.fontSize / 16;
193
+ }
194
+ if (h2Count > 0) {
195
+ theme.seedTypography.fontScaleH2 = ACADEMIC_PAPER_DEFAULTS.headings.h2.fontSize / 16;
196
+ }
197
+ if (headingCandidates.some((c) => c.level >= 3)) {
198
+ theme.seedTypography.fontScaleH3 = ACADEMIC_PAPER_DEFAULTS.headings.h3.fontSize / 16;
199
+ }
200
+ }
201
+ }
202
+
203
+ /**
204
+ * 推断正文样式特征
205
+ */
206
+ private detectBodyText(theme: ThemeStyle, lines: LineAnalysis[]): void {
207
+ const bodyLines = lines.filter(
208
+ (l) => !l.looksLikeHeading && !l.looksLikeCode && l.length > 20
209
+ );
210
+
211
+ if (bodyLines.length === 0) return;
212
+
213
+ const avgLength =
214
+ bodyLines.reduce((sum, l) => sum + l.length, 0) / bodyLines.length;
215
+ const avgIndent =
216
+ bodyLines.reduce((sum, l) => sum + l.indentLevel, 0) / bodyLines.length;
217
+
218
+ if (avgLength > 60) {
219
+ theme.typography.baseFontSize = "16px";
220
+ theme.typography.baseLineHeight = 1.75;
221
+ } else if (avgLength > 40) {
222
+ theme.typography.baseFontSize = "15px";
223
+ theme.typography.baseLineHeight = 1.7;
224
+ } else {
225
+ theme.typography.baseFontSize = "14px";
226
+ theme.typography.baseLineHeight = 1.65;
227
+ }
228
+
229
+ if (avgIndent >= 2) {
230
+ theme.typography.bodyFontFamily = ACADEMIC_PAPER_DEFAULTS.body.fontFamily;
231
+ }
232
+
233
+ theme.seedTypography.lineHeightBody = theme.typography.baseLineHeight;
234
+ }
235
+
236
+ /**
237
+ * 检测代码块区域(等宽文本特征)
238
+ */
239
+ private detectCodeBlocks(theme: ThemeStyle, lines: LineAnalysis[]): void {
240
+ const codeIndicators = [
241
+ (l: LineAnalysis) =>
242
+ l.text.includes("function ") ||
243
+ l.text.includes("const ") ||
244
+ l.text.includes("let ") ||
245
+ l.text.includes("var "),
246
+ (l: LineAnalysis) =>
247
+ l.text.includes("{") && l.text.includes("}"),
248
+ (l: LineAnalysis) =>
249
+ /^(\s*(\/\/|#|\/\*|\*\/|\s*import\s+\s*export\s+))/.test(l.text),
250
+ (l: LineAnalysis) =>
251
+ l.text.match(/[;<>=\[\](){}]/g)?.length &&
252
+ l.text.match(/[;<>=\[\](){}]/g)!?.length > 3,
253
+ ];
254
+
255
+ for (const line of lines) {
256
+ const isCode = codeIndicators.some((check) => check(line));
257
+ if (isCode) {
258
+ line.looksLikeCode = true;
259
+ }
260
+ }
261
+
262
+ const codeLineCount = lines.filter((l) => l.looksLikeCode).length;
263
+ if (codeLineCount > 3) {
264
+ theme.palette.codeBlockBg = "#f5f5f5";
265
+ theme.palette.codeBlockText = "#333333";
266
+ theme.palette.codeBg = "#f9f9f9";
267
+ }
268
+ }
269
+
270
+ /**
271
+ * 检测表格结构(多列对齐文本)
272
+ */
273
+ private detectTables(theme: ThemeStyle, lines: LineAnalysis[]): void {
274
+ const tablePatterns = [
275
+ /^\|.+\|.*\|$/,
276
+ /^\s*\|?\s*-{2,}\s*\|/,
277
+ /^\s+(\S+)\s{2,}(\S+)\s{2,}(\S+)/,
278
+ ];
279
+
280
+ let tableLineCount = 0;
281
+ for (const line of lines) {
282
+ if (tablePatterns.some((p) => p.test(line.text))) {
283
+ tableLineCount++;
284
+ }
285
+ }
286
+
287
+ if (tableLineCount >= 3) {
288
+ theme.palette.tableHeaderBg = ACADEMIC_PAPER_DEFAULTS.table.headerBgColor;
289
+ theme.palette.borderColor = ACADEMIC_PAPER_DEFAULTS.table.borderColor;
290
+ }
291
+ }
292
+
293
+ /**
294
+ * 基于文档特征推断配色方案
295
+ */
296
+ private inferColorPalette(theme: ThemeStyle, lines: LineAnalysis[]): void {
297
+ const p = theme.palette;
298
+
299
+ const hasChinese = lines.some((l) => /[\u4e00-\u9fa5]/.test(l.text));
300
+ const longEnglishBlocks = lines.filter(
301
+ (l) => l.length > 100 && /^[a-zA-Z0-9\s\.,;\:'"()\[\]{}]+$/.test(l.text)
302
+ ).length;
303
+
304
+ if (hasChinese) {
305
+ p.textColor = ACADEMIC_PAPER_DEFAULTS.body.color;
306
+ p.bgColor = ACADEMIC_PAPER_DEFAULTS.pageBackground;
307
+ theme.typography.bodyFontFamily = ACADEMIC_PAPER_DEFAULTS.body.fontFamily;
308
+ theme.typography.headingFontFamily = ACADEMIC_PAPER_DEFAULTS.headings.h1.fontFamily;
309
+ } else if (longEnglishBlocks > 5) {
310
+ p.textColor = BUSINESS_REPORT_DEFAULTS.body.color;
311
+ p.bgColor = BUSINESS_REPORT_DEFAULTS.pageBackground;
312
+ theme.typography.bodyFontFamily = BUSINESS_REPORT_DEFAULTS.body.fontFamily;
313
+ theme.typography.headingFontFamily = BUSINESS_REPORT_DEFAULTS.headings.h1.fontFamily;
314
+ }
315
+
316
+ p.accentColor = hasChinese ? "#2b579a" : "#2563eb";
317
+ p.textMuted = hasChinese ? "#666666" : "#9ca3af";
318
+ }
319
+
320
+ /**
321
+ * 提取 PDF 元数据信息
322
+ */
323
+ private populateFromMetadata(
324
+ theme: ThemeStyle,
325
+ metadata: Record<string, unknown>
326
+ ): void {
327
+ if (metadata.Title && typeof metadata.Title === "string") {
328
+ theme.description = `主题提取自: ${metadata.Title}`;
329
+ }
330
+ if (metadata.Author && typeof metadata.Author === "string") {
331
+ theme.description = `${theme.description || ""} (作者: ${metadata.Author})`;
332
+ }
333
+ }
334
+
335
+ /**
336
+ * 基于内容特征判断文档类型并应用对应预设
337
+ */
338
+ private detectDocumentType(
339
+ theme: ThemeStyle,
340
+ _text: string,
341
+ pageCount: number
342
+ ): void {
343
+ if (pageCount <= 2) {
344
+ theme.description = `${theme.description} [单页文档]`;
345
+ } else if (pageCount > 20) {
346
+ theme.description = `${theme.description} [长篇文档 ${pageCount}页]`;
347
+ }
348
+ }
349
+
350
+ /**
351
+ * 应用 DocxStyleParadigm 标准参考值填充所有缺失字段
352
+ */
353
+ private applyParadigmDefaults(theme: ThemeStyle): void {
354
+ const preset = getRecommendedPreset();
355
+ const p = theme.palette;
356
+ const t = theme.typography;
357
+ const st = theme.seedTypography;
358
+
359
+ if (!p.textColor || p.textColor === "#000000") {
360
+ p.textColor = preset.body.color;
361
+ }
362
+ if (!p.headingColor) {
363
+ p.headingColor = preset.headings.h1.color;
364
+ }
365
+ if (!p.bgColor || p.bgColor === "#ffffff") {
366
+ p.bgColor = preset.pageBackground;
367
+ }
368
+ if (!p.textMuted) {
369
+ p.textMuted = preset.mutedTextColor;
370
+ }
371
+ if (!p.accentColor || p.accentColor === "#0000ff") {
372
+ p.accentColor = preset.accentColor;
373
+ }
374
+ if (!p.tableHeaderBg) {
375
+ p.tableHeaderBg = preset.table.headerBgColor;
376
+ }
377
+ if (!p.codeBg) {
378
+ p.codeBg = preset.inlineCode.bgColor;
379
+ }
380
+ if (!p.codeBlockBg) {
381
+ p.codeBlockBg = preset.codeBlock.bgColor;
382
+ }
383
+ if (!p.codeBlockText) {
384
+ p.codeBlockText = preset.codeBlock.color;
385
+ }
386
+ if (!p.blockquoteBg) {
387
+ p.blockquoteBg = preset.blockquote.bgColor;
388
+ }
389
+ if (!p.blockquoteBorder) {
390
+ p.blockquoteBorder = preset.blockquote.borderLeftColor;
391
+ }
392
+ if (!p.selectionBg) {
393
+ p.selectionBg = preset.selectionBg;
394
+ }
395
+ if (!p.borderColor) {
396
+ p.borderColor = preset.table.borderColor;
397
+ }
398
+
399
+ if (!t.bodyFontFamily || t.bodyFontFamily === "Georgia, serif") {
400
+ t.bodyFontFamily = preset.body.fontFamily;
401
+ }
402
+ if (!t.headingFontFamily) {
403
+ t.headingFontFamily = preset.headings.h1.fontFamily;
404
+ }
405
+ if (!t.baseFontSize) {
406
+ t.baseFontSize = `${preset.body.fontSize}px`;
407
+ }
408
+ if (t.baseLineHeight < 1.5) {
409
+ t.baseLineHeight = preset.body.lineHeight;
410
+ }
411
+
412
+ st.fontBody = preset.body.fontFamily;
413
+ st.fontHeading = preset.headings.h1.fontFamily;
414
+ st.lineHeightBody = preset.body.lineHeight;
415
+ st.lineHeightHeading = preset.headings.h1.lineHeight;
416
+
417
+ const issues = validateDocumentStyle(this.themeToParadigm(theme));
418
+ for (const issue of issues) {
419
+ if (issue.level === "error") {
420
+ console.warn(`[PdfExtractor] ${issue.element}: ${issue.message}`);
421
+ }
422
+ }
423
+ }
424
+
425
+ /**
426
+ * 将 ThemeStyle 转换为 DocumentStyleParadigm 用于 WCAG 验证
427
+ */
428
+ private themeToParadigm(theme: ThemeStyle): DocumentStyleParadigm {
429
+ return {
430
+ pageBackground: theme.palette.bgColor,
431
+ headings: {
432
+ h1: {
433
+ fontFamily: theme.seedTypography.fontHeading,
434
+ fontSize: 16 * theme.seedTypography.fontScaleH1,
435
+ fontWeight: theme.typography.headingWeight,
436
+ color: theme.palette.headingColor,
437
+ lineHeight: theme.seedTypography.lineHeightHeading,
438
+ },
439
+ h2: {
440
+ fontFamily: theme.seedTypography.fontHeading,
441
+ fontSize: 16 * theme.seedTypography.fontScaleH2,
442
+ fontWeight: Math.max(600, theme.typography.headingWeight - 100),
443
+ color: theme.palette.headingColor,
444
+ lineHeight: theme.seedTypography.lineHeightHeading,
445
+ },
446
+ h3: {
447
+ fontFamily: theme.seedTypography.fontHeading,
448
+ fontSize: 16 * theme.seedTypography.fontScaleH3,
449
+ fontWeight: 600,
450
+ color: theme.palette.headingColor,
451
+ lineHeight: theme.seedTypography.lineHeightHeading + 0.05,
452
+ },
453
+ h4: {
454
+ fontFamily: theme.seedTypography.fontHeading,
455
+ fontSize: 16 * theme.seedTypography.fontScaleH4,
456
+ fontWeight: 600,
457
+ color: theme.palette.textMuted,
458
+ lineHeight: theme.seedTypography.lineHeightHeading + 0.05,
459
+ },
460
+ h5: {
461
+ fontFamily: theme.seedTypography.fontHeading,
462
+ fontSize: 16 * theme.seedTypography.fontScaleH5,
463
+ fontWeight: 500,
464
+ color: theme.palette.textMuted,
465
+ lineHeight: theme.seedTypography.lineHeightBody - 0.25,
466
+ },
467
+ h6: {
468
+ fontFamily: theme.seedTypography.fontHeading,
469
+ fontSize: 16 * theme.seedTypography.fontScaleH6,
470
+ fontWeight: 500,
471
+ color: theme.palette.textMuted,
472
+ lineHeight: theme.seedTypography.lineHeightBody - 0.2,
473
+ },
474
+ },
475
+ body: {
476
+ fontFamily: theme.seedTypography.fontBody,
477
+ fontSize: parseInt(theme.typography.baseFontSize) || 16,
478
+ fontWeight: 400,
479
+ color: theme.palette.textColor,
480
+ lineHeight: theme.typography.baseLineHeight,
481
+ },
482
+ blockquote: {
483
+ fontFamily: theme.seedTypography.fontBody,
484
+ fontSize: Math.max(13, (parseInt(theme.typography.baseFontSize) || 16) - 2),
485
+ fontWeight: 400,
486
+ color: theme.palette.textMuted,
487
+ lineHeight: theme.typography.baseLineHeight - 0.15,
488
+ borderLeftColor: theme.palette.blockquoteBorder,
489
+ bgColor: theme.palette.blockquoteBg,
490
+ },
491
+ codeBlock: {
492
+ fontFamily: theme.typography.codeFontFamily,
493
+ fontSize: Math.max(12, (parseInt(theme.typography.baseFontSize) || 16) - 3),
494
+ fontWeight: 400,
495
+ color: theme.palette.codeBlockText || theme.palette.textColor,
496
+ lineHeight: theme.seedTypography.lineHeightCode,
497
+ bgColor: theme.palette.codeBlockBg,
498
+ },
499
+ inlineCode: {
500
+ fontSize: Math.max(12, (parseInt(theme.typography.baseFontSize) || 16) - 3),
501
+ color: theme.palette.accentColor,
502
+ bgColor: theme.palette.codeBg,
503
+ },
504
+ table: {
505
+ headerFontFamily: theme.seedTypography.fontHeading,
506
+ headerFontSize: Math.max(12, (parseInt(theme.typography.baseFontSize) || 16) - 3),
507
+ headerFontWeight: 700,
508
+ headerColor: "#ffffff",
509
+ headerBgColor: theme.palette.tableHeaderBg,
510
+ headerLineHeight: 1.4,
511
+
512
+ cellFontFamily: theme.seedTypography.fontBody,
513
+ cellFontSize: Math.max(11, (parseInt(theme.typography.baseFontSize) || 16) - 4),
514
+ cellColor: theme.palette.textColor,
515
+ cellBgColor: theme.palette.bgColor,
516
+ cellLineHeight: 1.5,
517
+ cellPadding: "8px 12px",
518
+ borderColor: theme.palette.borderColor,
519
+ borderWidth: "1px",
520
+ },
521
+
522
+ accentColor: theme.palette.accentColor,
523
+ mutedTextColor: theme.palette.textMuted,
524
+ selectionBg: theme.palette.selectionBg,
525
+ };
526
+ }
527
+ }