@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.
- package/.claude/skills/colamd-themes-preview.skill.md +333 -0
- package/.claude/skills/colamd-themes.skill.md +155 -0
- package/.hermes/skills/tools/colamd-themes/SKILL.md +159 -0
- package/.openclaw/skills/colamd-themes/SKILL.md +166 -0
- package/.opencode/skills/colamd-themes/SKILL.md +162 -0
- package/.trae/rules/colamd-themes.md +150 -0
- package/CHANGELOG.md +102 -0
- package/README.md +373 -0
- package/README_CN.md +373 -0
- package/RELEASENOTE.md +177 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +208 -0
- package/dist/cli.js.map +1 -0
- package/dist/color-systems.d.ts +17 -0
- package/dist/color-systems.js +251 -0
- package/dist/color-systems.js.map +1 -0
- package/dist/color-utils.d.ts +9 -0
- package/dist/color-utils.js +112 -0
- package/dist/color-utils.js.map +1 -0
- package/dist/contrast.d.ts +15 -0
- package/dist/contrast.js +63 -0
- package/dist/contrast.js.map +1 -0
- package/dist/docx-style-paradigm.d.ts +153 -0
- package/dist/docx-style-paradigm.js +640 -0
- package/dist/docx-style-paradigm.js.map +1 -0
- package/dist/export-cli.d.ts +10 -0
- package/dist/export-cli.js +266 -0
- package/dist/export-cli.js.map +1 -0
- package/dist/extractors/base.d.ts +6 -0
- package/dist/extractors/base.js +3 -0
- package/dist/extractors/base.js.map +1 -0
- package/dist/extractors/docx-extractor.d.ts +52 -0
- package/dist/extractors/docx-extractor.js +370 -0
- package/dist/extractors/docx-extractor.js.map +1 -0
- package/dist/extractors/pdf-extractor.d.ts +66 -0
- package/dist/extractors/pdf-extractor.js +430 -0
- package/dist/extractors/pdf-extractor.js.map +1 -0
- package/dist/extractors/url-extractor.d.ts +104 -0
- package/dist/extractors/url-extractor.js +761 -0
- package/dist/extractors/url-extractor.js.map +1 -0
- package/dist/generator.d.ts +4 -0
- package/dist/generator.js +71 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mermaid-presets.d.ts +14 -0
- package/dist/mermaid-presets.js +122 -0
- package/dist/mermaid-presets.js.map +1 -0
- package/dist/models.d.ts +106 -0
- package/dist/models.js +92 -0
- package/dist/models.js.map +1 -0
- package/dist/renderer.d.ts +70 -0
- package/dist/renderer.js +204 -0
- package/dist/renderer.js.map +1 -0
- package/dist/templates/template.css +498 -0
- package/dist/templates/theme-paradigm.md +658 -0
- package/dist/templates/theme-template.hbs +370 -0
- package/dist/theme-store.d.ts +37 -0
- package/dist/theme-store.js +90 -0
- package/dist/theme-store.js.map +1 -0
- package/dist/validators.d.ts +26 -0
- package/dist/validators.js +144 -0
- package/dist/validators.js.map +1 -0
- package/package.json +36 -0
- package/skills/build-skills.sh +166 -0
- package/skills/colamd-themes/SKILL.md +148 -0
- package/src/cli.ts +200 -0
- package/src/color-systems.ts +289 -0
- package/src/color-utils.ts +120 -0
- package/src/contrast.ts +66 -0
- package/src/docx-style-paradigm.ts +811 -0
- package/src/export-cli.ts +301 -0
- package/src/extractors/base.ts +8 -0
- package/src/extractors/docx-extractor.ts +417 -0
- package/src/extractors/pdf-extractor.ts +527 -0
- package/src/extractors/url-extractor.ts +927 -0
- package/src/generator.ts +88 -0
- package/src/index.ts +29 -0
- package/src/mermaid-presets.ts +142 -0
- package/src/models.ts +212 -0
- package/src/renderer.ts +277 -0
- package/src/templates/template.css +498 -0
- package/src/templates/theme-paradigm.md +658 -0
- package/src/templates/theme-template.hbs +370 -0
- package/src/theme-store.ts +112 -0
- package/src/types/pdf-parse.d.ts +12 -0
- package/src/validators.ts +176 -0
- package/themes/.gitkeep +0 -0
- package/themes/academic-paper-pt.css +1805 -0
- package/themes/academic-paper.css +1099 -0
- package/themes/academic-style.css +2430 -0
- package/themes/colly.css +370 -0
- package/themes/elegant.css +671 -0
- package/themes/forest-ink.css +664 -0
- package/themes/guizang.css +732 -0
- package/themes/meeting-minutes.css +370 -0
- package/themes/pixso-design.css +1261 -0
- package/themes/salvator-blog.css +370 -0
- package/themes/swiss-design copy.css +746 -0
- package/themes/swiss-design.css +746 -0
- package/themes/template.css +498 -0
- package/themes/trae-blue.css +737 -0
- package/themes-preview/colly-preview.html +623 -0
- package/themes-preview/demo-content.md +187 -0
- package/themes-preview/meeting-minutes-preview.html +625 -0
- package/themes-preview/salvator-blog-preview.html +623 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* ColaMD Theme: {{ name }}
|
|
3
|
+
* {{ description }}
|
|
4
|
+
* Generated by colamd-themes ({{ sourceType }}: {{ sourceUrl }})
|
|
5
|
+
*
|
|
6
|
+
* ═══════════════════════════════════════════════════════════
|
|
7
|
+
* SECTION 1 — Design Tokens
|
|
8
|
+
* Modify the 5 seed colors + 3 font stacks to change the theme
|
|
9
|
+
* ═══════════════════════════════════════════════════════════ */
|
|
10
|
+
|
|
11
|
+
body.theme-custom {
|
|
12
|
+
|
|
13
|
+
/* ── 1.1 Seed Palette ── */
|
|
14
|
+
--seed-accent: {{ seed.accent }};
|
|
15
|
+
--seed-accent-light: {{ seed.accentLight }};
|
|
16
|
+
--seed-accent-dark: {{ seed.accentDark }};
|
|
17
|
+
--seed-surface: {{ seed.surface }};
|
|
18
|
+
--seed-panel: {{ seed.panel }};
|
|
19
|
+
--seed-panel-alt: {{ seed.panelAlt }};
|
|
20
|
+
--seed-ink: {{ seed.ink }};
|
|
21
|
+
--seed-ink-muted: {{ seed.inkMuted }};
|
|
22
|
+
--seed-ink-dim: {{ seed.inkDim }};
|
|
23
|
+
--seed-border: {{ seed.border }};
|
|
24
|
+
--seed-border-strong: {{ seed.borderStrong }};
|
|
25
|
+
|
|
26
|
+
/* ── 1.2 Typography ── */
|
|
27
|
+
--font-body: {{{ seedTypography.fontBody }}};
|
|
28
|
+
--font-heading: {{{ seedTypography.fontHeading }}};
|
|
29
|
+
--font-code: {{{ seedTypography.fontCode }}};
|
|
30
|
+
--font-mermaid: {{ seedTypography.fontMermaid }};
|
|
31
|
+
|
|
32
|
+
/* ── 1.3 Font Sizing ── */
|
|
33
|
+
--font-size-root: {{ seedTypography.fontSizeRoot }};
|
|
34
|
+
--font-scale-h1: {{ seedTypography.fontScaleH1 }};
|
|
35
|
+
--font-scale-h2: {{ seedTypography.fontScaleH2 }};
|
|
36
|
+
--font-scale-h3: {{ seedTypography.fontScaleH3 }};
|
|
37
|
+
--font-scale-h4: {{ seedTypography.fontScaleH4 }};
|
|
38
|
+
--font-scale-h5: {{ seedTypography.fontScaleH5 }};
|
|
39
|
+
--font-scale-h6: {{ seedTypography.fontScaleH6 }};
|
|
40
|
+
--font-size-mermaid: {{ seedTypography.fontSizeMermaid }};
|
|
41
|
+
--line-height-body: {{ seedTypography.lineHeightBody }};
|
|
42
|
+
--line-height-heading: {{ seedTypography.lineHeightHeading }};
|
|
43
|
+
--line-height-code: {{ seedTypography.lineHeightCode }};
|
|
44
|
+
|
|
45
|
+
/* ── 1.4 Radii & Spacing ── */
|
|
46
|
+
--radius-sm: {{ radiusSm }};
|
|
47
|
+
--radius-md: {{ radiusMd }};
|
|
48
|
+
--radius-lg: {{ radiusLg }};
|
|
49
|
+
--content-width: {{ contentWidth }};
|
|
50
|
+
|
|
51
|
+
/* ═══════════════════════════════════════════════════════════
|
|
52
|
+
SECTION 2 — Semantic Mapping
|
|
53
|
+
Auto-maps seed tokens → ColaMD built-in variables
|
|
54
|
+
═══════════════════════════════════════════════════════════ */
|
|
55
|
+
|
|
56
|
+
/* ── 2.1 Surface ── */
|
|
57
|
+
--bg-color: var(--seed-surface);
|
|
58
|
+
--surface-color: var(--seed-panel);
|
|
59
|
+
--surface-alt: var(--seed-panel-alt);
|
|
60
|
+
|
|
61
|
+
/* ── 2.2 Text ── */
|
|
62
|
+
--text-color: var(--seed-ink);
|
|
63
|
+
--heading-color: var(--seed-ink);
|
|
64
|
+
--text-muted: var(--seed-ink-muted);
|
|
65
|
+
--text-dim: var(--seed-ink-dim);
|
|
66
|
+
|
|
67
|
+
/* ── 2.3 Links & Accent ── */
|
|
68
|
+
--link-color: var(--seed-accent);
|
|
69
|
+
--accent-color: var(--seed-accent);
|
|
70
|
+
--accent-dark: var(--seed-accent-dark);
|
|
71
|
+
--accent-light: var(--seed-accent-light);
|
|
72
|
+
--selection-bg: {{rgba seed.accent 0.15}};
|
|
73
|
+
|
|
74
|
+
/* ── 2.4 Borders ── */
|
|
75
|
+
--border-color: var(--seed-border);
|
|
76
|
+
--blockquote-border: var(--seed-accent);
|
|
77
|
+
--hr-color: var(--seed-border);
|
|
78
|
+
|
|
79
|
+
/* ── 2.5 Inline Code ── */
|
|
80
|
+
--code-bg: var(--seed-panel);
|
|
81
|
+
--code-color: var(--seed-accent-dark);
|
|
82
|
+
|
|
83
|
+
/* ── 2.6 Code Blocks ── */
|
|
84
|
+
--code-block-bg: var(--seed-panel-alt);
|
|
85
|
+
--code-block-text: var(--seed-ink);
|
|
86
|
+
--code-block-color: var(--seed-ink);
|
|
87
|
+
|
|
88
|
+
/* ── 2.7 Blockquote ── */
|
|
89
|
+
--blockquote-bg: var(--seed-panel);
|
|
90
|
+
|
|
91
|
+
/* ── 2.8 Tables ── */
|
|
92
|
+
--table-header-bg: var(--seed-panel);
|
|
93
|
+
--table-border: var(--seed-border);
|
|
94
|
+
|
|
95
|
+
/* ── 2.9 Scrollbar ── */
|
|
96
|
+
--scrollbar-thumb: var(--seed-border-strong);
|
|
97
|
+
--scrollbar-thumb-hover: var(--seed-ink-muted);
|
|
98
|
+
|
|
99
|
+
/* ═══════════════════════════════════════════════════════════
|
|
100
|
+
SECTION 3 — Mermaid 20 Core Variables
|
|
101
|
+
Auto-consumed by built-in variables.css for 22 diagram types
|
|
102
|
+
═══════════════════════════════════════════════════════════ */
|
|
103
|
+
|
|
104
|
+
/* ── 3.1 Container ── */
|
|
105
|
+
--mermaid-background: var(--seed-panel);
|
|
106
|
+
--mermaid-border-color: var(--seed-border);
|
|
107
|
+
--mermaid-border-radius: var(--radius-md);
|
|
108
|
+
--mermaid-padding: 20px;
|
|
109
|
+
|
|
110
|
+
/* ── 3.2 Font ── */
|
|
111
|
+
--mermaid-font-family: var(--font-mermaid);
|
|
112
|
+
--mermaid-font-size: var(--font-size-mermaid);
|
|
113
|
+
|
|
114
|
+
/* ── 3.3 Nodes ── */
|
|
115
|
+
--mermaid-node-fill: var(--seed-panel);
|
|
116
|
+
--mermaid-node-stroke: var(--seed-accent);
|
|
117
|
+
--mermaid-node-stroke-width: 1.5px;
|
|
118
|
+
--mermaid-node-text: var(--seed-ink);
|
|
119
|
+
|
|
120
|
+
/* ── 3.4 Edges ── */
|
|
121
|
+
--mermaid-edge-stroke: var(--seed-ink-muted);
|
|
122
|
+
--mermaid-edge-stroke-width: 1.5px;
|
|
123
|
+
|
|
124
|
+
/* ── 3.5 Clusters ── */
|
|
125
|
+
--mermaid-cluster-fill: {{rgba seed.accent 0.06}};
|
|
126
|
+
--mermaid-cluster-stroke: var(--seed-accent);
|
|
127
|
+
|
|
128
|
+
/* ── 3.6 Labels ── */
|
|
129
|
+
--mermaid-label-text: var(--seed-ink);
|
|
130
|
+
--mermaid-edge-label-text: var(--seed-ink-muted);
|
|
131
|
+
--mermaid-edge-label-bg: var(--seed-surface);
|
|
132
|
+
|
|
133
|
+
/* ── 3.7 Titles & Axes ── */
|
|
134
|
+
--mermaid-title-text: var(--seed-ink);
|
|
135
|
+
--mermaid-axis-text: var(--seed-ink-muted);
|
|
136
|
+
--mermaid-highlight: var(--seed-accent);
|
|
137
|
+
|
|
138
|
+
/* ── 3.8 Person Nodes ── */
|
|
139
|
+
--mermaid-person-stroke: var(--seed-ink);
|
|
140
|
+
--mermaid-person-fill: var(--seed-panel);
|
|
141
|
+
|
|
142
|
+
/* ── 3.9 Label Offset ── */
|
|
143
|
+
--mermaid-label-offset-y: 0px;
|
|
144
|
+
|
|
145
|
+
/* ── 4. Fine Tuning ── */
|
|
146
|
+
--line-height-base: var(--line-height-body);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/* ═══════════════════════════════════════════════════════════
|
|
150
|
+
SECTION 5 — Selector-Level Micro Adjustments
|
|
151
|
+
Only where base.css doesn't cover. All values via var(--*).
|
|
152
|
+
═══════════════════════════════════════════════════════════ */
|
|
153
|
+
|
|
154
|
+
html { font-size: var(--font-size-root); }
|
|
155
|
+
body.theme-custom, html, body {
|
|
156
|
+
background-color: var(--bg-color);
|
|
157
|
+
color: var(--text-color);
|
|
158
|
+
font-family: var(--font-body);
|
|
159
|
+
line-height: var(--line-height-body);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#write {
|
|
163
|
+
max-width: var(--content-width);
|
|
164
|
+
margin: 0 auto;
|
|
165
|
+
padding: 30px 60px 100px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
body.theme-custom h1, body.theme-custom h2, body.theme-custom h3,
|
|
169
|
+
body.theme-custom h4, body.theme-custom h5, body.theme-custom h6 {
|
|
170
|
+
font-family: var(--font-heading);
|
|
171
|
+
color: var(--heading-color);
|
|
172
|
+
font-weight: 700;
|
|
173
|
+
line-height: var(--line-height-heading);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
body.theme-custom h1 { font-size: calc(var(--font-size-root) * var(--font-scale-h1)); }
|
|
177
|
+
body.theme-custom h2 { font-size: calc(var(--font-size-root) * var(--font-scale-h2)); }
|
|
178
|
+
body.theme-custom h3 { font-size: calc(var(--font-size-root) * var(--font-scale-h3)); }
|
|
179
|
+
body.theme-custom h4 { font-size: calc(var(--font-size-root) * var(--font-scale-h4)); }
|
|
180
|
+
body.theme-custom h5 { font-size: calc(var(--font-size-root) * var(--font-scale-h5)); }
|
|
181
|
+
body.theme-custom h6 { font-size: calc(var(--font-size-root) * var(--font-scale-h6)); }
|
|
182
|
+
|
|
183
|
+
body.theme-custom strong { color: var(--accent-color); }
|
|
184
|
+
body.theme-custom code {
|
|
185
|
+
font-family: var(--font-code);
|
|
186
|
+
background: var(--code-bg);
|
|
187
|
+
color: var(--code-color);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
body.theme-custom pre {
|
|
191
|
+
background: var(--code-block-bg);
|
|
192
|
+
font-family: var(--font-code);
|
|
193
|
+
line-height: var(--line-height-code);
|
|
194
|
+
}
|
|
195
|
+
body.theme-custom pre code { color: var(--code-block-text); background: transparent; }
|
|
196
|
+
|
|
197
|
+
body.theme-custom blockquote {
|
|
198
|
+
background: var(--blockquote-bg);
|
|
199
|
+
border-left: 4px solid var(--blockquote-border);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
body.theme-custom table th {
|
|
203
|
+
background: var(--table-header-bg);
|
|
204
|
+
font-weight: 700;
|
|
205
|
+
border-bottom: 2px solid var(--accent-color);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
body.theme-custom hr {
|
|
209
|
+
border: none;
|
|
210
|
+
border-top: 1px solid var(--hr-color);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
body.theme-custom img { max-width: 100%; }
|
|
214
|
+
|
|
215
|
+
/* ── 5.11 Mermaid caption ── */
|
|
216
|
+
body.theme-custom .mermaid-block + p {
|
|
217
|
+
text-align: center;
|
|
218
|
+
font-family: var(--font-heading);
|
|
219
|
+
font-size: calc(var(--font-size-mermaid) + 2px);
|
|
220
|
+
color: var(--text-muted);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* ── 5.12 Responsive ── */
|
|
224
|
+
@media only screen and (max-width: 768px) {
|
|
225
|
+
#write { padding: 20px; }
|
|
226
|
+
body.theme-custom .mermaid-block { padding: 12px; }
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/* ═══════════════════════════════════════════════════════════
|
|
230
|
+
SECTION 6 — Print / Export
|
|
231
|
+
Screen mirror: every screen property restated with !important.
|
|
232
|
+
═══════════════════════════════════════════════════════════ */
|
|
233
|
+
@media print {
|
|
234
|
+
@page { margin: 20mm; }
|
|
235
|
+
|
|
236
|
+
/* ── 6.0 Variable re-declaration (Chromium strips CSS variables in print) ── */
|
|
237
|
+
body.theme-custom {
|
|
238
|
+
--seed-accent: {{ seed.accent }};
|
|
239
|
+
--seed-accent-dark: {{ seed.accentDark }};
|
|
240
|
+
--seed-surface: {{ seed.surface }};
|
|
241
|
+
--seed-ink: {{ seed.ink }};
|
|
242
|
+
--seed-ink-muted: {{ seed.inkMuted }};
|
|
243
|
+
--seed-panel: {{ seed.panel }};
|
|
244
|
+
--seed-panel-alt: {{ seed.panelAlt }};
|
|
245
|
+
--seed-border: {{ seed.border }};
|
|
246
|
+
--font-size-root: {{ seedTypography.fontSizeRoot }};
|
|
247
|
+
--line-height-body: {{ seedTypography.lineHeightBody }};
|
|
248
|
+
--line-height-heading: {{ seedTypography.lineHeightHeading }};
|
|
249
|
+
--line-height-code: {{ seedTypography.lineHeightCode }};
|
|
250
|
+
--font-scale-h1: {{ seedTypography.fontScaleH1 }};
|
|
251
|
+
--font-scale-h2: {{ seedTypography.fontScaleH2 }};
|
|
252
|
+
--font-scale-h3: {{ seedTypography.fontScaleH3 }};
|
|
253
|
+
--font-scale-h4: {{ seedTypography.fontScaleH4 }};
|
|
254
|
+
--font-scale-h5: {{ seedTypography.fontScaleH5 }};
|
|
255
|
+
--font-scale-h6: {{ seedTypography.fontScaleH6 }};
|
|
256
|
+
--content-width: {{ contentWidth }};
|
|
257
|
+
--font-size-mermaid: {{ seedTypography.fontSizeMermaid }};
|
|
258
|
+
--accent-color: var(--seed-accent);
|
|
259
|
+
--accent-dark: var(--seed-accent-dark);
|
|
260
|
+
--code-bg: var(--seed-panel);
|
|
261
|
+
--code-color: var(--seed-accent-dark);
|
|
262
|
+
--code-block-bg: var(--seed-panel-alt);
|
|
263
|
+
--code-block-text: var(--seed-ink);
|
|
264
|
+
--blockquote-bg: var(--seed-panel);
|
|
265
|
+
--table-header-bg: var(--seed-panel);
|
|
266
|
+
--border-color: var(--seed-border);
|
|
267
|
+
--hr-color: var(--seed-border);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
html, body, body.theme-custom {
|
|
271
|
+
background: var(--seed-surface) !important;
|
|
272
|
+
color: var(--seed-ink) !important;
|
|
273
|
+
font-family: var(--font-body) !important;
|
|
274
|
+
line-height: var(--line-height-body) !important;
|
|
275
|
+
-webkit-print-color-adjust: exact !important;
|
|
276
|
+
print-color-adjust: exact !important;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
#write {
|
|
280
|
+
max-width: var(--content-width) !important;
|
|
281
|
+
margin: 0 auto !important;
|
|
282
|
+
padding: 30px 60px 100px !important;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
body.theme-custom h1, body.theme-custom h2, body.theme-custom h3,
|
|
286
|
+
body.theme-custom h4, body.theme-custom h5, body.theme-custom h6 {
|
|
287
|
+
font-family: var(--font-heading) !important;
|
|
288
|
+
color: var(--seed-ink) !important;
|
|
289
|
+
font-weight: 700 !important;
|
|
290
|
+
line-height: var(--line-height-heading) !important;
|
|
291
|
+
-webkit-print-color-adjust: exact !important;
|
|
292
|
+
print-color-adjust: exact !important;
|
|
293
|
+
}
|
|
294
|
+
body.theme-custom h1 { font-size: calc(var(--font-size-root) * var(--font-scale-h1)) !important; }
|
|
295
|
+
body.theme-custom h2 { font-size: calc(var(--font-size-root) * var(--font-scale-h2)) !important; }
|
|
296
|
+
body.theme-custom h3 { font-size: calc(var(--font-size-root) * var(--font-scale-h3)) !important; }
|
|
297
|
+
body.theme-custom h4 { font-size: calc(var(--font-size-root) * var(--font-scale-h4)) !important; }
|
|
298
|
+
body.theme-custom h5 { font-size: calc(var(--font-size-root) * var(--font-scale-h5)) !important; }
|
|
299
|
+
body.theme-custom h6 { font-size: calc(var(--font-size-root) * var(--font-scale-h6)) !important; }
|
|
300
|
+
|
|
301
|
+
body.theme-custom strong {
|
|
302
|
+
color: var(--accent-color) !important;
|
|
303
|
+
-webkit-print-color-adjust: exact !important;
|
|
304
|
+
print-color-adjust: exact !important;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
body.theme-custom code {
|
|
308
|
+
font-family: var(--font-code) !important;
|
|
309
|
+
background: var(--code-bg) !important;
|
|
310
|
+
color: var(--code-color) !important;
|
|
311
|
+
-webkit-print-color-adjust: exact !important;
|
|
312
|
+
print-color-adjust: exact !important;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
body.theme-custom pre {
|
|
316
|
+
background: var(--code-block-bg) !important;
|
|
317
|
+
font-family: var(--font-code) !important;
|
|
318
|
+
line-height: var(--line-height-code) !important;
|
|
319
|
+
-webkit-print-color-adjust: exact !important;
|
|
320
|
+
print-color-adjust: exact !important;
|
|
321
|
+
}
|
|
322
|
+
body.theme-custom pre code { color: var(--code-block-text) !important; background: transparent !important; }
|
|
323
|
+
|
|
324
|
+
body.theme-custom blockquote {
|
|
325
|
+
background: var(--blockquote-bg) !important;
|
|
326
|
+
border-left: 4px solid var(--seed-accent) !important;
|
|
327
|
+
-webkit-print-color-adjust: exact !important;
|
|
328
|
+
print-color-adjust: exact !important;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
body.theme-custom table th {
|
|
332
|
+
background: var(--table-header-bg) !important;
|
|
333
|
+
color: var(--seed-ink) !important;
|
|
334
|
+
font-weight: 700 !important;
|
|
335
|
+
border-bottom: 2px solid var(--accent-color) !important;
|
|
336
|
+
-webkit-print-color-adjust: exact !important;
|
|
337
|
+
print-color-adjust: exact !important;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
body.theme-custom a {
|
|
341
|
+
color: var(--seed-accent) !important;
|
|
342
|
+
-webkit-print-color-adjust: exact !important;
|
|
343
|
+
print-color-adjust: exact !important;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
body.theme-custom hr {
|
|
347
|
+
border: none !important;
|
|
348
|
+
border-top: 1px solid var(--hr-color) !important;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
body.theme-custom img { max-width: 100% !important; }
|
|
352
|
+
|
|
353
|
+
body.theme-custom .mermaid-block {
|
|
354
|
+
background: var(--seed-surface) !important;
|
|
355
|
+
border-color: var(--seed-border) !important;
|
|
356
|
+
-webkit-print-color-adjust: exact !important;
|
|
357
|
+
print-color-adjust: exact !important;
|
|
358
|
+
}
|
|
359
|
+
body.theme-custom .mermaid-preview svg * {
|
|
360
|
+
-webkit-print-color-adjust: exact !important;
|
|
361
|
+
print-color-adjust: exact !important;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
body.theme-custom .mermaid-block + p {
|
|
365
|
+
color: var(--seed-ink-muted) !important;
|
|
366
|
+
text-align: center !important;
|
|
367
|
+
font-family: var(--font-heading) !important;
|
|
368
|
+
font-size: calc(var(--font-size-mermaid) + 2px) !important;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme configuration persistence.
|
|
3
|
+
*
|
|
4
|
+
* Stores default theme and registered custom themes in ~/.colamd-themes/config.json
|
|
5
|
+
*/
|
|
6
|
+
/** Built-in themes provided by @bytechain.cn/colamd */
|
|
7
|
+
export declare const BUILTIN_THEMES: readonly ["light", "dark", "elegant", "newsprint"];
|
|
8
|
+
export type BuiltinTheme = (typeof BUILTIN_THEMES)[number];
|
|
9
|
+
export interface ThemeConfig {
|
|
10
|
+
/** Default theme name (built-in or custom) */
|
|
11
|
+
defaultTheme: string;
|
|
12
|
+
/** Registered custom themes: name → CSS file path */
|
|
13
|
+
themes: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
/** Get the full config. */
|
|
16
|
+
export declare function getConfig(): ThemeConfig;
|
|
17
|
+
/** Set the default theme (built-in name or registered custom name). */
|
|
18
|
+
export declare function setDefaultTheme(name: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Register a custom theme.
|
|
21
|
+
* @param name Unique name (will be prefixed with "custom:" when applied)
|
|
22
|
+
* @param cssPath Absolute path to the CSS file
|
|
23
|
+
*/
|
|
24
|
+
export declare function registerTheme(name: string, cssPath: string): void;
|
|
25
|
+
/** Remove a registered custom theme. */
|
|
26
|
+
export declare function unregisterTheme(name: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Resolve a theme name to the arguments needed by the ColaMD renderer.
|
|
29
|
+
*
|
|
30
|
+
* @param name Theme name. If omitted, uses the configured default.
|
|
31
|
+
* @returns { themeName, customCSS? } — themeName is either a built-in name
|
|
32
|
+
* or "custom:<name>"; customCSS is the CSS content for custom themes.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveTheme(name?: string): {
|
|
35
|
+
themeName: string;
|
|
36
|
+
customCSS?: string;
|
|
37
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Theme configuration persistence.
|
|
3
|
+
*
|
|
4
|
+
* Stores default theme and registered custom themes in ~/.colamd-themes/config.json
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { homedir } from "node:os";
|
|
9
|
+
const CONFIG_DIR = join(homedir(), ".colamd-themes");
|
|
10
|
+
const CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
11
|
+
/** Built-in themes provided by @bytechain.cn/colamd */
|
|
12
|
+
export const BUILTIN_THEMES = ["light", "dark", "elegant", "newsprint"];
|
|
13
|
+
function readConfig() {
|
|
14
|
+
if (!existsSync(CONFIG_FILE))
|
|
15
|
+
return { defaultTheme: "elegant", themes: {} };
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(readFileSync(CONFIG_FILE, "utf-8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return { defaultTheme: "elegant", themes: {} };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function writeConfig(config) {
|
|
24
|
+
if (!existsSync(CONFIG_DIR))
|
|
25
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
26
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), "utf-8");
|
|
27
|
+
}
|
|
28
|
+
/** Get the full config. */
|
|
29
|
+
export function getConfig() {
|
|
30
|
+
return readConfig();
|
|
31
|
+
}
|
|
32
|
+
/** Set the default theme (built-in name or registered custom name). */
|
|
33
|
+
export function setDefaultTheme(name) {
|
|
34
|
+
const config = readConfig();
|
|
35
|
+
config.defaultTheme = name;
|
|
36
|
+
writeConfig(config);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Register a custom theme.
|
|
40
|
+
* @param name Unique name (will be prefixed with "custom:" when applied)
|
|
41
|
+
* @param cssPath Absolute path to the CSS file
|
|
42
|
+
*/
|
|
43
|
+
export function registerTheme(name, cssPath) {
|
|
44
|
+
const config = readConfig();
|
|
45
|
+
config.themes[name] = cssPath;
|
|
46
|
+
writeConfig(config);
|
|
47
|
+
}
|
|
48
|
+
/** Remove a registered custom theme. */
|
|
49
|
+
export function unregisterTheme(name) {
|
|
50
|
+
const config = readConfig();
|
|
51
|
+
if (!(name in config.themes))
|
|
52
|
+
return false;
|
|
53
|
+
delete config.themes[name];
|
|
54
|
+
writeConfig(config);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a theme name to the arguments needed by the ColaMD renderer.
|
|
59
|
+
*
|
|
60
|
+
* @param name Theme name. If omitted, uses the configured default.
|
|
61
|
+
* @returns { themeName, customCSS? } — themeName is either a built-in name
|
|
62
|
+
* or "custom:<name>"; customCSS is the CSS content for custom themes.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveTheme(name) {
|
|
65
|
+
const config = readConfig();
|
|
66
|
+
const resolved = name ?? config.defaultTheme;
|
|
67
|
+
// Check if it's a registered custom theme
|
|
68
|
+
if (config.themes[resolved]) {
|
|
69
|
+
const cssPath = config.themes[resolved];
|
|
70
|
+
if (!existsSync(cssPath)) {
|
|
71
|
+
throw new Error(`Custom theme CSS file not found: ${cssPath}`);
|
|
72
|
+
}
|
|
73
|
+
return { themeName: `custom:${resolved}`, customCSS: readFileSync(cssPath, "utf-8") };
|
|
74
|
+
}
|
|
75
|
+
// Check if it's a built-in theme
|
|
76
|
+
if (BUILTIN_THEMES.includes(resolved)) {
|
|
77
|
+
return { themeName: resolved };
|
|
78
|
+
}
|
|
79
|
+
// Treat as a direct CSS file path
|
|
80
|
+
if (existsSync(resolved)) {
|
|
81
|
+
const nameFromPath = resolved.replace(/\.css$/i, "").split("/").pop() ?? "custom";
|
|
82
|
+
return {
|
|
83
|
+
themeName: `custom:${nameFromPath}`,
|
|
84
|
+
customCSS: readFileSync(resolved, "utf-8"),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`Unknown theme: "${resolved}". Use a built-in theme (${BUILTIN_THEMES.join(", ")}), ` +
|
|
88
|
+
`a registered custom theme, or a path to a .css file.`);
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=theme-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-store.js","sourceRoot":"","sources":["../src/theme-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paradigm validation engine — checks SeedPalette against v3.0 design constraints.
|
|
3
|
+
* Based on theme-paradigm.md Section 2.
|
|
4
|
+
*/
|
|
5
|
+
export interface ValidationIssue {
|
|
6
|
+
ruleId: string;
|
|
7
|
+
level: "MUST" | "MUST_NOT" | "SHOULD" | "SHOULD_NOT";
|
|
8
|
+
message: string;
|
|
9
|
+
fix?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface SeedPalette {
|
|
12
|
+
accent: string;
|
|
13
|
+
accentLight: string;
|
|
14
|
+
accentDark: string;
|
|
15
|
+
surface: string;
|
|
16
|
+
panel: string;
|
|
17
|
+
panelAlt: string;
|
|
18
|
+
ink: string;
|
|
19
|
+
inkMuted: string;
|
|
20
|
+
inkDim: string;
|
|
21
|
+
border: string;
|
|
22
|
+
borderStrong: string;
|
|
23
|
+
}
|
|
24
|
+
export declare function validateSeedPalette(palette: SeedPalette): ValidationIssue[];
|
|
25
|
+
/** Summarize validation results. */
|
|
26
|
+
export declare function summarizeIssues(issues: ValidationIssue[]): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Paradigm validation engine — checks SeedPalette against v3.0 design constraints.
|
|
3
|
+
* Based on theme-paradigm.md Section 2.
|
|
4
|
+
*/
|
|
5
|
+
import { contrastRatio, hslSaturation, hslLightness, sameHueAxis, isLightMode } from "./contrast.js";
|
|
6
|
+
export function validateSeedPalette(palette) {
|
|
7
|
+
const issues = [];
|
|
8
|
+
const light = isLightMode(palette.surface);
|
|
9
|
+
// CR-01: ink vs surface ≥ 7:1
|
|
10
|
+
const crInk = contrastRatio(palette.ink, palette.surface);
|
|
11
|
+
if (crInk < 7.0) {
|
|
12
|
+
issues.push({
|
|
13
|
+
ruleId: "CR-01",
|
|
14
|
+
level: "MUST",
|
|
15
|
+
message: `正文-底色对比度 ${crInk.toFixed(1)}:1 < 7:1 (WCAG AAA)`,
|
|
16
|
+
fix: `建议加深 ink 或调浅 surface`,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
// CR-02: inkMuted vs surface ≥ 4.5:1
|
|
20
|
+
const crMuted = contrastRatio(palette.inkMuted, palette.surface);
|
|
21
|
+
if (crMuted < 4.5) {
|
|
22
|
+
issues.push({
|
|
23
|
+
ruleId: "CR-02",
|
|
24
|
+
level: "MUST",
|
|
25
|
+
message: `次要文字-底色对比度 ${crMuted.toFixed(1)}:1 < 4.5:1 (WCAG AA)`,
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
// CR-04: accent vs surface ≥ 4.5:1
|
|
29
|
+
const crAccent = contrastRatio(palette.accent, palette.surface);
|
|
30
|
+
if (crAccent < 4.5) {
|
|
31
|
+
issues.push({
|
|
32
|
+
ruleId: "CR-04",
|
|
33
|
+
level: "MUST",
|
|
34
|
+
message: `点缀色-底色对比度 ${crAccent.toFixed(1)}:1 < 4.5:1`,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
// SL-01: surface saturation ≤ 0.05
|
|
38
|
+
const sSurface = hslSaturation(palette.surface);
|
|
39
|
+
if (sSurface > 0.05) {
|
|
40
|
+
issues.push({
|
|
41
|
+
ruleId: "SL-01",
|
|
42
|
+
level: "MUST",
|
|
43
|
+
message: `底色饱和度 ${(sSurface * 100).toFixed(1)}% > 5%,页面会偏色`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
// SL-02: panel/panelAlt saturation ≤ 0.10
|
|
47
|
+
for (const [name, hex] of [["panel", palette.panel], ["panelAlt", palette.panelAlt]]) {
|
|
48
|
+
const s = hslSaturation(hex);
|
|
49
|
+
if (s > 0.10) {
|
|
50
|
+
issues.push({
|
|
51
|
+
ruleId: "SL-02",
|
|
52
|
+
level: "MUST_NOT",
|
|
53
|
+
message: `表面色 ${name} 饱和度 ${(s * 100).toFixed(1)}% > 10%`,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// SL-03: surface/panel/panelAlt same hue axis
|
|
58
|
+
if (!sameHueAxis(palette.surface, palette.panel, 5) || !sameHueAxis(palette.surface, palette.panelAlt, 5)) {
|
|
59
|
+
issues.push({
|
|
60
|
+
ruleId: "SL-03",
|
|
61
|
+
level: "SHOULD",
|
|
62
|
+
message: "三层表面色应保持相同色相轴(H 偏差 ≤ 5°)",
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// SL-04: L(surface) > L(panel) > L(panelAlt) for light
|
|
66
|
+
const lSurface = hslLightness(palette.surface);
|
|
67
|
+
const lPanel = hslLightness(palette.panel);
|
|
68
|
+
const lPanelAlt = hslLightness(palette.panelAlt);
|
|
69
|
+
if (light) {
|
|
70
|
+
if (!(lSurface > lPanel && lPanel > lPanelAlt)) {
|
|
71
|
+
issues.push({
|
|
72
|
+
ruleId: "SL-04",
|
|
73
|
+
level: "MUST",
|
|
74
|
+
message: `浅色主题要求 L(surface) > L(panel) > L(panelAlt)`,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
if (!(lSurface < lPanel && lPanel < lPanelAlt)) {
|
|
80
|
+
issues.push({
|
|
81
|
+
ruleId: "SL-04",
|
|
82
|
+
level: "MUST",
|
|
83
|
+
message: `深色主题要求 L(surface) < L(panel) < L(panelAlt)`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// NT-01: ink/inkMuted/inkDim same hue axis
|
|
88
|
+
if (!sameHueAxis(palette.ink, palette.inkMuted, 3) || !sameHueAxis(palette.ink, palette.inkDim, 3)) {
|
|
89
|
+
issues.push({
|
|
90
|
+
ruleId: "NT-01",
|
|
91
|
+
level: "MUST",
|
|
92
|
+
message: "文字色必须位于同一色相轴(H 偏差 ≤ 3°)",
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
// NT-02: border vs panel lightness diff ≥ 0.08
|
|
96
|
+
const lBorder = hslLightness(palette.border);
|
|
97
|
+
if (Math.abs(lBorder - lPanel) < 0.08) {
|
|
98
|
+
issues.push({
|
|
99
|
+
ruleId: "NT-02",
|
|
100
|
+
level: "MUST",
|
|
101
|
+
message: `边框色与 panel 明度差 ${Math.abs(lBorder - lPanel).toFixed(3)} < 0.08,边框不可见`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
// NT-03: border should be neutral gray
|
|
105
|
+
const sBorder = hslSaturation(palette.border);
|
|
106
|
+
if (sBorder > 0.05) {
|
|
107
|
+
issues.push({
|
|
108
|
+
ruleId: "NT-03",
|
|
109
|
+
level: "SHOULD",
|
|
110
|
+
message: `边框色饱和度 ${(sBorder * 100).toFixed(1)}% > 5%,应使用中性灰`,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// HR-01: accent saturation ≥ 0.30 for light themes
|
|
114
|
+
const sAccent = hslSaturation(palette.accent);
|
|
115
|
+
if (light && sAccent < 0.30) {
|
|
116
|
+
issues.push({
|
|
117
|
+
ruleId: "HR-01",
|
|
118
|
+
level: "SHOULD",
|
|
119
|
+
message: `点缀色饱和度 ${(sAccent * 100).toFixed(1)}% < 30%,建议选暖色或冷色`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return issues;
|
|
123
|
+
}
|
|
124
|
+
/** Summarize validation results. */
|
|
125
|
+
export function summarizeIssues(issues) {
|
|
126
|
+
const errors = issues.filter((i) => i.level === "MUST" || i.level === "MUST_NOT");
|
|
127
|
+
const warnings = issues.filter((i) => i.level === "SHOULD" || i.level === "SHOULD_NOT");
|
|
128
|
+
const lines = [];
|
|
129
|
+
if (errors.length > 0) {
|
|
130
|
+
lines.push(`ERRORS (${errors.length}):`);
|
|
131
|
+
for (const e of errors)
|
|
132
|
+
lines.push(` [${e.ruleId}] ${e.message}`);
|
|
133
|
+
}
|
|
134
|
+
if (warnings.length > 0) {
|
|
135
|
+
lines.push(`WARNINGS (${warnings.length}):`);
|
|
136
|
+
for (const w of warnings)
|
|
137
|
+
lines.push(` [${w.ruleId}] ${w.message}`);
|
|
138
|
+
}
|
|
139
|
+
if (errors.length === 0 && warnings.length === 0) {
|
|
140
|
+
lines.push("All validations passed.");
|
|
141
|
+
}
|
|
142
|
+
return lines.join("\n");
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=validators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validators.js","sourceRoot":"","sources":["../src/validators.ts"],"names":[],"mappings":"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"}
|