@zvoove/unity-ui 2.23.1 → 2.25.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/dist/bin/cli.js +5629 -0
- package/{bin/commands/skills.mjs → dist/bin/generate-skills.js} +621 -688
- package/dist/llms.txt +74 -34
- package/dist/theme.css +54 -0
- package/dist/unity-ui.cjs.js +1 -1
- package/dist/unity-ui.css +1 -1
- package/dist/unity-ui.d.ts +180 -9
- package/dist/unity-ui.es.js +372 -349
- package/package.json +16 -14
- package/bin/cli.mjs +0 -49
- package/bin/commands/config.mjs +0 -68
- package/bin/commands/create.mjs +0 -163
- package/bin/commands/init.mjs +0 -158
- package/bin/commands/rules.mjs +0 -100
- package/bin/generate-skills.mjs +0 -32
- /package/{bin → dist/bin}/templates/component.tsx +0 -0
- /package/{bin → dist/bin}/templates/doc.mdx +0 -0
- /package/{bin → dist/bin}/templates/index.ts +0 -0
- /package/{bin → dist/bin}/templates/stories.tsx +0 -0
- /package/{bin → dist/bin}/templates/styled.ts +0 -0
- /package/{bin → dist/bin}/templates/test.tsx +0 -0
- /package/{bin → dist/bin}/templates/types.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zvoove/unity-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.25.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+ssh://git@github.com/zvoove-org/unity-ui.git"
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"./config": "./src/config.ts"
|
|
21
21
|
},
|
|
22
22
|
"bin": {
|
|
23
|
-
"unity-ui": "./bin/cli.mjs",
|
|
24
|
-
"unity-ui-skills": "./bin/generate-skills.mjs"
|
|
23
|
+
"unity-ui": "./dist/bin/cli.mjs",
|
|
24
|
+
"unity-ui-skills": "./dist/bin/generate-skills.mjs"
|
|
25
25
|
},
|
|
26
26
|
"type": "module",
|
|
27
27
|
"files": [
|
|
@@ -31,10 +31,11 @@
|
|
|
31
31
|
"!docs",
|
|
32
32
|
"!**/*.mdx",
|
|
33
33
|
"!**/*.md",
|
|
34
|
-
"bin"
|
|
34
|
+
"dist/bin/templates"
|
|
35
35
|
],
|
|
36
36
|
"scripts": {
|
|
37
|
-
"build": "tsc && vite build",
|
|
37
|
+
"build": "tsc && vite build && npm run build:cli",
|
|
38
|
+
"build:cli": "esbuild bin/cli.mjs bin/generate-skills.mjs --bundle --platform=node --format=esm --banner:js='#!/usr/bin/env node' --outdir=dist/bin",
|
|
38
39
|
"test": "vitest",
|
|
39
40
|
"storybook": "cross-env VITE_CJS_IGNORE_WARNING=true storybook dev -p 6006",
|
|
40
41
|
"build-storybook": "storybook build",
|
|
@@ -50,17 +51,19 @@
|
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@chromatic-com/storybook": "^5.0.1",
|
|
54
|
+
"commander": "^14.0.3",
|
|
55
|
+
"esbuild": "0.25.0",
|
|
53
56
|
"@commitlint/cli": "^20.4.3",
|
|
54
57
|
"@commitlint/config-conventional": "^20.5.0",
|
|
55
|
-
"@eslint/compat": "^2.0.
|
|
58
|
+
"@eslint/compat": "^2.0.4",
|
|
56
59
|
"@eslint/eslintrc": "^3.3.5",
|
|
57
60
|
"@eslint/js": "^9.39.4",
|
|
58
61
|
"@phosphor-icons/react": "^2.1.10",
|
|
59
|
-
"@storybook/addon-a11y": "^10.3.
|
|
60
|
-
"@storybook/addon-docs": "^10.3.
|
|
61
|
-
"@storybook/addon-links": "^10.3.
|
|
62
|
-
"@storybook/addon-themes": "^10.3.
|
|
63
|
-
"@storybook/react-vite": "^10.3.
|
|
62
|
+
"@storybook/addon-a11y": "^10.3.5",
|
|
63
|
+
"@storybook/addon-docs": "^10.3.5",
|
|
64
|
+
"@storybook/addon-links": "^10.3.5",
|
|
65
|
+
"@storybook/addon-themes": "^10.3.5",
|
|
66
|
+
"@storybook/react-vite": "^10.3.5",
|
|
64
67
|
"@storybook/testing-library": "^0.2.2",
|
|
65
68
|
"@tailwindcss/postcss": "^4.2.1",
|
|
66
69
|
"@tailwindcss/vite": "^4.2.2",
|
|
@@ -78,8 +81,7 @@
|
|
|
78
81
|
"@vitejs/plugin-react": "^5.1.4",
|
|
79
82
|
"@vitest/coverage-v8": "^4.0.18",
|
|
80
83
|
"@vitest/ui": "^4.0.7",
|
|
81
|
-
"chromatic": "^16.
|
|
82
|
-
"commander": "^14.0.3",
|
|
84
|
+
"chromatic": "^16.3.0",
|
|
83
85
|
"commitizen": "^4.3.1",
|
|
84
86
|
"cross-env": "^10.1.0",
|
|
85
87
|
"cz-conventional-changelog": "^3.3.0",
|
|
@@ -99,7 +101,7 @@
|
|
|
99
101
|
"react-dom": "^19.2.4",
|
|
100
102
|
"resize-observer-polyfill": "^1.5.1",
|
|
101
103
|
"rollup-plugin-visualizer": "^7.0.1",
|
|
102
|
-
"storybook": "^10.3.
|
|
104
|
+
"storybook": "^10.3.5",
|
|
103
105
|
"tailwind-merge": "^3.5.0",
|
|
104
106
|
"tailwind-variants": "^3.2.2",
|
|
105
107
|
"tailwindcss": "^4.2.1",
|
package/bin/cli.mjs
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Unity UI — Unified CLI
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* npx unity-ui init Initialize unity-ui.config.mjs
|
|
8
|
-
* npx unity-ui skills [-o .claude] Generate Agent Skills
|
|
9
|
-
* npx unity-ui create <ComponentName> Scaffold a new component
|
|
10
|
-
* npx unity-ui rules [-o .] Generate AI rules (.cursorrules + CLAUDE.md)
|
|
11
|
-
* npx unity-ui --help Show all commands
|
|
12
|
-
*/
|
|
13
|
-
import { runCreate } from './commands/create.mjs';
|
|
14
|
-
import { runInit } from './commands/init.mjs';
|
|
15
|
-
import { runRules } from './commands/rules.mjs';
|
|
16
|
-
import { runSkills } from './commands/skills.mjs';
|
|
17
|
-
import { Command } from 'commander';
|
|
18
|
-
|
|
19
|
-
const program = new Command();
|
|
20
|
-
|
|
21
|
-
program
|
|
22
|
-
.name('unity-ui')
|
|
23
|
-
.description('Unity UI Design System CLI')
|
|
24
|
-
.version('1.0.0');
|
|
25
|
-
|
|
26
|
-
program
|
|
27
|
-
.command('init')
|
|
28
|
-
.description('Initialize unity-ui.config.mjs with project settings')
|
|
29
|
-
.action(() => runInit());
|
|
30
|
-
|
|
31
|
-
program
|
|
32
|
-
.command('skills')
|
|
33
|
-
.description('Generate Agent Skills files from llms.txt')
|
|
34
|
-
.option('-o, --output <dir>', 'Base directory for skills output')
|
|
35
|
-
.action((opts) => runSkills(opts));
|
|
36
|
-
|
|
37
|
-
program
|
|
38
|
-
.command('create')
|
|
39
|
-
.description('Scaffold a new component')
|
|
40
|
-
.argument('<name>', 'Component name (PascalCase)')
|
|
41
|
-
.action((name) => runCreate(name));
|
|
42
|
-
|
|
43
|
-
program
|
|
44
|
-
.command('rules')
|
|
45
|
-
.description('Generate AI rules files (.cursorrules + CLAUDE.md)')
|
|
46
|
-
.option('-o, --output <dir>', 'Output directory')
|
|
47
|
-
.action((opts) => runRules(opts));
|
|
48
|
-
|
|
49
|
-
program.parse();
|
package/bin/commands/config.mjs
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unity UI — Config Loader
|
|
3
|
-
*
|
|
4
|
-
* Looks for unity-ui.config.mjs in process.cwd().
|
|
5
|
-
* If found, merges with defaults. If not, returns defaults.
|
|
6
|
-
*/
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import { pathToFileURL } from 'url';
|
|
10
|
-
|
|
11
|
-
export const DEFAULTS = {
|
|
12
|
-
components: {
|
|
13
|
-
directory: 'src/components',
|
|
14
|
-
indexFile: 'src/index.ts',
|
|
15
|
-
},
|
|
16
|
-
ai: {
|
|
17
|
-
skills: {
|
|
18
|
-
output: '.claude',
|
|
19
|
-
},
|
|
20
|
-
rules: {
|
|
21
|
-
output: '.',
|
|
22
|
-
targets: ['cursorrules', 'claude'],
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function deepMerge(target, source) {
|
|
28
|
-
const result = { ...target };
|
|
29
|
-
for (const key of Object.keys(source)) {
|
|
30
|
-
if (
|
|
31
|
-
source[key] &&
|
|
32
|
-
typeof source[key] === 'object' &&
|
|
33
|
-
!Array.isArray(source[key]) &&
|
|
34
|
-
target[key] &&
|
|
35
|
-
typeof target[key] === 'object' &&
|
|
36
|
-
!Array.isArray(target[key])
|
|
37
|
-
) {
|
|
38
|
-
result[key] = deepMerge(target[key], source[key]);
|
|
39
|
-
} else {
|
|
40
|
-
result[key] = source[key];
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return result;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Loads unity-ui.config.mjs from process.cwd() and merges with defaults.
|
|
48
|
-
* Returns defaults if no config file is found.
|
|
49
|
-
*/
|
|
50
|
-
export async function loadConfig() {
|
|
51
|
-
const configPath = path.resolve(process.cwd(), 'unity-ui.config.mjs');
|
|
52
|
-
|
|
53
|
-
if (!fs.existsSync(configPath)) {
|
|
54
|
-
return DEFAULTS;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
const configUrl = pathToFileURL(configPath).href;
|
|
59
|
-
const mod = await import(configUrl);
|
|
60
|
-
const userConfig = mod.default || {};
|
|
61
|
-
return deepMerge(DEFAULTS, userConfig);
|
|
62
|
-
} catch (err) {
|
|
63
|
-
console.warn(
|
|
64
|
-
`\x1b[33m⚠️ Failed to load unity-ui.config.mjs: ${err.message}\x1b[0m`
|
|
65
|
-
);
|
|
66
|
-
return DEFAULTS;
|
|
67
|
-
}
|
|
68
|
-
}
|
package/bin/commands/create.mjs
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unity UI — Component Scaffolder (core logic)
|
|
3
|
-
*
|
|
4
|
-
* Creates a new component folder with all required files
|
|
5
|
-
* from templates.
|
|
6
|
-
*/
|
|
7
|
-
import { loadConfig } from './config.mjs';
|
|
8
|
-
import { execSync } from 'child_process';
|
|
9
|
-
import fs from 'fs';
|
|
10
|
-
import path from 'path';
|
|
11
|
-
import { fileURLToPath } from 'url';
|
|
12
|
-
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
-
const __dirname = path.dirname(__filename);
|
|
15
|
-
|
|
16
|
-
const lowerFirstLetter = (str) => {
|
|
17
|
-
if (!str) return '';
|
|
18
|
-
return str.charAt(0).toLowerCase() + str.slice(1);
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const checkComponentName = (componentName) => {
|
|
22
|
-
const componentNameRegex = /^[A-Z][a-zA-Z]*$/;
|
|
23
|
-
|
|
24
|
-
if (!componentNameRegex.test(componentName)) {
|
|
25
|
-
console.error(
|
|
26
|
-
'❌ Component name must start with an uppercase letter and contain only letters'
|
|
27
|
-
);
|
|
28
|
-
return false;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (componentName.includes(' ')) {
|
|
32
|
-
console.error('❌ Component name must not contain spaces');
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
return true;
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
export async function runCreate(componentName) {
|
|
40
|
-
if (!checkComponentName(componentName)) {
|
|
41
|
-
process.exit(1);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const config = await loadConfig();
|
|
45
|
-
|
|
46
|
-
const componentDir = path.join(
|
|
47
|
-
process.cwd(),
|
|
48
|
-
config.components.directory,
|
|
49
|
-
componentName
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const templatesDir = path.resolve(__dirname, '..', 'templates');
|
|
53
|
-
|
|
54
|
-
const templateMap = {
|
|
55
|
-
[`{name}.tsx`]: 'component.tsx',
|
|
56
|
-
[`{name}.styled.ts`]: 'styled.ts',
|
|
57
|
-
[`{name}.stories.tsx`]: 'stories.tsx',
|
|
58
|
-
[`{name}.test.tsx`]: 'test.tsx',
|
|
59
|
-
[`{name}.types.ts`]: 'types.ts',
|
|
60
|
-
[`{name}.mdx`]: 'doc.mdx',
|
|
61
|
-
[`index.ts`]: 'index.ts',
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
// Load template files
|
|
65
|
-
const loadTemplate = (templateFile, name) => {
|
|
66
|
-
const filePath = path.join(templatesDir, templateFile);
|
|
67
|
-
|
|
68
|
-
if (!fs.existsSync(filePath)) {
|
|
69
|
-
console.error(`❌ Template file not found: \x1b[33m${filePath}\x1b[0m`);
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
74
|
-
|
|
75
|
-
return content
|
|
76
|
-
.replace(/__COMPONENT_NAME__/g, name)
|
|
77
|
-
.replace(/__STYLES__FUNCTION__/g, lowerFirstLetter(name));
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Create component folder
|
|
81
|
-
if (!fs.existsSync(componentDir)) {
|
|
82
|
-
fs.mkdirSync(componentDir);
|
|
83
|
-
console.log(`✅ Created folder: \x1b[34m${componentName}\x1b[0m`);
|
|
84
|
-
} else {
|
|
85
|
-
console.log(`⚠️ Folder \x1b[33m${componentName}\x1b[0m already exists`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
// Create files
|
|
89
|
-
Object.entries(templateMap).forEach(([fileNamePattern, templateFile]) => {
|
|
90
|
-
const fileName = fileNamePattern.replace('{name}', componentName);
|
|
91
|
-
const fullPath = path.join(componentDir, fileName);
|
|
92
|
-
|
|
93
|
-
if (!fs.existsSync(fullPath)) {
|
|
94
|
-
const content = loadTemplate(templateFile, componentName);
|
|
95
|
-
fs.writeFileSync(fullPath, content, 'utf8');
|
|
96
|
-
console.log(`✅ Created file: \x1b[32m${fileName}\x1b[0m`);
|
|
97
|
-
} else {
|
|
98
|
-
console.log(`⚠️ File \x1b[33m${fileName}\x1b[0m already exists`);
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const indexFile = path.join(process.cwd(), config.components.indexFile);
|
|
103
|
-
const exportLine = `export * from './components/${componentName}';`;
|
|
104
|
-
|
|
105
|
-
// Add export to index.ts
|
|
106
|
-
if (fs.existsSync(indexFile)) {
|
|
107
|
-
const content = fs.readFileSync(indexFile, 'utf8');
|
|
108
|
-
const lines = content.split('\n').filter((line) => line.trim());
|
|
109
|
-
|
|
110
|
-
// Separate theme import from component exports
|
|
111
|
-
const themeImport = lines.find((line) =>
|
|
112
|
-
line.includes("import './theme.css'")
|
|
113
|
-
);
|
|
114
|
-
const componentExports = lines.filter(
|
|
115
|
-
(line) => line !== themeImport && line.startsWith('export * from')
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
if (!componentExports.includes(exportLine)) {
|
|
119
|
-
// Add new export and sort alphabetically
|
|
120
|
-
componentExports.push(exportLine);
|
|
121
|
-
const sortedExports = componentExports.sort((a, b) => {
|
|
122
|
-
const getComponentName = (line) => {
|
|
123
|
-
const match = line.match(/from '\.\/components\/([^']+)'/);
|
|
124
|
-
return match ? match[1] : '';
|
|
125
|
-
};
|
|
126
|
-
return getComponentName(a).localeCompare(getComponentName(b));
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
const finalContent =
|
|
130
|
-
[themeImport, '', ...sortedExports].filter(Boolean).join('\n') + '\n';
|
|
131
|
-
|
|
132
|
-
const finalContentWithEmptyLine = finalContent.replace(
|
|
133
|
-
/(import '\.\/theme\.css';\n)(\n*)/,
|
|
134
|
-
'$1\n'
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
fs.writeFileSync(indexFile, finalContentWithEmptyLine, 'utf8');
|
|
138
|
-
console.log(
|
|
139
|
-
`✅ Added export to \x1b[34m./src/index.ts\x1b[0m (sorted alphabetically)`
|
|
140
|
-
);
|
|
141
|
-
} else {
|
|
142
|
-
console.log(`⚠️ Export already exists in \x1b[33m./src/index.ts\x1b[0m`);
|
|
143
|
-
}
|
|
144
|
-
} else {
|
|
145
|
-
console.log(`❌ \x1b[33m./src/index.ts\x1b[0m does not exist.`);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
console.log(
|
|
149
|
-
`🎉 Component \x1b[32m<${componentName} />\x1b[0m structure created successfully!`
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
// Format the newly created component folder
|
|
153
|
-
try {
|
|
154
|
-
execSync(
|
|
155
|
-
`npx prettier --write "${componentDir}" --ignore-glob "**/*.md" --ignore-glob "**/*.mdx"`,
|
|
156
|
-
{ stdio: 'inherit' }
|
|
157
|
-
);
|
|
158
|
-
|
|
159
|
-
console.log(`✅ Prettier formatted: \x1b[32m<${componentName} />\x1b[0m`);
|
|
160
|
-
} catch (err) {
|
|
161
|
-
console.error(`❌ Prettier formatting failed:`, err);
|
|
162
|
-
}
|
|
163
|
-
}
|
package/bin/commands/init.mjs
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unity UI — Init Command
|
|
3
|
-
*
|
|
4
|
-
* Interactive questionnaire that generates unity-ui.config.mjs.
|
|
5
|
-
*/
|
|
6
|
-
import { DEFAULTS } from './config.mjs';
|
|
7
|
-
import fs from 'fs';
|
|
8
|
-
import path from 'path';
|
|
9
|
-
import readline from 'readline';
|
|
10
|
-
|
|
11
|
-
function createRL() {
|
|
12
|
-
return readline.createInterface({
|
|
13
|
-
input: process.stdin,
|
|
14
|
-
output: process.stdout,
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function ask(rl, question, defaultValue) {
|
|
19
|
-
return new Promise((resolve) => {
|
|
20
|
-
rl.question(
|
|
21
|
-
` \x1b[36m?\x1b[0m ${question} \x1b[90m(${defaultValue})\x1b[0m `,
|
|
22
|
-
(answer) => {
|
|
23
|
-
resolve(answer.trim() || defaultValue);
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function askChoice(rl, question, options, defaultValue) {
|
|
30
|
-
const optionsList = options.map((o) => o.label).join(' / ');
|
|
31
|
-
return new Promise((resolve) => {
|
|
32
|
-
rl.question(
|
|
33
|
-
` \x1b[36m?\x1b[0m ${question} \x1b[90m(${defaultValue})\x1b[0m [${optionsList}] `,
|
|
34
|
-
(answer) => {
|
|
35
|
-
const trimmed = answer.trim().toLowerCase();
|
|
36
|
-
const match = options.find(
|
|
37
|
-
(o) => o.label.toLowerCase() === trimmed || o.alias === trimmed
|
|
38
|
-
);
|
|
39
|
-
if (match) {
|
|
40
|
-
resolve(match.value);
|
|
41
|
-
} else {
|
|
42
|
-
// Default
|
|
43
|
-
const defaultOption = options.find(
|
|
44
|
-
(o) =>
|
|
45
|
-
o.label.toLowerCase() === defaultValue.toLowerCase() ||
|
|
46
|
-
o.alias === defaultValue.toLowerCase()
|
|
47
|
-
);
|
|
48
|
-
resolve(defaultOption ? defaultOption.value : options[0].value);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function generateConfigContent(config) {
|
|
56
|
-
const targets = config.ai.rules.targets;
|
|
57
|
-
const targetsStr = targets.map((t) => `'${t}'`).join(', ');
|
|
58
|
-
|
|
59
|
-
return `// unity-ui.config.mjs — generated by \`npx unity-ui init\`
|
|
60
|
-
import { defineConfig } from '@zvoove/unity-ui/config';
|
|
61
|
-
|
|
62
|
-
export default defineConfig({
|
|
63
|
-
components: {
|
|
64
|
-
directory: '${config.components.directory}',
|
|
65
|
-
indexFile: '${config.components.indexFile}',
|
|
66
|
-
},
|
|
67
|
-
ai: {
|
|
68
|
-
skills: {
|
|
69
|
-
output: '${config.ai.skills.output}',
|
|
70
|
-
},
|
|
71
|
-
rules: {
|
|
72
|
-
output: '${config.ai.rules.output}',
|
|
73
|
-
targets: [${targetsStr}],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
});
|
|
77
|
-
`;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export async function runInit() {
|
|
81
|
-
const configPath = path.resolve(process.cwd(), 'unity-ui.config.mjs');
|
|
82
|
-
|
|
83
|
-
if (fs.existsSync(configPath)) {
|
|
84
|
-
console.log(
|
|
85
|
-
`\x1b[33m⚠️ unity-ui.config.mjs already exists. Delete it first to re-initialize.\x1b[0m`
|
|
86
|
-
);
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
console.log(`\n \x1b[1m🔧 Unity UI — Project Setup\x1b[0m\n`);
|
|
91
|
-
|
|
92
|
-
const rl = createRL();
|
|
93
|
-
|
|
94
|
-
const componentsDir = await ask(
|
|
95
|
-
rl,
|
|
96
|
-
'Where do your components live?',
|
|
97
|
-
DEFAULTS.components.directory
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const indexFile = await ask(
|
|
101
|
-
rl,
|
|
102
|
-
'Where is your main index/barrel file?',
|
|
103
|
-
DEFAULTS.components.indexFile
|
|
104
|
-
);
|
|
105
|
-
|
|
106
|
-
const rulesTargets = await askChoice(
|
|
107
|
-
rl,
|
|
108
|
-
'Generate AI rules for which tools?',
|
|
109
|
-
[
|
|
110
|
-
{ label: 'Both', alias: 'b', value: ['cursorrules', 'claude'] },
|
|
111
|
-
{ label: 'Claude', alias: 'c', value: ['claude'] },
|
|
112
|
-
{ label: 'Cursor', alias: 'u', value: ['cursorrules'] },
|
|
113
|
-
{ label: 'None', alias: 'n', value: [] },
|
|
114
|
-
],
|
|
115
|
-
'Both'
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
const skillsOutput = await ask(
|
|
119
|
-
rl,
|
|
120
|
-
'Where should Agent Skills be generated?',
|
|
121
|
-
DEFAULTS.ai.skills.output
|
|
122
|
-
);
|
|
123
|
-
|
|
124
|
-
const rulesOutput = await ask(
|
|
125
|
-
rl,
|
|
126
|
-
'Where should rules files be generated?',
|
|
127
|
-
DEFAULTS.ai.rules.output
|
|
128
|
-
);
|
|
129
|
-
|
|
130
|
-
rl.close();
|
|
131
|
-
|
|
132
|
-
const config = {
|
|
133
|
-
components: {
|
|
134
|
-
directory: componentsDir,
|
|
135
|
-
indexFile: indexFile,
|
|
136
|
-
},
|
|
137
|
-
ai: {
|
|
138
|
-
skills: { output: skillsOutput },
|
|
139
|
-
rules: { output: rulesOutput, targets: rulesTargets },
|
|
140
|
-
},
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const content = generateConfigContent(config);
|
|
144
|
-
fs.writeFileSync(configPath, content, 'utf8');
|
|
145
|
-
|
|
146
|
-
console.log(`\n \x1b[32m✅ Created unity-ui.config.mjs\x1b[0m\n`);
|
|
147
|
-
console.log(` Components: ${config.components.directory}/`);
|
|
148
|
-
console.log(` Index file: ${config.components.indexFile}`);
|
|
149
|
-
console.log(` Skills dir: ${config.ai.skills.output}/skills/`);
|
|
150
|
-
if (config.ai.rules.targets.length > 0) {
|
|
151
|
-
console.log(
|
|
152
|
-
` Rules: ${config.ai.rules.targets.join(', ')} → ${config.ai.rules.output}/`
|
|
153
|
-
);
|
|
154
|
-
} else {
|
|
155
|
-
console.log(` Rules: disabled`);
|
|
156
|
-
}
|
|
157
|
-
console.log('');
|
|
158
|
-
}
|
package/bin/commands/rules.mjs
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unity UI — AI Rules Generator
|
|
3
|
-
*
|
|
4
|
-
* Generates .cursorrules and CLAUDE.md files for consuming projects.
|
|
5
|
-
* These files help AI coding assistants understand and correctly use
|
|
6
|
-
* Unity UI components.
|
|
7
|
-
*/
|
|
8
|
-
import { loadConfig } from './config.mjs';
|
|
9
|
-
import { findLlmsTxt } from './skills.mjs';
|
|
10
|
-
import fs from 'fs';
|
|
11
|
-
import path from 'path';
|
|
12
|
-
|
|
13
|
-
function generateRulesContent(llmsContent) {
|
|
14
|
-
return `# Unity UI — AI Rules
|
|
15
|
-
|
|
16
|
-
> Auto-generated by \`npx unity-ui rules\`. Do not edit manually.
|
|
17
|
-
> Source: @zvoove/unity-ui llms.txt
|
|
18
|
-
|
|
19
|
-
## General Rules
|
|
20
|
-
|
|
21
|
-
- Always import components from \`@zvoove/unity-ui\`
|
|
22
|
-
- Never recreate components that exist in this library
|
|
23
|
-
- Use responsive props where applicable (single value or breakpoint object)
|
|
24
|
-
- Use design tokens from theme.css — never hardcode colors, spacing, or shadows
|
|
25
|
-
- Use \`tv()\` from tailwind-variants for component styling — never inline conditional classes
|
|
26
|
-
- Dark mode uses \`data-theme="dark"\` attribute, not \`className="dark"\`
|
|
27
|
-
- Default/placeholder texts should be in German
|
|
28
|
-
- Font (Source Sans 3) is bundled via \`@font-face\` in theme.css — no extra setup needed
|
|
29
|
-
|
|
30
|
-
## Setup
|
|
31
|
-
|
|
32
|
-
\`\`\`bash
|
|
33
|
-
npm install @zvoove/unity-ui
|
|
34
|
-
\`\`\`
|
|
35
|
-
|
|
36
|
-
\`\`\`css
|
|
37
|
-
@import '@zvoove/unity-ui/theme.css';
|
|
38
|
-
@import '@zvoove/unity-ui/unity-ui.css';
|
|
39
|
-
\`\`\`
|
|
40
|
-
|
|
41
|
-
## Responsive Props
|
|
42
|
-
|
|
43
|
-
Breakpoints: minimum (0px), mobile (320px), tablet (768px), laptop (1024px), desktop (1440px).
|
|
44
|
-
|
|
45
|
-
\`\`\`tsx
|
|
46
|
-
<Button size="md" />
|
|
47
|
-
<Button size={{ mobile: 'sm', tablet: 'md', desktop: 'lg' }} />
|
|
48
|
-
\`\`\`
|
|
49
|
-
|
|
50
|
-
## Component Reference
|
|
51
|
-
|
|
52
|
-
${llmsContent}
|
|
53
|
-
`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
export async function runRules({ output: outputDir } = {}) {
|
|
57
|
-
const config = await loadConfig();
|
|
58
|
-
const resolvedDir = path.resolve(
|
|
59
|
-
process.cwd(),
|
|
60
|
-
outputDir || config.ai.rules.output
|
|
61
|
-
);
|
|
62
|
-
const targets = config.ai.rules.targets;
|
|
63
|
-
|
|
64
|
-
const llmsPath = findLlmsTxt();
|
|
65
|
-
if (!llmsPath) {
|
|
66
|
-
console.error(
|
|
67
|
-
'Could not find llms.txt. Make sure @zvoove/unity-ui is installed and built.'
|
|
68
|
-
);
|
|
69
|
-
process.exit(1);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const llmsContent = fs.readFileSync(llmsPath, 'utf8');
|
|
73
|
-
const rulesContent = generateRulesContent(llmsContent);
|
|
74
|
-
|
|
75
|
-
fs.mkdirSync(resolvedDir, { recursive: true });
|
|
76
|
-
|
|
77
|
-
if (targets.includes('cursorrules')) {
|
|
78
|
-
const cursorRulesPath = path.join(resolvedDir, '.cursorrules');
|
|
79
|
-
fs.writeFileSync(cursorRulesPath, rulesContent, 'utf8');
|
|
80
|
-
console.log(
|
|
81
|
-
`✅ Generated ${path.relative(process.cwd(), cursorRulesPath)}`
|
|
82
|
-
);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (targets.includes('claude')) {
|
|
86
|
-
const claudeMdPath = path.join(resolvedDir, 'CLAUDE.md');
|
|
87
|
-
fs.writeFileSync(claudeMdPath, rulesContent, 'utf8');
|
|
88
|
-
console.log(`✅ Generated ${path.relative(process.cwd(), claudeMdPath)}`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (targets.length > 0) {
|
|
92
|
-
console.log(
|
|
93
|
-
`\n Your AI assistant now knows how to use Unity UI components.\n`
|
|
94
|
-
);
|
|
95
|
-
} else {
|
|
96
|
-
console.log(
|
|
97
|
-
`\n No rule targets configured. Set targets in unity-ui.config.mjs.\n`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
}
|
package/bin/generate-skills.mjs
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @deprecated Use `npx unity-ui skills` instead.
|
|
5
|
-
*
|
|
6
|
-
* This shim exists for backward compatibility only.
|
|
7
|
-
*/
|
|
8
|
-
import { runSkills } from './commands/skills.mjs';
|
|
9
|
-
|
|
10
|
-
console.warn(
|
|
11
|
-
'\x1b[33m⚠️ "unity-ui-skills" is deprecated. Use "npx unity-ui skills" instead.\x1b[0m\n'
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
// Parse legacy args
|
|
15
|
-
const args = process.argv.slice(2);
|
|
16
|
-
let output = '.claude';
|
|
17
|
-
for (let i = 0; i < args.length; i++) {
|
|
18
|
-
if ((args[i] === '--output' || args[i] === '-o') && args[i + 1]) {
|
|
19
|
-
output = args[i + 1];
|
|
20
|
-
i++;
|
|
21
|
-
}
|
|
22
|
-
if (args[i] === '--help' || args[i] === '-h') {
|
|
23
|
-
console.log(`Usage: npx unity-ui skills [options]
|
|
24
|
-
|
|
25
|
-
This command has moved. Please use:
|
|
26
|
-
npx unity-ui skills [-o <dir>]
|
|
27
|
-
`);
|
|
28
|
-
process.exit(0);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
runSkills({ output });
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|