@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 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 > tailwind.theme.js
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.extend block for tailwind.config.js
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.1.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",
@@ -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 toTailwind(data) {
29
- const c = data.colors ?? {}
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(Object.entries(c).map(([k, v]) => [k, String(v)])),
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
- process.stdout.write(RENDERERS[flags.to](data) + '\n')
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
  }
@@ -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(' The CLI will gain a direct extraction endpoint in v0.2.'))
32
+ console.log(kleur.dim(' A direct extraction endpoint is on the roadmap for now this opens the web flow.'))
33
33
  },
34
34
  }
@@ -7,26 +7,30 @@ ${kleur.dim('USAGE')}
7
7
  design-md <command> [args]
8
8
 
9
9
  ${kleur.dim('COMMANDS')}
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
- extract <url> Extract a draft DESIGN.md from any production URL
18
- theme <slug> --dark Compute a dark-mode counterpart of a light design
19
- preview <slug> Open the directory detail page in your browser
20
- help This screen
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 > tailwind.theme.js
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://github.com/google-labs-code/design.md
29
- ${kleur.dim('Catalog:')} https://www.webdesignhot.com/design-md
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 = {
package/src/index.mjs CHANGED
@@ -25,6 +25,7 @@ const COMMANDS = {
25
25
  diff,
26
26
  export: exportTokens,
27
27
  extract,
28
+ import: extract, // alias — name aligned with Google Labs PR #40
28
29
  theme,
29
30
  preview,
30
31
  help,