@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
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bytechain.cn/colamd-themes",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Theme development & export tool for ColaMD — extract formatting, generate themes, and export Markdown to HTML/PDF",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"colamd-themes": "./dist/cli.js",
|
|
9
|
+
"cthemes": "./dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc && node --input-type=commonjs -e \"require('fs').cpSync('src/templates','dist/templates',{recursive:true})\"",
|
|
13
|
+
"build:skills": "bash skills/build-skills.sh",
|
|
14
|
+
"dev": "tsx src/cli.ts",
|
|
15
|
+
"start": "node dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@bytechain.cn/colamd": "^1.5.2",
|
|
19
|
+
"axios": "^1.7",
|
|
20
|
+
"chalk": "^5.3",
|
|
21
|
+
"cheerio": "^1.0",
|
|
22
|
+
"commander": "^12.0",
|
|
23
|
+
"css-tree": "^3.0",
|
|
24
|
+
"handlebars": "^4.7",
|
|
25
|
+
"mammoth": "^1.8",
|
|
26
|
+
"ora": "^8.0",
|
|
27
|
+
"pdf-parse": "^1.1",
|
|
28
|
+
"puppeteer": "^24.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/css-tree": "^2.3",
|
|
32
|
+
"@types/node": "^22.0",
|
|
33
|
+
"tsx": "^4.0",
|
|
34
|
+
"typescript": "^5.5"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Build agent-specific skill files from the canonical source.
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# bash skills/build-skills.sh # generate all
|
|
7
|
+
# bash skills/build-skills.sh claude # generate for one agent
|
|
8
|
+
#
|
|
9
|
+
# Source: skills/colamd-themes/SKILL.md
|
|
10
|
+
# Output: .{agent}/skills/colamd-themes/SKILL.md (or equivalent)
|
|
11
|
+
|
|
12
|
+
set -euo pipefail
|
|
13
|
+
cd "$(dirname "$0")/.."
|
|
14
|
+
|
|
15
|
+
SOURCE="skills/colamd-themes/SKILL.md"
|
|
16
|
+
if [[ ! -f "$SOURCE" ]]; then
|
|
17
|
+
echo "Error: Source skill not found: $SOURCE" >&2
|
|
18
|
+
exit 1
|
|
19
|
+
fi
|
|
20
|
+
|
|
21
|
+
# Read the body (everything after the first blank line following the heading)
|
|
22
|
+
BODY=$(sed -n '/^$/,$ { /^# ColaMD/!p; }' "$SOURCE" | sed '1{/^$/d;}')
|
|
23
|
+
|
|
24
|
+
# ── Frontmatter templates ──
|
|
25
|
+
|
|
26
|
+
FRONT_CLAUDE='---
|
|
27
|
+
name: colamd-themes
|
|
28
|
+
description: >
|
|
29
|
+
Generate, validate, export, and manage ColaMD v3.0 paradigm CSS themes.
|
|
30
|
+
Extract formatting from URLs, DOCX, or PDF sources; export Markdown to
|
|
31
|
+
standalone HTML/PDF with themes applied; batch export; manage theme
|
|
32
|
+
configuration.
|
|
33
|
+
---'
|
|
34
|
+
|
|
35
|
+
FRONT_OPENCODE='---
|
|
36
|
+
name: colamd-themes
|
|
37
|
+
version: "1.0.0"
|
|
38
|
+
description: >
|
|
39
|
+
Generate, validate, export, and manage ColaMD v3.0 paradigm CSS themes.
|
|
40
|
+
Extract from URLs/DOCX/PDF; export Markdown to HTML/PDF; batch export.
|
|
41
|
+
user-invocable: true
|
|
42
|
+
allowed-tools:
|
|
43
|
+
- Read
|
|
44
|
+
- Write
|
|
45
|
+
- Edit
|
|
46
|
+
- Bash
|
|
47
|
+
- Glob
|
|
48
|
+
- Grep
|
|
49
|
+
---'
|
|
50
|
+
|
|
51
|
+
FRONT_OPENCLAW='---
|
|
52
|
+
id: colamd-themes
|
|
53
|
+
name: ColaMD Themes
|
|
54
|
+
description: >
|
|
55
|
+
Generate, validate, export, and manage ColaMD v3.0 paradigm CSS themes.
|
|
56
|
+
Extract from URLs/DOCX/PDF; export Markdown to HTML/PDF; batch export.
|
|
57
|
+
version: "1.0.0"
|
|
58
|
+
icon: "\U0001F3A8"
|
|
59
|
+
author: bytechain
|
|
60
|
+
homepage: https://github.com/byteuser1977/ColaMD-themes
|
|
61
|
+
user-invocable: true
|
|
62
|
+
metadata:
|
|
63
|
+
openclaw:
|
|
64
|
+
os: [darwin, linux, win32]
|
|
65
|
+
clawdbot:
|
|
66
|
+
emoji: "\U0001F3A8"
|
|
67
|
+
requires:
|
|
68
|
+
bins: [node, npm]
|
|
69
|
+
---'
|
|
70
|
+
|
|
71
|
+
FRONT_HERMES='---
|
|
72
|
+
name: colamd-themes
|
|
73
|
+
description: "Generate, validate, export, and manage ColaMD v3.0 paradigm CSS themes."
|
|
74
|
+
version: 1.0.0
|
|
75
|
+
author: bytechain
|
|
76
|
+
license: MIT
|
|
77
|
+
metadata:
|
|
78
|
+
hermes:
|
|
79
|
+
tags: [colamd, themes, css, markdown, export, pdf, html]
|
|
80
|
+
prerequisites:
|
|
81
|
+
commands: [node, npm]
|
|
82
|
+
---'
|
|
83
|
+
|
|
84
|
+
# ── Generator functions ──
|
|
85
|
+
|
|
86
|
+
generate_claude() {
|
|
87
|
+
local dir=".claude/skills"
|
|
88
|
+
mkdir -p "$dir"
|
|
89
|
+
local file="$dir/colamd-themes.skill.md"
|
|
90
|
+
echo "$FRONT_CLAUDE" > "$file"
|
|
91
|
+
echo "" >> "$file"
|
|
92
|
+
echo "$BODY" >> "$file"
|
|
93
|
+
echo " → $file"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
generate_opencode() {
|
|
97
|
+
local dir=".opencode/skills/colamd-themes"
|
|
98
|
+
mkdir -p "$dir"
|
|
99
|
+
local file="$dir/SKILL.md"
|
|
100
|
+
echo "$FRONT_OPENCODE" > "$file"
|
|
101
|
+
echo "" >> "$file"
|
|
102
|
+
echo "$BODY" >> "$file"
|
|
103
|
+
echo " → $file"
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
generate_openclaw() {
|
|
107
|
+
local dir=".openclaw/skills/colamd-themes"
|
|
108
|
+
mkdir -p "$dir"
|
|
109
|
+
local file="$dir/SKILL.md"
|
|
110
|
+
echo "$FRONT_OPENCLAW" > "$file"
|
|
111
|
+
echo "" >> "$file"
|
|
112
|
+
echo "$BODY" >> "$file"
|
|
113
|
+
echo " → $file"
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
generate_hermes() {
|
|
117
|
+
local dir=".hermes/skills/tools/colamd-themes"
|
|
118
|
+
mkdir -p "$dir"
|
|
119
|
+
local file="$dir/SKILL.md"
|
|
120
|
+
echo "$FRONT_HERMES" > "$file"
|
|
121
|
+
echo "" >> "$file"
|
|
122
|
+
echo "$BODY" >> "$file"
|
|
123
|
+
echo " → $file"
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
generate_trae() {
|
|
127
|
+
local dir=".trae/rules"
|
|
128
|
+
mkdir -p "$dir"
|
|
129
|
+
local file="$dir/colamd-themes.md"
|
|
130
|
+
# Trae uses plain Markdown, no YAML frontmatter
|
|
131
|
+
echo "# ColaMD Themes Skill Instructions" > "$file"
|
|
132
|
+
echo "" >> "$file"
|
|
133
|
+
echo "When the user asks to create, validate, export, or manage ColaMD themes, use the following CLI tool:" >> "$file"
|
|
134
|
+
echo "" >> "$file"
|
|
135
|
+
echo "$BODY" >> "$file"
|
|
136
|
+
echo " → $file"
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# ── Main ──
|
|
140
|
+
|
|
141
|
+
TARGET="${1:-all}"
|
|
142
|
+
echo "Building skill files from: $SOURCE"
|
|
143
|
+
echo ""
|
|
144
|
+
|
|
145
|
+
case "$TARGET" in
|
|
146
|
+
claude) generate_claude ;;
|
|
147
|
+
opencode) generate_opencode ;;
|
|
148
|
+
openclaw) generate_openclaw ;;
|
|
149
|
+
hermes) generate_hermes ;;
|
|
150
|
+
trae) generate_trae ;;
|
|
151
|
+
all)
|
|
152
|
+
generate_claude
|
|
153
|
+
generate_opencode
|
|
154
|
+
generate_openclaw
|
|
155
|
+
generate_hermes
|
|
156
|
+
generate_trae
|
|
157
|
+
;;
|
|
158
|
+
*)
|
|
159
|
+
echo "Unknown agent: $TARGET" >&2
|
|
160
|
+
echo "Usage: $0 [claude|opencode|openclaw|hermes|trae|all]" >&2
|
|
161
|
+
exit 1
|
|
162
|
+
;;
|
|
163
|
+
esac
|
|
164
|
+
|
|
165
|
+
echo ""
|
|
166
|
+
echo "Done. Skill files generated."
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# ColaMD Themes — Universal AI Agent Skill
|
|
2
|
+
|
|
3
|
+
Generate, validate, export, and manage ColaMD v3.0 paradigm CSS themes. Extract formatting from URLs, DOCX, or PDF sources; export Markdown to standalone HTML/PDF with themes applied; batch export; manage theme configuration.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js ≥ 18
|
|
8
|
+
- Project root: run `npm install && npm run build` before first use
|
|
9
|
+
- Or run directly: `npx tsx src/cli.ts <command>`
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### Theme extraction
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
colamd-themes from-url <URL> [options]
|
|
17
|
+
colamd-themes from-docx <file> [options]
|
|
18
|
+
colamd-themes from-pdf <file> [options]
|
|
19
|
+
colamd-themes extract <source> [options]
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Export to HTML / PDF
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
colamd-themes export-html <input.md> -t <theme> -o <output.html>
|
|
26
|
+
colamd-themes export-pdf <input.md> -t <theme> -o <output.pdf>
|
|
27
|
+
colamd-themes export <inputs...> --format html|pdf -t <theme> -d <dir>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Theme management
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
colamd-themes set-theme <name> --default
|
|
34
|
+
colamd-themes set-theme <name> --css <file>
|
|
35
|
+
colamd-themes set-theme <name> --css <file> --default
|
|
36
|
+
colamd-themes set-theme <name> --remove
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Inspection
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
colamd-themes color-systems [-j]
|
|
43
|
+
colamd-themes mermaid-presets [-j]
|
|
44
|
+
colamd-themes list [-d <dir>]
|
|
45
|
+
colamd-themes validate <file.css>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Options
|
|
49
|
+
|
|
50
|
+
### Extract options
|
|
51
|
+
|
|
52
|
+
| Flag | Description |
|
|
53
|
+
|------|-------------|
|
|
54
|
+
| `-n, --name` | Theme name |
|
|
55
|
+
| `-o, --output` | Output CSS file path |
|
|
56
|
+
| `-d, --themes-dir` | Themes directory (default: `themes/`) |
|
|
57
|
+
| `-c, --color-system` | Force a color system |
|
|
58
|
+
| `-m, --mermaid-preset` | Force a Mermaid preset (light/dark/elegant) |
|
|
59
|
+
| `-A, --auto-match` | Auto-match color system and Mermaid preset |
|
|
60
|
+
|
|
61
|
+
### Export options
|
|
62
|
+
|
|
63
|
+
| Flag | Description |
|
|
64
|
+
|------|-------------|
|
|
65
|
+
| `-t, --theme` | Theme: built-in name, custom name, or `.css` file path |
|
|
66
|
+
| `-o, --output` | Output file path |
|
|
67
|
+
| `-d, --output-dir` | Output directory for batch export |
|
|
68
|
+
| `--format` | Batch: `html` or `pdf`; PDF: `A4`, `Letter`, `A3` |
|
|
69
|
+
|
|
70
|
+
## Theme Resolution
|
|
71
|
+
|
|
72
|
+
`-t, --theme` accepts:
|
|
73
|
+
1. **Built-in**: `light`, `dark`, `elegant`, `newsprint`
|
|
74
|
+
2. **Custom registered**: name set via `set-theme --css`
|
|
75
|
+
3. **File path**: any `.css` file on disk
|
|
76
|
+
|
|
77
|
+
Config: `~/.colamd-themes/config.json`
|
|
78
|
+
|
|
79
|
+
## Color Systems (15 schemes)
|
|
80
|
+
|
|
81
|
+
| Family | Schemes |
|
|
82
|
+
|--------|---------|
|
|
83
|
+
| 莫兰迪 (Morandi) | misty-rose, sage-green, dusky-blue |
|
|
84
|
+
| 马卡龙 (Macaron) | strawberry, mint, lavender |
|
|
85
|
+
| 北欧 (Nordic) | fjord-blue, pine-green, cloud-grey |
|
|
86
|
+
| 复古 (Vintage) | amber, burgundy, forest |
|
|
87
|
+
| 薄荷绿 (Mint) | matcha, spearmint, seafoam |
|
|
88
|
+
|
|
89
|
+
## Mermaid Presets
|
|
90
|
+
|
|
91
|
+
`light` — cool accent on light bg | `dark` — dark bg | `elegant` — warm accent on light bg
|
|
92
|
+
|
|
93
|
+
## Workflow Examples
|
|
94
|
+
|
|
95
|
+
### Create theme from source
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
colamd-themes extract <source> --name "my-theme" --auto-match
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Export with theme
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
colamd-themes export-html doc.md -t elegant -o output.html
|
|
105
|
+
colamd-themes export-pdf doc.md -t my-brand -o output.pdf
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Batch export
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
colamd-themes export docs/ --format pdf -t dark -d output/
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Validate theme
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
colamd-themes validate themes/my-theme.css
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Rendering Pipeline
|
|
121
|
+
|
|
122
|
+
Export uses Puppeteer (headless Chromium) with `@bytechain.cn/colamd/renderer`:
|
|
123
|
+
|
|
124
|
+
1. Local HTTP server serves renderer ESM bundle (avoids CORS)
|
|
125
|
+
2. Puppeteer navigates to server page (same-origin)
|
|
126
|
+
3. `createColaMDEditor({ editable: false })` initializes Milkdown editor
|
|
127
|
+
4. `applyTheme(name, customCSS?)` sets theme
|
|
128
|
+
5. `setMarkdown(content)` loads document
|
|
129
|
+
6. `ensureAllPluginsRendered()` waits for mermaid/KaTeX
|
|
130
|
+
7. `buildExportHTML()` → standalone HTML with embedded CSS
|
|
131
|
+
8. For PDF: `emulateMediaType('screen')` + `page.pdf()`
|
|
132
|
+
|
|
133
|
+
## v3.0 Paradigm Constraints
|
|
134
|
+
|
|
135
|
+
- No bare hex colors in selectors — use `var(--seed-*)`
|
|
136
|
+
- No bare font sizes — use `var(--font-*)`
|
|
137
|
+
- No Mermaid SVG selectors (handled by built-in `variables.css`)
|
|
138
|
+
- `!important` only in `@media print`
|
|
139
|
+
- Generated CSS ≤ 300 lines
|
|
140
|
+
- Font stacks must include CJK fallback and end with generic family
|
|
141
|
+
|
|
142
|
+
## Architecture
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
Source → Extractor → ThemeStyle → Color System + Mermaid Preset + Validators → CSS
|
|
146
|
+
|
|
147
|
+
Markdown → Puppeteer + ColaMD Renderer → HTML / PDF
|
|
148
|
+
```
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
5
|
+
import { join, isAbsolute } from "node:path";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import ora from "ora";
|
|
8
|
+
import { UrlExtractor } from "./extractors/url-extractor.js";
|
|
9
|
+
import { DocxExtractor } from "./extractors/docx-extractor.js";
|
|
10
|
+
import { PdfExtractor } from "./extractors/pdf-extractor.js";
|
|
11
|
+
import type { Extractor } from "./extractors/base.js";
|
|
12
|
+
import { writeThemeFile } from "./generator.js";
|
|
13
|
+
import { COLOR_SYSTEMS, getColorSystem } from "./color-systems.js";
|
|
14
|
+
import { MERMAID_PRESETS } from "./mermaid-presets.js";
|
|
15
|
+
import { validateSeedPalette, summarizeIssues } from "./validators.js";
|
|
16
|
+
import type { ThemeStyle } from "./models.js";
|
|
17
|
+
import { registerExportCommands } from "./export-cli.js";
|
|
18
|
+
|
|
19
|
+
const program = new Command();
|
|
20
|
+
|
|
21
|
+
program
|
|
22
|
+
.name("colamd-themes")
|
|
23
|
+
.description("ColaMD Theme Development Tool — extract formatting and generate v3.0 paradigm CSS themes")
|
|
24
|
+
.version("0.2.0");
|
|
25
|
+
|
|
26
|
+
// ── Shared extract options builder ──
|
|
27
|
+
|
|
28
|
+
function addExtractOptions(cmd: Command): Command {
|
|
29
|
+
return cmd
|
|
30
|
+
.option("-n, --name <name>", "Theme name")
|
|
31
|
+
.option("-o, --output <path>", "Output CSS file path")
|
|
32
|
+
.option("-d, --themes-dir <dir>", "Themes directory", "themes")
|
|
33
|
+
.option("-c, --color-system <id>", "Force a color system (use `color-systems` to list)")
|
|
34
|
+
.option("-m, --mermaid-preset <id>", "Force a Mermaid preset (light/dark/elegant)")
|
|
35
|
+
.option("-A, --auto-match", "Auto-match color system and mermaid preset");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function runExtraction(
|
|
39
|
+
extractor: Extractor,
|
|
40
|
+
source: string,
|
|
41
|
+
options: Record<string, string>
|
|
42
|
+
) {
|
|
43
|
+
const spinner = ora("Extracting styles...").start();
|
|
44
|
+
try {
|
|
45
|
+
const style = await extractor.extract(source);
|
|
46
|
+
if (options.name) style.name = options.name;
|
|
47
|
+
if (options.colorSystem) {
|
|
48
|
+
const cs = getColorSystem(options.colorSystem);
|
|
49
|
+
if (!cs) { spinner.fail(`Unknown color system: ${options.colorSystem}`); process.exit(1); }
|
|
50
|
+
style.seed = { ...cs.palette };
|
|
51
|
+
style.colorSystemId = cs.id;
|
|
52
|
+
}
|
|
53
|
+
if (options.mermaidPreset) style.mermaidPresetId = options.mermaidPreset;
|
|
54
|
+
if (options.autoMatch) { style.colorSystemId = ""; style.mermaidPresetId = ""; }
|
|
55
|
+
spinner.text = "Generating CSS (v3.0 paradigm)...";
|
|
56
|
+
const outputPath = writeThemeFile(style, options.output || options.themesDir);
|
|
57
|
+
spinner.succeed(chalk.green(`Theme "${style.name}" generated: ${outputPath}`));
|
|
58
|
+
printSummary(style);
|
|
59
|
+
} catch (err) {
|
|
60
|
+
spinner.fail(chalk.red(`Failed: ${(err as Error).message}`));
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ── from-url ──
|
|
66
|
+
addExtractOptions(
|
|
67
|
+
program.command("from-url")
|
|
68
|
+
.description("Extract theme from a web page URL")
|
|
69
|
+
.argument("<url>", "URL of the web page")
|
|
70
|
+
).action(async (url: string, options: Record<string, string>) => {
|
|
71
|
+
await runExtraction(new UrlExtractor(), url, options);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// ── from-docx ──
|
|
75
|
+
addExtractOptions(
|
|
76
|
+
program.command("from-docx")
|
|
77
|
+
.description("Extract theme from a .docx document")
|
|
78
|
+
.argument("<file>", "Path to the .docx file")
|
|
79
|
+
).action(async (file: string, options: Record<string, string>) => {
|
|
80
|
+
if (!existsSync(file)) { console.error(chalk.red(`File not found: ${file}`)); process.exit(1); }
|
|
81
|
+
await runExtraction(new DocxExtractor(), file, options);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// ── from-pdf ──
|
|
85
|
+
addExtractOptions(
|
|
86
|
+
program.command("from-pdf")
|
|
87
|
+
.description("Extract theme from a PDF document")
|
|
88
|
+
.argument("<file>", "Path to the PDF file")
|
|
89
|
+
).action(async (file: string, options: Record<string, string>) => {
|
|
90
|
+
if (!existsSync(file)) { console.error(chalk.red(`File not found: ${file}`)); process.exit(1); }
|
|
91
|
+
await runExtraction(new PdfExtractor(), file, options);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// ── extract (auto-detect) ──
|
|
95
|
+
addExtractOptions(
|
|
96
|
+
program.command("extract")
|
|
97
|
+
.description("Auto-detect source type and extract theme")
|
|
98
|
+
.argument("<source>", "URL, .docx file, or .pdf file")
|
|
99
|
+
).action(async (source: string, options: Record<string, string>) => {
|
|
100
|
+
const extractors: Extractor[] = [new UrlExtractor(), new DocxExtractor(), new PdfExtractor()];
|
|
101
|
+
const ext = extractors.find((e) => e.canHandle(source));
|
|
102
|
+
if (!ext) { console.error(chalk.red(`Cannot detect source type for: ${source}`)); process.exit(1); }
|
|
103
|
+
await runExtraction(ext, source, options);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// ── color-systems ──
|
|
107
|
+
program
|
|
108
|
+
.command("color-systems")
|
|
109
|
+
.description("List all 15 built-in color systems")
|
|
110
|
+
.option("-j, --json", "Output as JSON")
|
|
111
|
+
.action((options: Record<string, string>) => {
|
|
112
|
+
if (options.json) { console.log(JSON.stringify(COLOR_SYSTEMS, null, 2)); return; }
|
|
113
|
+
const families: Record<string, typeof COLOR_SYSTEMS> = {};
|
|
114
|
+
for (const cs of COLOR_SYSTEMS) {
|
|
115
|
+
const fam = cs.nameCN.split(" ")[0];
|
|
116
|
+
(families[fam] ??= []).push(cs);
|
|
117
|
+
}
|
|
118
|
+
for (const [fam, systems] of Object.entries(families)) {
|
|
119
|
+
console.log(chalk.bold(`\n${fam}`));
|
|
120
|
+
for (const cs of systems) {
|
|
121
|
+
console.log(` ${chalk.cyan(cs.id.padEnd(24))} ${chalk.white(cs.nameCN.split(" ").slice(1).join(" "))} ${chalk.dim(cs.palette.accent)}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
console.log();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// ── mermaid-presets ──
|
|
128
|
+
program
|
|
129
|
+
.command("mermaid-presets")
|
|
130
|
+
.description("List Mermaid theme presets (light / dark / elegant)")
|
|
131
|
+
.option("-j, --json", "Output as JSON")
|
|
132
|
+
.action((options: Record<string, string>) => {
|
|
133
|
+
if (options.json) { console.log(JSON.stringify(MERMAID_PRESETS, null, 2)); return; }
|
|
134
|
+
for (const p of MERMAID_PRESETS) {
|
|
135
|
+
console.log(` ${chalk.cyan(p.id.padEnd(12))} ${chalk.white(p.name)} ${chalk.dim(p.description)}`);
|
|
136
|
+
}
|
|
137
|
+
console.log();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// ── list ──
|
|
141
|
+
program
|
|
142
|
+
.command("list")
|
|
143
|
+
.description("List all generated themes")
|
|
144
|
+
.option("-d, --themes-dir <dir>", "Themes directory", "themes")
|
|
145
|
+
.action((options: Record<string, string>) => {
|
|
146
|
+
const dirPath = isAbsolute(options.themesDir) ? options.themesDir : join(process.cwd(), options.themesDir);
|
|
147
|
+
if (!existsSync(dirPath)) { console.log(chalk.yellow(`No themes directory: ${dirPath}`)); return; }
|
|
148
|
+
const files = readdirSync(dirPath).filter((f) => f.endsWith(".css"));
|
|
149
|
+
if (files.length === 0) { console.log(chalk.yellow("No themes found.")); return; }
|
|
150
|
+
console.log(chalk.bold(`\nThemes in ${dirPath}/:`));
|
|
151
|
+
for (const f of files) console.log(` ${chalk.cyan("●")} ${chalk.white(f.replace(".css", ""))}`);
|
|
152
|
+
console.log(`\n${files.length} theme(s) total.\n`);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
// ── validate ──
|
|
156
|
+
program
|
|
157
|
+
.command("validate")
|
|
158
|
+
.description("Validate a theme CSS against v3.0 paradigm rules")
|
|
159
|
+
.argument("<file>", "Path to theme CSS file")
|
|
160
|
+
.action((file: string) => {
|
|
161
|
+
if (!existsSync(file)) { console.error(chalk.red(`File not found: ${file}`)); process.exit(1); }
|
|
162
|
+
const css = readFileSync(file, "utf-8");
|
|
163
|
+
const extract = (name: string) => {
|
|
164
|
+
const m = css.match(new RegExp(`${name}:\\s*([^;]+);`));
|
|
165
|
+
return m ? m[1].trim() : "";
|
|
166
|
+
};
|
|
167
|
+
const seed = {
|
|
168
|
+
accent: extract("--seed-accent"), accentLight: extract("--seed-accent-light"),
|
|
169
|
+
accentDark: extract("--seed-accent-dark"), surface: extract("--seed-surface"),
|
|
170
|
+
panel: extract("--seed-panel"), panelAlt: extract("--seed-panel-alt"),
|
|
171
|
+
ink: extract("--seed-ink"), inkMuted: extract("--seed-ink-muted"),
|
|
172
|
+
inkDim: extract("--seed-ink-dim"), border: extract("--seed-border"),
|
|
173
|
+
borderStrong: extract("--seed-border-strong"),
|
|
174
|
+
};
|
|
175
|
+
if (!seed.accent) { console.error(chalk.yellow("Not a v3.0 paradigm theme (no seed palette found).")); process.exit(0); }
|
|
176
|
+
console.log(chalk.bold("Seed palette:"));
|
|
177
|
+
for (const [k, v] of Object.entries(seed)) console.log(` ${chalk.dim(k.padEnd(18))} ${v}`);
|
|
178
|
+
const issues = validateSeedPalette(seed);
|
|
179
|
+
console.log(chalk.bold(`\nParadigm validation (${issues.length} issues):`));
|
|
180
|
+
console.log(summarizeIssues(issues));
|
|
181
|
+
if (issues.filter((i) => i.level === "MUST" || i.level === "MUST_NOT").length > 0) process.exit(1);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// ── Export commands (set-theme, export-html, export-pdf, export) ──
|
|
185
|
+
registerExportCommands(program);
|
|
186
|
+
|
|
187
|
+
// ── Summary ──
|
|
188
|
+
|
|
189
|
+
function printSummary(style: ThemeStyle): void {
|
|
190
|
+
const s = style.seed;
|
|
191
|
+
console.log(chalk.dim("\n Seed palette:"));
|
|
192
|
+
console.log(` ${chalk.white("surface:")} ${s.surface} ${chalk.white("ink:")} ${s.ink} ${chalk.white("accent:")} ${s.accent}`);
|
|
193
|
+
console.log(` ${chalk.white("panel:")} ${s.panel} ${chalk.white("panel-alt:")} ${s.panelAlt}`);
|
|
194
|
+
if (style.colorSystemId) {
|
|
195
|
+
console.log(chalk.dim(` Color system: ${style.colorSystemId} Mermaid: ${style.mermaidPresetId}`));
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function main(): void { program.parse(); }
|
|
200
|
+
main();
|