@webdesignhot/design-md 0.1.0 → 0.2.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/README.md +10 -3
- package/package.json +1 -1
- package/src/commands/export.mjs +51 -6
- package/src/commands/extract.mjs +1 -1
- package/src/commands/help.mjs +18 -14
- package/src/index.mjs +1 -0
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ $ npx @webdesignhot/design-md list
|
|
|
12
12
|
arc Arc light warm sans
|
|
13
13
|
…
|
|
14
14
|
|
|
15
|
-
$ npx @webdesignhot/design-md export DESIGN.md --to tailwind >
|
|
15
|
+
$ npx @webdesignhot/design-md export DESIGN.md --to tailwind > theme.css # Tailwind v4 default
|
|
16
|
+
$ npx @webdesignhot/design-md export DESIGN.md --to tailwind --tailwind-version v3 > tailwind.config.js
|
|
16
17
|
```
|
|
17
18
|
|
|
18
19
|
## Why
|
|
@@ -57,9 +58,11 @@ lint <file> [--format=text|json]
|
|
|
57
58
|
diff <a> <b> [--format=text|json]
|
|
58
59
|
Token-level diff between two DESIGN.md files.
|
|
59
60
|
|
|
60
|
-
export <file> --to <tailwind|css|dtcg|figma>
|
|
61
|
+
export <file> --to <tailwind|css|dtcg|figma> [--tailwind-version <v3|v4>]
|
|
61
62
|
Convert tokens to one of:
|
|
62
|
-
tailwind — theme
|
|
63
|
+
tailwind — @theme {} CSS block (Tailwind v4 default).
|
|
64
|
+
Pass --tailwind-version v3 for the legacy
|
|
65
|
+
module.exports = { theme: { extend: { ... } } } shape.
|
|
63
66
|
css — :root { --color-bg, --radius-card, … }
|
|
64
67
|
dtcg — W3C Design Tokens Community Group JSON
|
|
65
68
|
figma — Figma Variables import format
|
|
@@ -68,6 +71,10 @@ extract <url> [-o <path>] [--token-only]
|
|
|
68
71
|
Extract a draft DESIGN.md from any production URL.
|
|
69
72
|
(Requires a webdesignhot session — opens the browser flow.)
|
|
70
73
|
|
|
74
|
+
import <url>
|
|
75
|
+
Alias of `extract`. Naming aligned with Google Labs DESIGN.md tooling
|
|
76
|
+
so the same verb works whichever CLI you've internalised.
|
|
77
|
+
|
|
71
78
|
theme <slug> [--dark|--light]
|
|
72
79
|
Compute a dark/light variant of any design.
|
|
73
80
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webdesignhot/design-md",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Drop any DESIGN.md into your repo in one command. Browse, install, lint, diff, and export design systems extracted from real production sites.",
|
|
5
5
|
"keywords": ["design.md", "design-system", "design-tokens", "ai-agents", "cli", "tailwind", "figma", "dtcg"],
|
|
6
6
|
"author": "webdesignhot",
|
package/src/commands/export.mjs
CHANGED
|
@@ -2,14 +2,17 @@ import { resolve } from 'node:path'
|
|
|
2
2
|
import { readDesignMd } from '../lib/parse.mjs'
|
|
3
3
|
|
|
4
4
|
const FORMATS = new Set(['tailwind', 'css', 'dtcg', 'figma'])
|
|
5
|
+
const TAILWIND_VERSIONS = new Set(['v3', 'v4'])
|
|
5
6
|
|
|
6
7
|
function parseFlags(args) {
|
|
7
|
-
const flags = { to: null }
|
|
8
|
+
const flags = { to: null, tailwindVersion: 'v4' }
|
|
8
9
|
const positional = []
|
|
9
10
|
for (let i = 0; i < args.length; i++) {
|
|
10
11
|
const a = args[i]
|
|
11
12
|
if (a.startsWith('--to=')) flags.to = a.slice(5)
|
|
12
13
|
else if (a === '--to') flags.to = args[++i]
|
|
14
|
+
else if (a.startsWith('--tailwind-version=')) flags.tailwindVersion = a.slice(19)
|
|
15
|
+
else if (a === '--tailwind-version') flags.tailwindVersion = args[++i]
|
|
13
16
|
else positional.push(a)
|
|
14
17
|
}
|
|
15
18
|
return { flags, positional }
|
|
@@ -25,13 +28,44 @@ function toCss(data) {
|
|
|
25
28
|
return lines.join('\n')
|
|
26
29
|
}
|
|
27
30
|
|
|
28
|
-
function
|
|
29
|
-
|
|
31
|
+
function flattenColors(c) {
|
|
32
|
+
// Multi-theme: pick the default theme (or first one) for export.
|
|
33
|
+
const values = Object.values(c)
|
|
34
|
+
if (values.length > 0 && values.every((v) => v && typeof v === 'object')) {
|
|
35
|
+
return values[0]
|
|
36
|
+
}
|
|
37
|
+
return c
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function toTailwindV4(data) {
|
|
41
|
+
const c = flattenColors(data.colors ?? {})
|
|
42
|
+
const r = data.radius ?? {}
|
|
43
|
+
const s = data.spacing?.scale
|
|
44
|
+
const lines = ['@theme {']
|
|
45
|
+
for (const [k, v] of Object.entries(c)) {
|
|
46
|
+
if (typeof v === 'string') lines.push(` --color-${k}: ${v};`)
|
|
47
|
+
}
|
|
48
|
+
for (const [k, v] of Object.entries(r)) {
|
|
49
|
+
lines.push(` --radius-${k}: ${typeof v === 'number' ? `${v}px` : v};`)
|
|
50
|
+
}
|
|
51
|
+
if (Array.isArray(s)) {
|
|
52
|
+
s.forEach((unit, i) => lines.push(` --spacing-${i}: ${typeof unit === 'number' ? `${unit}px` : unit};`))
|
|
53
|
+
}
|
|
54
|
+
lines.push('}')
|
|
55
|
+
return lines.join('\n')
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function toTailwindV3(data) {
|
|
59
|
+
const c = flattenColors(data.colors ?? {})
|
|
30
60
|
const r = data.radius ?? {}
|
|
31
61
|
const out = {
|
|
32
62
|
theme: {
|
|
33
63
|
extend: {
|
|
34
|
-
colors: Object.fromEntries(
|
|
64
|
+
colors: Object.fromEntries(
|
|
65
|
+
Object.entries(c)
|
|
66
|
+
.filter(([, v]) => typeof v === 'string')
|
|
67
|
+
.map(([k, v]) => [k, String(v)]),
|
|
68
|
+
),
|
|
35
69
|
borderRadius: Object.fromEntries(
|
|
36
70
|
Object.entries(r).map(([k, v]) => [k, typeof v === 'number' ? `${v}px` : v]),
|
|
37
71
|
),
|
|
@@ -41,6 +75,10 @@ function toTailwind(data) {
|
|
|
41
75
|
return `module.exports = ${JSON.stringify(out, null, 2)}`
|
|
42
76
|
}
|
|
43
77
|
|
|
78
|
+
function toTailwind(data, version = 'v4') {
|
|
79
|
+
return version === 'v3' ? toTailwindV3(data) : toTailwindV4(data)
|
|
80
|
+
}
|
|
81
|
+
|
|
44
82
|
function toDtcg(data) {
|
|
45
83
|
const c = data.colors ?? {}
|
|
46
84
|
const r = data.radius ?? {}
|
|
@@ -73,7 +111,7 @@ function toFigma(data) {
|
|
|
73
111
|
const RENDERERS = { tailwind: toTailwind, css: toCss, dtcg: toDtcg, figma: toFigma }
|
|
74
112
|
|
|
75
113
|
export const exportTokens = {
|
|
76
|
-
usage: 'export <file> --to <tailwind|css|dtcg|figma>',
|
|
114
|
+
usage: 'export <file> --to <tailwind|css|dtcg|figma> [--tailwind-version v3|v4]',
|
|
77
115
|
async run(args) {
|
|
78
116
|
const { flags, positional } = parseFlags(args)
|
|
79
117
|
const file = positional[0]
|
|
@@ -85,7 +123,14 @@ export const exportTokens = {
|
|
|
85
123
|
console.error(`Unknown format "${flags.to}". Choose: ${[...FORMATS].join(', ')}`)
|
|
86
124
|
process.exit(2)
|
|
87
125
|
}
|
|
126
|
+
if (!TAILWIND_VERSIONS.has(flags.tailwindVersion)) {
|
|
127
|
+
console.error(`Unknown --tailwind-version "${flags.tailwindVersion}". Choose: v3, v4`)
|
|
128
|
+
process.exit(2)
|
|
129
|
+
}
|
|
88
130
|
const { data } = await readDesignMd(resolve(process.cwd(), file))
|
|
89
|
-
|
|
131
|
+
const out = flags.to === 'tailwind'
|
|
132
|
+
? toTailwind(data, flags.tailwindVersion)
|
|
133
|
+
: RENDERERS[flags.to](data)
|
|
134
|
+
process.stdout.write(out + '\n')
|
|
90
135
|
},
|
|
91
136
|
}
|
package/src/commands/extract.mjs
CHANGED
|
@@ -29,6 +29,6 @@ export const extract = {
|
|
|
29
29
|
console.log(` ${kleur.cyan(target)}`)
|
|
30
30
|
console.log()
|
|
31
31
|
console.log(kleur.yellow('Tip: extract requires a webdesignhot session — visit the URL above to authorize.'))
|
|
32
|
-
console.log(kleur.dim('
|
|
32
|
+
console.log(kleur.dim(' A direct extraction endpoint is on the roadmap — for now this opens the web flow.'))
|
|
33
33
|
},
|
|
34
34
|
}
|
package/src/commands/help.mjs
CHANGED
|
@@ -7,26 +7,30 @@ ${kleur.dim('USAGE')}
|
|
|
7
7
|
design-md <command> [args]
|
|
8
8
|
|
|
9
9
|
${kleur.dim('COMMANDS')}
|
|
10
|
-
add <slug>
|
|
11
|
-
list
|
|
12
|
-
category [name]
|
|
13
|
-
init
|
|
14
|
-
lint <file>
|
|
15
|
-
diff <a> <b>
|
|
16
|
-
export <file> --to <f>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
10
|
+
add <slug> Write the design's DESIGN.md to your CWD
|
|
11
|
+
list Print the full catalog (slug · name · tags)
|
|
12
|
+
category [name] Browse categories — without a name lists all
|
|
13
|
+
init Interactive picker (default if no command)
|
|
14
|
+
lint <file> Validate a DESIGN.md for spec compliance
|
|
15
|
+
diff <a> <b> Token-level diff between two DESIGN.md files
|
|
16
|
+
export <file> --to <f> Convert tokens to tailwind|css|dtcg|figma
|
|
17
|
+
tailwind defaults to v4 (--tailwind-version v3 for legacy)
|
|
18
|
+
extract <url> Extract a draft DESIGN.md from a production URL
|
|
19
|
+
import <url> Alias of extract — name aligned with Google Labs
|
|
20
|
+
theme <slug> --dark Compute a dark-mode counterpart of a light design
|
|
21
|
+
preview <slug> Open the directory detail page in your browser
|
|
22
|
+
help This screen
|
|
21
23
|
|
|
22
24
|
${kleur.dim('EXAMPLES')}
|
|
23
25
|
$ design-md add linear ${kleur.dim('# writes DESIGN.md to CWD')}
|
|
24
26
|
$ design-md list | grep editorial
|
|
25
|
-
$ design-md export DESIGN.md --to tailwind >
|
|
27
|
+
$ design-md export DESIGN.md --to tailwind > theme.css
|
|
28
|
+
$ design-md export DESIGN.md --to tailwind --tailwind-version v3 > tailwind.config.js
|
|
29
|
+
$ design-md import https://stripe.com
|
|
26
30
|
$ design-md diff DESIGN.md old.md
|
|
27
31
|
|
|
28
|
-
${kleur.dim('Spec:')} https://
|
|
29
|
-
${kleur.dim('Catalog:')} https://www.webdesignhot.com/design
|
|
32
|
+
${kleur.dim('Spec:')} https://www.webdesignhot.com/design.md/spec ${kleur.dim('(webdesignhot/0.1)')}
|
|
33
|
+
${kleur.dim('Catalog:')} https://www.webdesignhot.com/design.md/
|
|
30
34
|
`
|
|
31
35
|
|
|
32
36
|
export const help = {
|