inai-react-components 0.1.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/commands/add.d.ts +34 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +284 -0
- package/dist/commands/diff.d.ts +6 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +100 -0
- package/dist/commands/init.d.ts +46 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +267 -0
- package/dist/commands/list.d.ts +8 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +73 -0
- package/dist/commands/status.d.ts +50 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +72 -0
- package/dist/commands/sync.d.ts +2 -0
- package/dist/commands/sync.d.ts.map +1 -0
- package/dist/commands/sync.js +23 -0
- package/dist/commands/theme.d.ts +14 -0
- package/dist/commands/theme.d.ts.map +1 -0
- package/dist/commands/theme.js +94 -0
- package/dist/commands/update.d.ts +8 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +139 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +54 -0
- package/dist/utils/registry-resolver.d.ts +4 -0
- package/dist/utils/registry-resolver.d.ts.map +1 -0
- package/dist/utils/registry-resolver.js +33 -0
- package/package.json +47 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import prompts from "prompts";
|
|
6
|
+
import { cloneRegistry, getCacheDir } from "../utils/registry-resolver.js";
|
|
7
|
+
const AVAILABLE_THEMES = ["monday", "linear", "notion", "vercel"];
|
|
8
|
+
export async function promptInitConfig() {
|
|
9
|
+
const response = await prompts([
|
|
10
|
+
{
|
|
11
|
+
type: "text",
|
|
12
|
+
name: "componentPath",
|
|
13
|
+
message: "Where would you like to install components?",
|
|
14
|
+
initial: "src/components/ui",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
type: "text",
|
|
18
|
+
name: "blockPath",
|
|
19
|
+
message: "Where would you like to install blocks?",
|
|
20
|
+
initial: "src/components/blocks",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
type: "select",
|
|
24
|
+
name: "theme",
|
|
25
|
+
message: "Which base theme would you like to use?",
|
|
26
|
+
choices: AVAILABLE_THEMES.map((t) => ({ title: t, value: t })),
|
|
27
|
+
initial: 0,
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
type: "text",
|
|
31
|
+
name: "importAlias",
|
|
32
|
+
message: "Configure the import alias for components:",
|
|
33
|
+
initial: "@/components/ui",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
name: "utilsAlias",
|
|
38
|
+
message: "Configure the import alias for utils:",
|
|
39
|
+
initial: "@/lib/utils",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
type: "confirm",
|
|
43
|
+
name: "tanstackRouter",
|
|
44
|
+
message: "Would you like to use TanStack Router?",
|
|
45
|
+
initial: false,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
type: "confirm",
|
|
49
|
+
name: "tanstackQuery",
|
|
50
|
+
message: "Would you like to use TanStack Query?",
|
|
51
|
+
initial: false,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
type: "confirm",
|
|
55
|
+
name: "tanstackForm",
|
|
56
|
+
message: "Would you like to use TanStack Form?",
|
|
57
|
+
initial: false,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
type: "confirm",
|
|
61
|
+
name: "tanstackTable",
|
|
62
|
+
message: "Would you like to use TanStack Table?",
|
|
63
|
+
initial: false,
|
|
64
|
+
},
|
|
65
|
+
], {
|
|
66
|
+
onCancel: () => {
|
|
67
|
+
return false;
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
if (!response.componentPath) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
return response;
|
|
74
|
+
}
|
|
75
|
+
export function buildComponentsJson(config, repoUrl) {
|
|
76
|
+
const json = {
|
|
77
|
+
$schema: "https://inai-ui.dev/schema.json",
|
|
78
|
+
style: "default",
|
|
79
|
+
tailwind: {
|
|
80
|
+
config: "tailwind.config.ts",
|
|
81
|
+
css: "src/index.css",
|
|
82
|
+
},
|
|
83
|
+
aliases: {
|
|
84
|
+
components: config.importAlias,
|
|
85
|
+
blocks: config.blockPath.startsWith("src/")
|
|
86
|
+
? `@/${config.blockPath.slice(4)}`
|
|
87
|
+
: config.blockPath,
|
|
88
|
+
utils: config.utilsAlias,
|
|
89
|
+
},
|
|
90
|
+
theme: config.theme,
|
|
91
|
+
tanstack: {
|
|
92
|
+
router: config.tanstackRouter,
|
|
93
|
+
query: config.tanstackQuery,
|
|
94
|
+
form: config.tanstackForm,
|
|
95
|
+
table: config.tanstackTable,
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
if (repoUrl) {
|
|
99
|
+
json.registrySource = repoUrl;
|
|
100
|
+
}
|
|
101
|
+
return json;
|
|
102
|
+
}
|
|
103
|
+
export function getCnTemplate() {
|
|
104
|
+
return `import { clsx, type ClassValue } from "clsx";
|
|
105
|
+
import { twMerge } from "tailwind-merge";
|
|
106
|
+
|
|
107
|
+
export function cn(...inputs: ClassValue[]) {
|
|
108
|
+
return twMerge(clsx(inputs));
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
export function getLocalTailwindCssTemplate(theme) {
|
|
113
|
+
return `@import "tailwindcss";
|
|
114
|
+
@import "./styles/tokens/index.css";
|
|
115
|
+
@import "./styles/tokens/themes/${theme}.css";
|
|
116
|
+
@import "./styles/tokens/presets/typography.css";
|
|
117
|
+
@import "./styles/tokens/presets/animations.css";
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
export function getLegacyTailwindCssTemplate(theme) {
|
|
121
|
+
return `@import "tailwindcss";
|
|
122
|
+
@import "@company/tokens";
|
|
123
|
+
@import "@company/tokens/themes/${theme}.css";
|
|
124
|
+
@import "@company/tokens/presets/typography.css";
|
|
125
|
+
@import "@company/tokens/presets/animations.css";
|
|
126
|
+
`;
|
|
127
|
+
}
|
|
128
|
+
function copyDirRecursive(src, dest) {
|
|
129
|
+
const copied = [];
|
|
130
|
+
if (!fs.existsSync(src))
|
|
131
|
+
return copied;
|
|
132
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
133
|
+
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
|
|
134
|
+
const srcPath = path.join(src, entry.name);
|
|
135
|
+
const destPath = path.join(dest, entry.name);
|
|
136
|
+
if (entry.isDirectory()) {
|
|
137
|
+
copied.push(...copyDirRecursive(srcPath, destPath));
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
fs.copyFileSync(srcPath, destPath);
|
|
141
|
+
copied.push(destPath);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return copied;
|
|
145
|
+
}
|
|
146
|
+
function copyTokensToProject(registryDir, targetDir, theme) {
|
|
147
|
+
const tokensSrc = path.join(registryDir, "packages", "tokens", "src");
|
|
148
|
+
const tokensDest = path.join(targetDir, "src", "styles", "tokens");
|
|
149
|
+
const copied = [];
|
|
150
|
+
if (!fs.existsSync(tokensSrc))
|
|
151
|
+
return copied;
|
|
152
|
+
fs.mkdirSync(tokensDest, { recursive: true });
|
|
153
|
+
// Copy base files
|
|
154
|
+
for (const file of ["base.css", "index.css"]) {
|
|
155
|
+
const src = path.join(tokensSrc, file);
|
|
156
|
+
if (fs.existsSync(src)) {
|
|
157
|
+
fs.copyFileSync(src, path.join(tokensDest, file));
|
|
158
|
+
copied.push(`src/styles/tokens/${file}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
// Copy selected theme
|
|
162
|
+
const themesSrc = path.join(tokensSrc, "themes");
|
|
163
|
+
const themesDest = path.join(tokensDest, "themes");
|
|
164
|
+
if (fs.existsSync(themesSrc)) {
|
|
165
|
+
fs.mkdirSync(themesDest, { recursive: true });
|
|
166
|
+
const themeFile = `${theme}.css`;
|
|
167
|
+
const themeSrc = path.join(themesSrc, themeFile);
|
|
168
|
+
if (fs.existsSync(themeSrc)) {
|
|
169
|
+
fs.copyFileSync(themeSrc, path.join(themesDest, themeFile));
|
|
170
|
+
copied.push(`src/styles/tokens/themes/${themeFile}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Copy presets
|
|
174
|
+
const presetsSrc = path.join(tokensSrc, "presets");
|
|
175
|
+
const presetsDest = path.join(tokensDest, "presets");
|
|
176
|
+
if (fs.existsSync(presetsSrc)) {
|
|
177
|
+
fs.mkdirSync(presetsDest, { recursive: true });
|
|
178
|
+
for (const file of ["typography.css", "animations.css"]) {
|
|
179
|
+
const src = path.join(presetsSrc, file);
|
|
180
|
+
if (fs.existsSync(src)) {
|
|
181
|
+
fs.copyFileSync(src, path.join(presetsDest, file));
|
|
182
|
+
copied.push(`src/styles/tokens/presets/${file}`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return copied;
|
|
187
|
+
}
|
|
188
|
+
export async function runInit(config, targetDir, repoUrl) {
|
|
189
|
+
const filesCreated = [];
|
|
190
|
+
// 1. Create components.json
|
|
191
|
+
const componentsJsonPath = path.join(targetDir, "components.json");
|
|
192
|
+
const componentsJson = buildComponentsJson(config, repoUrl);
|
|
193
|
+
fs.writeFileSync(componentsJsonPath, JSON.stringify(componentsJson, null, 2) + "\n");
|
|
194
|
+
filesCreated.push("components.json");
|
|
195
|
+
// 2. Create component and block directories
|
|
196
|
+
const componentDir = path.join(targetDir, config.componentPath);
|
|
197
|
+
fs.mkdirSync(componentDir, { recursive: true });
|
|
198
|
+
const blockDir = path.join(targetDir, config.blockPath);
|
|
199
|
+
fs.mkdirSync(blockDir, { recursive: true });
|
|
200
|
+
// 3. Create cn.ts utility
|
|
201
|
+
const utilsDir = path.join(targetDir, "src", "lib");
|
|
202
|
+
fs.mkdirSync(utilsDir, { recursive: true });
|
|
203
|
+
const cnPath = path.join(utilsDir, "cn.ts");
|
|
204
|
+
fs.writeFileSync(cnPath, getCnTemplate());
|
|
205
|
+
filesCreated.push("src/lib/cn.ts");
|
|
206
|
+
// 4. Copy tokens and create CSS
|
|
207
|
+
const cssDir = path.join(targetDir, "src");
|
|
208
|
+
fs.mkdirSync(cssDir, { recursive: true });
|
|
209
|
+
const cssPath = path.join(cssDir, "index.css");
|
|
210
|
+
if (repoUrl) {
|
|
211
|
+
// Remote mode: copy tokens from cached registry
|
|
212
|
+
const registryDir = getCacheDir();
|
|
213
|
+
const tokenFiles = copyTokensToProject(registryDir, targetDir, config.theme);
|
|
214
|
+
filesCreated.push(...tokenFiles);
|
|
215
|
+
fs.writeFileSync(cssPath, getLocalTailwindCssTemplate(config.theme));
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
// Local mode: reference @company/tokens package
|
|
219
|
+
fs.writeFileSync(cssPath, getLegacyTailwindCssTemplate(config.theme));
|
|
220
|
+
}
|
|
221
|
+
filesCreated.push("src/index.css");
|
|
222
|
+
return { success: true, filesCreated };
|
|
223
|
+
}
|
|
224
|
+
export async function initCommand(repoUrl) {
|
|
225
|
+
console.log(chalk.bold("\nInAI UI - Project Initialization\n"));
|
|
226
|
+
if (repoUrl) {
|
|
227
|
+
const spinner = ora("Cloning component registry...").start();
|
|
228
|
+
try {
|
|
229
|
+
cloneRegistry(repoUrl);
|
|
230
|
+
spinner.succeed("Registry cloned successfully!");
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
spinner.fail("Failed to clone registry.");
|
|
234
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
235
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
236
|
+
console.error(chalk.dim("\nMake sure you have access to the repository and your SSH keys are configured."));
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
const config = await promptInitConfig();
|
|
241
|
+
if (!config) {
|
|
242
|
+
console.log(chalk.yellow("\nInitialization cancelled."));
|
|
243
|
+
process.exit(0);
|
|
244
|
+
}
|
|
245
|
+
const spinner = ora("Initializing project...").start();
|
|
246
|
+
try {
|
|
247
|
+
const targetDir = process.cwd();
|
|
248
|
+
const result = await runInit(config, targetDir, repoUrl);
|
|
249
|
+
spinner.succeed("Project initialized successfully!");
|
|
250
|
+
console.log(chalk.green("\nCreated files:"));
|
|
251
|
+
for (const file of result.filesCreated) {
|
|
252
|
+
console.log(chalk.dim(` - ${file}`));
|
|
253
|
+
}
|
|
254
|
+
console.log(chalk.bold("\nNext steps:"));
|
|
255
|
+
console.log(chalk.dim(" 1. Install dependencies:"));
|
|
256
|
+
console.log(chalk.cyan(" pnpm add clsx tailwind-merge class-variance-authority"));
|
|
257
|
+
console.log(chalk.cyan(" pnpm add react-aria react-aria-components motion"));
|
|
258
|
+
console.log(chalk.dim(" 2. Start adding components:"));
|
|
259
|
+
console.log(chalk.cyan(" npx inai-react-components add button"));
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
spinner.fail("Initialization failed.");
|
|
263
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
264
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
265
|
+
process.exit(1);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RegistryComponent } from "./status.js";
|
|
2
|
+
export interface ListOptions {
|
|
3
|
+
category?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function formatComponentTable(components: RegistryComponent[], filterCategory?: string): string;
|
|
6
|
+
export declare function runList(registryPath: string, options: ListOptions): Promise<string>;
|
|
7
|
+
export declare function listCommand(options: ListOptions): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAGA,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGvE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAOD,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,iBAAiB,EAAE,EAC/B,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CA6CR;AAED,wBAAsB,OAAO,CAC3B,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBrE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { readRegistryJson } from "./status.js";
|
|
5
|
+
import { resolveRegistryDir } from "../utils/registry-resolver.js";
|
|
6
|
+
function padRight(str, len) {
|
|
7
|
+
if (str.length >= len)
|
|
8
|
+
return str;
|
|
9
|
+
return str + " ".repeat(len - str.length);
|
|
10
|
+
}
|
|
11
|
+
export function formatComponentTable(components, filterCategory) {
|
|
12
|
+
let filtered = components;
|
|
13
|
+
if (filterCategory) {
|
|
14
|
+
filtered = components.filter((c) => c.type.toLowerCase() === filterCategory.toLowerCase());
|
|
15
|
+
}
|
|
16
|
+
if (filtered.length === 0) {
|
|
17
|
+
if (filterCategory) {
|
|
18
|
+
return chalk.yellow(`No components found with category "${filterCategory}".`);
|
|
19
|
+
}
|
|
20
|
+
return chalk.yellow("No components found in registry.");
|
|
21
|
+
}
|
|
22
|
+
const title = filterCategory
|
|
23
|
+
? `${chalk.bold("Components")} (category: ${filterCategory})`
|
|
24
|
+
: chalk.bold("All Components");
|
|
25
|
+
const countInfo = chalk.dim(`${filtered.length} component${filtered.length === 1 ? "" : "s"}`);
|
|
26
|
+
const header = `${title} ${countInfo}\n`;
|
|
27
|
+
const separator = chalk.dim("─".repeat(80)) + "\n";
|
|
28
|
+
const columnHeader = chalk.bold(padRight("Name", 22)) +
|
|
29
|
+
chalk.bold(padRight("Type", 14)) +
|
|
30
|
+
chalk.bold("Description") +
|
|
31
|
+
"\n";
|
|
32
|
+
let rows = "";
|
|
33
|
+
for (const comp of filtered) {
|
|
34
|
+
const description = comp.description.length > 42
|
|
35
|
+
? comp.description.slice(0, 39) + "..."
|
|
36
|
+
: comp.description;
|
|
37
|
+
rows +=
|
|
38
|
+
chalk.cyan(padRight(comp.name, 22)) +
|
|
39
|
+
padRight(comp.type, 14) +
|
|
40
|
+
chalk.dim(description) +
|
|
41
|
+
"\n";
|
|
42
|
+
}
|
|
43
|
+
return header + separator + columnHeader + separator + rows;
|
|
44
|
+
}
|
|
45
|
+
export async function runList(registryPath, options) {
|
|
46
|
+
const registry = readRegistryJson(registryPath);
|
|
47
|
+
if (!registry) {
|
|
48
|
+
return chalk.red(`Registry not found at ${registryPath}. Ensure you are in the project root.`);
|
|
49
|
+
}
|
|
50
|
+
const allItems = [
|
|
51
|
+
...registry.components,
|
|
52
|
+
...registry.blocks,
|
|
53
|
+
...registry.templates,
|
|
54
|
+
];
|
|
55
|
+
return formatComponentTable(allItems, options.category);
|
|
56
|
+
}
|
|
57
|
+
export async function listCommand(options) {
|
|
58
|
+
const spinner = ora("Loading component registry...").start();
|
|
59
|
+
try {
|
|
60
|
+
const rootDir = process.cwd();
|
|
61
|
+
const registryDir = resolveRegistryDir(rootDir);
|
|
62
|
+
const registryPath = path.join(registryDir, "registry.json");
|
|
63
|
+
const output = await runList(registryPath, options);
|
|
64
|
+
spinner.stop();
|
|
65
|
+
console.log(output);
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
spinner.fail("Failed to load registry.");
|
|
69
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
70
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface ComponentsJsonFile {
|
|
2
|
+
$schema: string;
|
|
3
|
+
style: string;
|
|
4
|
+
tailwind: {
|
|
5
|
+
config: string;
|
|
6
|
+
css: string;
|
|
7
|
+
};
|
|
8
|
+
aliases: {
|
|
9
|
+
components: string;
|
|
10
|
+
blocks: string;
|
|
11
|
+
utils: string;
|
|
12
|
+
};
|
|
13
|
+
registrySource?: string;
|
|
14
|
+
theme: string;
|
|
15
|
+
tanstack: {
|
|
16
|
+
router: boolean;
|
|
17
|
+
query: boolean;
|
|
18
|
+
form: boolean;
|
|
19
|
+
table: boolean;
|
|
20
|
+
};
|
|
21
|
+
installedComponents?: InstalledComponent[];
|
|
22
|
+
}
|
|
23
|
+
export interface InstalledComponent {
|
|
24
|
+
name: string;
|
|
25
|
+
version: string;
|
|
26
|
+
installedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export interface RegistryJson {
|
|
29
|
+
version: string;
|
|
30
|
+
components: RegistryComponent[];
|
|
31
|
+
blocks: RegistryComponent[];
|
|
32
|
+
templates: RegistryComponent[];
|
|
33
|
+
}
|
|
34
|
+
export interface RegistryComponent {
|
|
35
|
+
name: string;
|
|
36
|
+
type: string;
|
|
37
|
+
description: string;
|
|
38
|
+
files: string[];
|
|
39
|
+
npmDeps: string[];
|
|
40
|
+
internalDeps: string[];
|
|
41
|
+
tokenUsage: string[];
|
|
42
|
+
tanstackCompatibility: Record<string, boolean>;
|
|
43
|
+
fieldWrappers?: string[];
|
|
44
|
+
}
|
|
45
|
+
export declare function readComponentsJson(rootDir: string): ComponentsJsonFile | null;
|
|
46
|
+
export declare function readRegistryJson(registryPath: string): RegistryJson | null;
|
|
47
|
+
export declare function formatStatusTable(installedComponents: InstalledComponent[], registryVersion: string): string;
|
|
48
|
+
export declare function runStatus(rootDir: string): Promise<string>;
|
|
49
|
+
export declare function statusCommand(): Promise<void>;
|
|
50
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QACR,MAAM,EAAE,OAAO,CAAC;QAChB,KAAK,EAAE,OAAO,CAAC;QACf,IAAI,EAAE,OAAO,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;KAChB,CAAC;IACF,mBAAmB,CAAC,EAAE,kBAAkB,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,iBAAiB,EAAE,CAAC;IAChC,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,SAAS,EAAE,iBAAiB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI,CAO7E;AAED,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAM1E;AAED,wBAAgB,iBAAiB,CAC/B,mBAAmB,EAAE,kBAAkB,EAAE,EACzC,eAAe,EAAE,MAAM,GACtB,MAAM,CAuBR;AAOD,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBhE;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CAcnD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
export function readComponentsJson(rootDir) {
|
|
6
|
+
const filePath = path.join(rootDir, "components.json");
|
|
7
|
+
if (!fs.existsSync(filePath)) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
export function readRegistryJson(registryPath) {
|
|
14
|
+
if (!fs.existsSync(registryPath)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
const raw = fs.readFileSync(registryPath, "utf-8");
|
|
18
|
+
return JSON.parse(raw);
|
|
19
|
+
}
|
|
20
|
+
export function formatStatusTable(installedComponents, registryVersion) {
|
|
21
|
+
if (installedComponents.length === 0) {
|
|
22
|
+
return chalk.yellow("No components installed yet. Run `inai-ui add` to get started.");
|
|
23
|
+
}
|
|
24
|
+
const header = `${chalk.bold("Installed Components")} (registry v${registryVersion})\n`;
|
|
25
|
+
const separator = chalk.dim("─".repeat(60)) + "\n";
|
|
26
|
+
const columnHeader = chalk.bold(padRight("Component", 20)) +
|
|
27
|
+
chalk.bold(padRight("Version", 15)) +
|
|
28
|
+
chalk.bold("Installed At") +
|
|
29
|
+
"\n";
|
|
30
|
+
let rows = "";
|
|
31
|
+
for (const comp of installedComponents) {
|
|
32
|
+
rows +=
|
|
33
|
+
chalk.cyan(padRight(comp.name, 20)) +
|
|
34
|
+
padRight(comp.version, 15) +
|
|
35
|
+
chalk.dim(comp.installedAt) +
|
|
36
|
+
"\n";
|
|
37
|
+
}
|
|
38
|
+
return header + separator + columnHeader + separator + rows;
|
|
39
|
+
}
|
|
40
|
+
function padRight(str, len) {
|
|
41
|
+
if (str.length >= len)
|
|
42
|
+
return str;
|
|
43
|
+
return str + " ".repeat(len - str.length);
|
|
44
|
+
}
|
|
45
|
+
export async function runStatus(rootDir) {
|
|
46
|
+
const componentsJson = readComponentsJson(rootDir);
|
|
47
|
+
if (!componentsJson) {
|
|
48
|
+
return chalk.red("No components.json found. Run `inai-ui init` first to initialize your project.");
|
|
49
|
+
}
|
|
50
|
+
const { resolveRegistryDir } = await import("../utils/registry-resolver.js");
|
|
51
|
+
const registryDir = resolveRegistryDir(rootDir);
|
|
52
|
+
const registryPath = path.join(registryDir, "registry.json");
|
|
53
|
+
const registry = readRegistryJson(registryPath);
|
|
54
|
+
const registryVersion = registry?.version ?? "unknown";
|
|
55
|
+
const installed = componentsJson.installedComponents ?? [];
|
|
56
|
+
return formatStatusTable(installed, registryVersion);
|
|
57
|
+
}
|
|
58
|
+
export async function statusCommand() {
|
|
59
|
+
const spinner = ora("Reading project configuration...").start();
|
|
60
|
+
try {
|
|
61
|
+
const rootDir = process.cwd();
|
|
62
|
+
const output = await runStatus(rootDir);
|
|
63
|
+
spinner.stop();
|
|
64
|
+
console.log(output);
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
spinner.fail("Failed to read project status.");
|
|
68
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
69
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAKA,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAwBjD"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import ora from "ora";
|
|
3
|
+
import { readComponentsJson } from "./status.js";
|
|
4
|
+
import { cloneRegistry } from "../utils/registry-resolver.js";
|
|
5
|
+
export async function syncCommand() {
|
|
6
|
+
const rootDir = process.cwd();
|
|
7
|
+
const componentsJson = readComponentsJson(rootDir);
|
|
8
|
+
if (!componentsJson?.registrySource) {
|
|
9
|
+
console.log(chalk.yellow("No remote registry configured. Run `inai-ui init <repo-url>` first."));
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
const spinner = ora("Syncing registry from remote...").start();
|
|
13
|
+
try {
|
|
14
|
+
cloneRegistry(componentsJson.registrySource);
|
|
15
|
+
spinner.succeed("Registry synced successfully!");
|
|
16
|
+
}
|
|
17
|
+
catch (error) {
|
|
18
|
+
spinner.fail("Failed to sync registry.");
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ThemeCreateOptions {
|
|
2
|
+
name: string;
|
|
3
|
+
base: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function resolveThemesDir(rootDir: string): string;
|
|
6
|
+
export declare function readBaseTheme(themesDir: string, baseName: string): string | null;
|
|
7
|
+
export declare function generateThemeCss(baseCss: string, newName: string, baseName: string): string;
|
|
8
|
+
export declare function runThemeCreate(options: ThemeCreateOptions, rootDir: string): Promise<{
|
|
9
|
+
success: boolean;
|
|
10
|
+
filePath: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function themeCreateCommand(options: ThemeCreateOptions): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=theme.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../../src/commands/theme.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMhF;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAgB3F;AAED,wBAAsB,cAAc,CAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAoDlE;AAED,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBnF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
const AVAILABLE_THEMES = ["monday", "linear", "notion", "vercel"];
|
|
6
|
+
export function resolveThemesDir(rootDir) {
|
|
7
|
+
return path.join(rootDir, "packages", "tokens", "src", "themes");
|
|
8
|
+
}
|
|
9
|
+
export function readBaseTheme(themesDir, baseName) {
|
|
10
|
+
const basePath = path.join(themesDir, `${baseName}.css`);
|
|
11
|
+
if (!fs.existsSync(basePath)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return fs.readFileSync(basePath, "utf-8");
|
|
15
|
+
}
|
|
16
|
+
export function generateThemeCss(baseCss, newName, baseName) {
|
|
17
|
+
// Replace the header comment with the new theme name
|
|
18
|
+
const capitalized = newName.charAt(0).toUpperCase() + newName.slice(1);
|
|
19
|
+
const baseCapitalized = baseName.charAt(0).toUpperCase() + baseName.slice(1);
|
|
20
|
+
let output = baseCss;
|
|
21
|
+
// Replace the theme name in the top comment block
|
|
22
|
+
const commentPattern = /\/\*[\s\S]*?\*\//;
|
|
23
|
+
const match = output.match(commentPattern);
|
|
24
|
+
if (match) {
|
|
25
|
+
const newComment = `/*\n * ${capitalized} Theme (Custom)\n * Based on ${baseCapitalized} theme\n * Generated by company-ui CLI\n * OKLCH color space with .dark class toggle\n */`;
|
|
26
|
+
output = output.replace(commentPattern, newComment);
|
|
27
|
+
}
|
|
28
|
+
return output;
|
|
29
|
+
}
|
|
30
|
+
export async function runThemeCreate(options, rootDir) {
|
|
31
|
+
const { name, base } = options;
|
|
32
|
+
if (!name || name.trim().length === 0) {
|
|
33
|
+
return {
|
|
34
|
+
success: false,
|
|
35
|
+
filePath: "",
|
|
36
|
+
message: "Theme name is required.",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const validBases = [...AVAILABLE_THEMES];
|
|
40
|
+
if (!validBases.includes(base)) {
|
|
41
|
+
return {
|
|
42
|
+
success: false,
|
|
43
|
+
filePath: "",
|
|
44
|
+
message: `Invalid base theme "${base}". Available themes: ${AVAILABLE_THEMES.join(", ")}`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
const themesDir = resolveThemesDir(rootDir);
|
|
48
|
+
const baseCss = readBaseTheme(themesDir, base);
|
|
49
|
+
if (baseCss === null) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
filePath: "",
|
|
53
|
+
message: `Base theme file not found: ${path.join(themesDir, `${base}.css`)}`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const outputFileName = `${name}.css`;
|
|
57
|
+
const outputPath = path.join(themesDir, outputFileName);
|
|
58
|
+
if (fs.existsSync(outputPath)) {
|
|
59
|
+
return {
|
|
60
|
+
success: false,
|
|
61
|
+
filePath: outputPath,
|
|
62
|
+
message: `Theme file "${outputFileName}" already exists at ${themesDir}.`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const themeCss = generateThemeCss(baseCss, name, base);
|
|
66
|
+
fs.mkdirSync(themesDir, { recursive: true });
|
|
67
|
+
fs.writeFileSync(outputPath, themeCss);
|
|
68
|
+
return {
|
|
69
|
+
success: true,
|
|
70
|
+
filePath: outputPath,
|
|
71
|
+
message: `Theme "${name}" created at ${outputPath}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
export async function themeCreateCommand(options) {
|
|
75
|
+
const spinner = ora(`Creating theme "${options.name}" based on "${options.base}"...`).start();
|
|
76
|
+
try {
|
|
77
|
+
const rootDir = process.cwd();
|
|
78
|
+
const result = await runThemeCreate(options, rootDir);
|
|
79
|
+
if (result.success) {
|
|
80
|
+
spinner.succeed(result.message);
|
|
81
|
+
console.log(chalk.dim(`\nTo use this theme, import it in your CSS:`));
|
|
82
|
+
console.log(chalk.cyan(` @import "@company/tokens/themes/${options.name}.css";`));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
spinner.fail(result.message);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
spinner.fail("Theme creation failed.");
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface UpdateResult {
|
|
2
|
+
updated: boolean;
|
|
3
|
+
message: string;
|
|
4
|
+
files: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function runUpdate(componentName: string, rootDir: string, skipPrompts?: boolean): Promise<UpdateResult>;
|
|
7
|
+
export declare function updateCommand(componentName: string): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,wBAAsB,SAAS,CAC7B,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,EACf,WAAW,UAAQ,GAClB,OAAO,CAAC,YAAY,CAAC,CAgIvB;AAED,wBAAsB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBxE"}
|