@bytechain.cn/colamd-themes 0.3.1 → 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.
- package/.claude/skills/colamd-themes-preview.skill.md +333 -0
- package/.claude/skills/colamd-themes.skill.md +10 -0
- package/.dsh/skills/colamd-themes/SKILL.md +14 -0
- package/.github/supported-topics.yml +17 -0
- package/.hermes/skills/tools/colamd-themes/SKILL.md +14 -0
- package/.openclaw/skills/colamd-themes/SKILL.md +1 -146
- package/.opencode/skills/colamd-themes/SKILL.md +17 -0
- package/.trae/rules/colamd-themes.md +0 -145
- package/CHANGELOG.md +318 -240
- package/DSH_SUPPORT_SUMMARY.md +87 -0
- package/README.md +414 -384
- package/README_CN.md +412 -384
- package/RELEASENOTE.md +541 -365
- package/bytechain.cn-colamd-themes-0.5.0.tgz +0 -0
- package/dist/cli.js +272 -32
- package/dist/cli.js.map +1 -1
- package/dist/color-utils.d.ts +1 -0
- package/dist/color-utils.js +25 -6
- package/dist/color-utils.js.map +1 -1
- package/dist/extractors/pdf-extractor.js +6 -1
- package/dist/extractors/pdf-extractor.js.map +1 -1
- package/dist/extractors/url-extractor.d.ts +0 -4
- package/dist/extractors/url-extractor.js +13 -126
- package/dist/extractors/url-extractor.js.map +1 -1
- package/dist/generator.d.ts +1 -1
- package/dist/generator.js +32 -11
- package/dist/generator.js.map +1 -1
- package/dist/models.d.ts +5 -4
- package/dist/models.js +2 -3
- package/dist/models.js.map +1 -1
- package/dist/renderer.d.ts +4 -2
- package/dist/renderer.js +68 -25
- package/dist/renderer.js.map +1 -1
- package/dist/templates/template.css +220 -498
- package/dist/templates/theme-paradigm.md +530 -658
- package/dist/templates/theme-template.hbs +256 -370
- package/dist/theme-store.js +19 -3
- package/dist/theme-store.js.map +1 -1
- package/dist/utils/document-paradigm.d.ts +12 -0
- package/dist/utils/document-paradigm.js +109 -0
- package/dist/utils/document-paradigm.js.map +1 -0
- package/dist/validators.d.ts +4 -1
- package/dist/validators.js +115 -1
- package/dist/validators.js.map +1 -1
- package/mcp-server/dist/index.d.ts +13 -0
- package/mcp-server/dist/index.d.ts.map +1 -0
- package/mcp-server/dist/index.js +0 -0
- package/mcp-server/dist/index.js.map +1 -0
- package/mcp-server/package-lock.json +1759 -0
- package/mcp-server/package.json +24 -0
- package/mcp-server/src/index.ts +0 -0
- package/mcp-server/tsconfig.json +19 -0
- package/package.json +54 -36
- package/skills/build-skills.sh +30 -5
- package/skills/colamd-themes/SKILL.md +180 -148
- package/src/cli.ts +474 -217
- package/src/color-systems.ts +289 -289
- package/src/color-utils.ts +137 -120
- package/src/contrast.ts +66 -66
- package/src/docx-style-paradigm.ts +811 -811
- package/src/export-cli.ts +356 -356
- package/src/extractors/base.ts +8 -8
- package/src/extractors/docx-extractor.ts +417 -417
- package/src/extractors/pdf-extractor.ts +533 -527
- package/src/extractors/url-extractor.ts +846 -981
- package/src/generator.ts +197 -169
- package/src/index.ts +29 -29
- package/src/models.ts +212 -212
- package/src/renderer.ts +332 -288
- package/src/templates/template.css +220 -498
- package/src/templates/theme-paradigm.md +530 -658
- package/src/templates/theme-template.hbs +256 -370
- package/src/theme-store.ts +185 -170
- package/src/types/pdf-parse.d.ts +12 -12
- package/src/utils/cli-utils.ts +84 -84
- package/src/utils/document-paradigm.ts +118 -0
- package/src/validators.ts +298 -176
- package/themes/academic-paper-pt.css +353 -1805
- package/themes/academic-paper.css +350 -1099
- package/themes/academic-style.css +342 -2430
- package/themes/colly.css +256 -370
- package/themes/elegant.css +288 -671
- package/themes/forest-ink.css +240 -664
- package/themes/guizang.css +250 -732
- package/themes/hermes-security.css +279 -0
- package/themes/meeting-minutes.css +256 -370
- package/themes/pixso-design.css +278 -1261
- package/themes/salvator-blog.css +256 -370
- package/themes/shimo-theme.css +256 -0
- package/themes/swiss-design.css +285 -746
- package/themes/template.css +220 -498
- package/themes/trae-blue.css +280 -737
- package/themes/word-contract.css +249 -0
- package/themes-preview/demo-content.md +187 -187
- package/tsconfig.json +18 -18
- package/src/mermaid-presets.ts +0 -142
- package/themes/swiss-design copy.css +0 -746
- package/themes-preview/colly-preview.html +0 -623
- package/themes-preview/meeting-minutes-preview.html +0 -625
- package/themes-preview/salvator-blog-preview.html +0 -623
package/src/color-utils.ts
CHANGED
|
@@ -1,120 +1,137 @@
|
|
|
1
|
-
/** Color manipulation utilities. */
|
|
2
|
-
|
|
3
|
-
export function hexToRgb(hex: string): [number, number, number] {
|
|
4
|
-
|
|
5
|
-
if (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
r
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
case
|
|
59
|
-
h = ((
|
|
60
|
-
break;
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
1
|
+
/** Color manipulation utilities. */
|
|
2
|
+
|
|
3
|
+
export function hexToRgb(hex: string): [number, number, number] {
|
|
4
|
+
const trimmed = hex.replace(/^#/, "").trim();
|
|
5
|
+
if (!/^[0-9a-fA-F]{6}$/.test(trimmed) && !/^[0-9a-fA-F]{3}$/.test(trimmed)) {
|
|
6
|
+
throw new Error(`Invalid hex color: "${hex}"`);
|
|
7
|
+
}
|
|
8
|
+
hex = trimmed;
|
|
9
|
+
if (hex.length === 3) hex = hex.split("").map((c) => c + c).join("");
|
|
10
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
11
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
|
12
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
|
13
|
+
if ([r, g, b].some((v) => Number.isNaN(v))) {
|
|
14
|
+
throw new Error(`Invalid hex color: "${hex}"`);
|
|
15
|
+
}
|
|
16
|
+
return [r, g, b];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function rgbToHex(r: number, g: number, b: number): string {
|
|
20
|
+
const clamp = (v: number) => Math.max(0, Math.min(255, Math.round(v)));
|
|
21
|
+
return `#${clamp(r).toString(16).padStart(2, "0")}${clamp(g).toString(16).padStart(2, "0")}${clamp(b).toString(16).padStart(2, "0")}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function lighten(hex: string, factor: number = 0.3): string {
|
|
25
|
+
const [r, g, b] = hexToRgb(hex);
|
|
26
|
+
return rgbToHex(
|
|
27
|
+
r + (255 - r) * factor,
|
|
28
|
+
g + (255 - g) * factor,
|
|
29
|
+
b + (255 - b) * factor
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function darken(hex: string, factor: number = 0.15): string {
|
|
34
|
+
const [r, g, b] = hexToRgb(hex);
|
|
35
|
+
return rgbToHex(r * (1 - factor), g * (1 - factor), b * (1 - factor));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function toRgba(hex: string, alpha: number = 0.18): string {
|
|
39
|
+
const [r, g, b] = hexToRgb(hex);
|
|
40
|
+
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function rgbToHsl(
|
|
44
|
+
r: number, g: number, b: number
|
|
45
|
+
): [number, number, number] {
|
|
46
|
+
r /= 255; g /= 255; b /= 255;
|
|
47
|
+
const max = Math.max(r, g, b);
|
|
48
|
+
const min = Math.min(r, g, b);
|
|
49
|
+
let h = 0, s: number;
|
|
50
|
+
const l = (max + min) / 2;
|
|
51
|
+
|
|
52
|
+
if (max === min) {
|
|
53
|
+
h = s = 0;
|
|
54
|
+
} else {
|
|
55
|
+
const d = max - min;
|
|
56
|
+
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
57
|
+
switch (max) {
|
|
58
|
+
case r:
|
|
59
|
+
h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
|
|
60
|
+
break;
|
|
61
|
+
case g:
|
|
62
|
+
h = ((b - r) / d + 2) / 6;
|
|
63
|
+
break;
|
|
64
|
+
case b:
|
|
65
|
+
h = ((r - g) / d + 4) / 6;
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return [h, s, l];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function deriveSyntaxColors(
|
|
73
|
+
baseHex: string
|
|
74
|
+
): Record<string, string> {
|
|
75
|
+
const [r, g, b] = hexToRgb(baseHex);
|
|
76
|
+
const [, , l] = rgbToHsl(r, g, b);
|
|
77
|
+
const isDark = l < 0.5;
|
|
78
|
+
|
|
79
|
+
if (isDark) {
|
|
80
|
+
return {
|
|
81
|
+
comment: lighten(baseHex, 0.4),
|
|
82
|
+
punctuation: lighten(baseHex, 0.2),
|
|
83
|
+
keyword: "#569cd6",
|
|
84
|
+
booleanBuiltinTag: "#569cd6",
|
|
85
|
+
string: "#ce9178",
|
|
86
|
+
number: "#b5cea8",
|
|
87
|
+
functionClass: "#dcdcaa",
|
|
88
|
+
operator: lighten(baseHex, 0.2),
|
|
89
|
+
variable: lighten(baseHex, 0.2),
|
|
90
|
+
regex: "#d16969",
|
|
91
|
+
};
|
|
92
|
+
} else {
|
|
93
|
+
return {
|
|
94
|
+
comment: darken(baseHex, 0.4),
|
|
95
|
+
punctuation: baseHex,
|
|
96
|
+
keyword: "#0000ff",
|
|
97
|
+
booleanBuiltinTag: "#0000ff",
|
|
98
|
+
string: "#a31515",
|
|
99
|
+
number: "#098658",
|
|
100
|
+
functionClass: "#795e26",
|
|
101
|
+
operator: baseHex,
|
|
102
|
+
variable: baseHex,
|
|
103
|
+
regex: "#811f3f",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function sanitizeCssString(value: string): string {
|
|
109
|
+
// Remove HTML-injection vectors while preserving CSS syntax (quotes, spaces, commas)
|
|
110
|
+
return value.replace(/[<>]/g, "");
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function normalizeThemeStyle(style: import("./models.js").ThemeStyle): void {
|
|
114
|
+
const p = style.palette;
|
|
115
|
+
const t = style.typography;
|
|
116
|
+
const s = style.syntax;
|
|
117
|
+
|
|
118
|
+
if (!p.headingColor) p.headingColor = p.textColor;
|
|
119
|
+
if (!p.codeColor) p.codeColor = p.textColor;
|
|
120
|
+
if (!p.blockquoteBorder) p.blockquoteBorder = p.accentColor;
|
|
121
|
+
if (!p.selectionBg) p.selectionBg = toRgba(p.accentColor);
|
|
122
|
+
if (!t.headingFontFamily) t.headingFontFamily = t.bodyFontFamily;
|
|
123
|
+
|
|
124
|
+
// Sanitize font stacks to prevent CSS injection via crafted input
|
|
125
|
+
if (t.bodyFontFamily) t.bodyFontFamily = sanitizeCssString(t.bodyFontFamily);
|
|
126
|
+
if (t.headingFontFamily) t.headingFontFamily = sanitizeCssString(t.headingFontFamily);
|
|
127
|
+
if (t.codeFontFamily) t.codeFontFamily = sanitizeCssString(t.codeFontFamily);
|
|
128
|
+
if (style.seedTypography.fontMermaid) style.seedTypography.fontMermaid = sanitizeCssString(style.seedTypography.fontMermaid);
|
|
129
|
+
|
|
130
|
+
if (!s.comment) {
|
|
131
|
+
const derived = deriveSyntaxColors(p.codeBlockText);
|
|
132
|
+
for (const [key, value] of Object.entries(derived)) {
|
|
133
|
+
const k = key as keyof typeof s;
|
|
134
|
+
if (!s[k]) (s as unknown as Record<string, string>)[key] = value;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/contrast.ts
CHANGED
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
/** WCAG 2.1 relative luminance and contrast ratio calculations. */
|
|
2
|
-
|
|
3
|
-
import { hexToRgb } from "./color-utils.js";
|
|
4
|
-
|
|
5
|
-
/** Linearize an sRGB channel value (0-255) → (0-1). */
|
|
6
|
-
function linearize(channel: number): number {
|
|
7
|
-
const c = channel / 255;
|
|
8
|
-
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** WCAG 2.1 relative luminance of a hex color. */
|
|
12
|
-
export function relativeLuminance(hex: string): number {
|
|
13
|
-
const [r, g, b] = hexToRgb(hex);
|
|
14
|
-
return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** WCAG 2.1 contrast ratio between two hex colors. Range: 1-21. */
|
|
18
|
-
export function contrastRatio(hex1: string, hex2: string): number {
|
|
19
|
-
const L1 = relativeLuminance(hex1);
|
|
20
|
-
const L2 = relativeLuminance(hex2);
|
|
21
|
-
const lighter = Math.max(L1, L2);
|
|
22
|
-
const darker = Math.min(L1, L2);
|
|
23
|
-
return (lighter + 0.05) / (darker + 0.05);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/** Get HSL lightness (0-1) from a hex color. */
|
|
27
|
-
export function hslLightness(hex: string): number {
|
|
28
|
-
const [r, g, b] = hexToRgb(hex);
|
|
29
|
-
const max = Math.max(r, g, b) / 255;
|
|
30
|
-
const min = Math.min(r, g, b) / 255;
|
|
31
|
-
return (max + min) / 2;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/** Get HSL saturation (0-1) from a hex color. */
|
|
35
|
-
export function hslSaturation(hex: string): number {
|
|
36
|
-
const [r, g, b] = hexToRgb(hex);
|
|
37
|
-
const max = Math.max(r, g, b) / 255;
|
|
38
|
-
const min = Math.min(r, g, b) / 255;
|
|
39
|
-
const l = (max + min) / 2;
|
|
40
|
-
if (max === min) return 0;
|
|
41
|
-
return l > 0.5 ? (max - min) / (2 - max - min) : (max - min) / (max + min);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Get HSL hue (0-360) from a hex color. */
|
|
45
|
-
export function hslHue(hex: string): number {
|
|
46
|
-
const [r, g, b] = hexToRgb(hex);
|
|
47
|
-
const max = Math.max(r, g, b);
|
|
48
|
-
const min = Math.min(r, g, b);
|
|
49
|
-
if (max === min) return 0;
|
|
50
|
-
const d = max - min;
|
|
51
|
-
let h = 0;
|
|
52
|
-
if (max === r) h = ((g - b) / d) % 6;
|
|
53
|
-
else if (max === g) h = (b - r) / d + 2;
|
|
54
|
-
else h = (r - g) / d + 4;
|
|
55
|
-
return Math.round(h * 60);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Check if two colors are on the same hue axis (within tolerance degrees). */
|
|
59
|
-
export function sameHueAxis(h1: string, h2: string, tolerance: number = 5): boolean {
|
|
60
|
-
return Math.abs(hslHue(h1) - hslHue(h2)) <= tolerance;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Determine if a palette is light mode (bg luminance > 0.5). */
|
|
64
|
-
export function isLightMode(bgHex: string): boolean {
|
|
65
|
-
return hslLightness(bgHex) > 0.5;
|
|
66
|
-
}
|
|
1
|
+
/** WCAG 2.1 relative luminance and contrast ratio calculations. */
|
|
2
|
+
|
|
3
|
+
import { hexToRgb } from "./color-utils.js";
|
|
4
|
+
|
|
5
|
+
/** Linearize an sRGB channel value (0-255) → (0-1). */
|
|
6
|
+
function linearize(channel: number): number {
|
|
7
|
+
const c = channel / 255;
|
|
8
|
+
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** WCAG 2.1 relative luminance of a hex color. */
|
|
12
|
+
export function relativeLuminance(hex: string): number {
|
|
13
|
+
const [r, g, b] = hexToRgb(hex);
|
|
14
|
+
return 0.2126 * linearize(r) + 0.7152 * linearize(g) + 0.0722 * linearize(b);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** WCAG 2.1 contrast ratio between two hex colors. Range: 1-21. */
|
|
18
|
+
export function contrastRatio(hex1: string, hex2: string): number {
|
|
19
|
+
const L1 = relativeLuminance(hex1);
|
|
20
|
+
const L2 = relativeLuminance(hex2);
|
|
21
|
+
const lighter = Math.max(L1, L2);
|
|
22
|
+
const darker = Math.min(L1, L2);
|
|
23
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Get HSL lightness (0-1) from a hex color. */
|
|
27
|
+
export function hslLightness(hex: string): number {
|
|
28
|
+
const [r, g, b] = hexToRgb(hex);
|
|
29
|
+
const max = Math.max(r, g, b) / 255;
|
|
30
|
+
const min = Math.min(r, g, b) / 255;
|
|
31
|
+
return (max + min) / 2;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Get HSL saturation (0-1) from a hex color. */
|
|
35
|
+
export function hslSaturation(hex: string): number {
|
|
36
|
+
const [r, g, b] = hexToRgb(hex);
|
|
37
|
+
const max = Math.max(r, g, b) / 255;
|
|
38
|
+
const min = Math.min(r, g, b) / 255;
|
|
39
|
+
const l = (max + min) / 2;
|
|
40
|
+
if (max === min) return 0;
|
|
41
|
+
return l > 0.5 ? (max - min) / (2 - max - min) : (max - min) / (max + min);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Get HSL hue (0-360) from a hex color. */
|
|
45
|
+
export function hslHue(hex: string): number {
|
|
46
|
+
const [r, g, b] = hexToRgb(hex);
|
|
47
|
+
const max = Math.max(r, g, b);
|
|
48
|
+
const min = Math.min(r, g, b);
|
|
49
|
+
if (max === min) return 0;
|
|
50
|
+
const d = max - min;
|
|
51
|
+
let h = 0;
|
|
52
|
+
if (max === r) h = ((g - b) / d) % 6;
|
|
53
|
+
else if (max === g) h = (b - r) / d + 2;
|
|
54
|
+
else h = (r - g) / d + 4;
|
|
55
|
+
return Math.round(h * 60);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Check if two colors are on the same hue axis (within tolerance degrees). */
|
|
59
|
+
export function sameHueAxis(h1: string, h2: string, tolerance: number = 5): boolean {
|
|
60
|
+
return Math.abs(hslHue(h1) - hslHue(h2)) <= tolerance;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Determine if a palette is light mode (bg luminance > 0.5). */
|
|
64
|
+
export function isLightMode(bgHex: string): boolean {
|
|
65
|
+
return hslLightness(bgHex) > 0.5;
|
|
66
|
+
}
|