@frontic/ui 0.3.1 → 0.5.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/api-DmrBFC4C.d.ts +313 -0
- package/dist/api-DmrBFC4C.d.ts.map +1 -0
- package/dist/index-Cd5RBhtD.d.ts +1480 -0
- package/dist/index-Cd5RBhtD.d.ts.map +1 -0
- package/dist/index.d.ts +4 -6
- package/dist/index.js +2411 -555
- package/dist/index.js.map +1 -1
- package/dist/mcp/index.d.ts +46 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +5 -0
- package/dist/mcp-CxUIP4Qu.js +304 -0
- package/dist/mcp-CxUIP4Qu.js.map +1 -0
- package/dist/registry/index.d.ts +113 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +4 -0
- package/dist/registry-CgE-Q6HO.js +2638 -0
- package/dist/registry-CgE-Q6HO.js.map +1 -0
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema-DgHN-d0T.js +155 -0
- package/dist/schema-DgHN-d0T.js.map +1 -0
- package/package.json +68 -14
- package/dist/bin/frontic-ui.js +0 -590
- package/dist/bin/frontic-ui.js.map +0 -1
package/dist/bin/frontic-ui.js
DELETED
|
@@ -1,590 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// src/index.ts
|
|
4
|
-
import { Command } from "commander";
|
|
5
|
-
|
|
6
|
-
// src/commands/init.ts
|
|
7
|
-
import chalk from "chalk";
|
|
8
|
-
import ora from "ora";
|
|
9
|
-
import prompts from "prompts";
|
|
10
|
-
import { join as join2 } from "path";
|
|
11
|
-
|
|
12
|
-
// src/utils/spawn-shadcn.ts
|
|
13
|
-
import { execa } from "execa";
|
|
14
|
-
async function spawnShadcn(args, options = {}) {
|
|
15
|
-
const { silent = false, filterOutput = false } = options;
|
|
16
|
-
try {
|
|
17
|
-
if (filterOutput) {
|
|
18
|
-
const proc = execa("npx", ["shadcn-vue@latest", ...args], {
|
|
19
|
-
stdio: ["inherit", "pipe", "pipe"],
|
|
20
|
-
shell: true
|
|
21
|
-
});
|
|
22
|
-
proc.stdout?.on("data", (data) => {
|
|
23
|
-
process.stdout.write(
|
|
24
|
-
data.toString().replace(/shadcn-vue/gi, "frontic-ui")
|
|
25
|
-
);
|
|
26
|
-
});
|
|
27
|
-
proc.stderr?.on("data", (data) => {
|
|
28
|
-
process.stderr.write(
|
|
29
|
-
data.toString().replace(/shadcn-vue/gi, "frontic-ui")
|
|
30
|
-
);
|
|
31
|
-
});
|
|
32
|
-
await proc;
|
|
33
|
-
} else {
|
|
34
|
-
await execa("npx", ["shadcn-vue@latest", ...args], {
|
|
35
|
-
stdio: silent ? "pipe" : "inherit",
|
|
36
|
-
shell: true
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
} catch (error) {
|
|
40
|
-
if (!silent) {
|
|
41
|
-
throw error;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// src/utils/config.ts
|
|
47
|
-
import { readFile, writeFile, access } from "fs/promises";
|
|
48
|
-
import { join } from "path";
|
|
49
|
-
|
|
50
|
-
// src/utils/constants.ts
|
|
51
|
-
var FRONTIC_REGISTRY_URL = process.env.FRONTIC_REGISTRY_LOCAL === "1" ? "http://localhost:3333/r/{name}.json" : "https://registry.frontic.io/r/{name}.json";
|
|
52
|
-
var CONFIG_FILE = "components.json";
|
|
53
|
-
var DEFAULT_BRAND_COLOR = "oklch(58% 0.25 265)";
|
|
54
|
-
var DEFAULT_RADIUS = "0.5rem";
|
|
55
|
-
var RADIUS_OPTIONS = {
|
|
56
|
-
none: "0",
|
|
57
|
-
small: "0.3rem",
|
|
58
|
-
medium: "0.5rem",
|
|
59
|
-
large: "0.75rem",
|
|
60
|
-
full: "1rem"
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
// src/utils/config.ts
|
|
64
|
-
async function configExists() {
|
|
65
|
-
try {
|
|
66
|
-
await access(join(process.cwd(), CONFIG_FILE));
|
|
67
|
-
return true;
|
|
68
|
-
} catch {
|
|
69
|
-
return false;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async function readConfig() {
|
|
73
|
-
try {
|
|
74
|
-
const content = await readFile(join(process.cwd(), CONFIG_FILE), "utf-8");
|
|
75
|
-
return JSON.parse(content);
|
|
76
|
-
} catch {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
async function writeConfig(config) {
|
|
81
|
-
await writeFile(
|
|
82
|
-
join(process.cwd(), CONFIG_FILE),
|
|
83
|
-
JSON.stringify(config, null, 2)
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
async function updateConfig(updates) {
|
|
87
|
-
const existing = await readConfig();
|
|
88
|
-
if (!existing) {
|
|
89
|
-
throw new Error(
|
|
90
|
-
"components.json not found. Run `npx @frontic/ui init` first."
|
|
91
|
-
);
|
|
92
|
-
}
|
|
93
|
-
const merged = deepMerge(existing, updates);
|
|
94
|
-
await writeConfig(merged);
|
|
95
|
-
}
|
|
96
|
-
async function ensureFronticRegistry() {
|
|
97
|
-
const config = await readConfig();
|
|
98
|
-
if (!config) {
|
|
99
|
-
throw new Error("components.json not found");
|
|
100
|
-
}
|
|
101
|
-
if (config.registries?.["@frontic"]?.url === FRONTIC_REGISTRY_URL) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
await updateConfig({
|
|
105
|
-
registries: {
|
|
106
|
-
...config.registries,
|
|
107
|
-
"@frontic": {
|
|
108
|
-
url: FRONTIC_REGISTRY_URL
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
function deepMerge(target, source) {
|
|
114
|
-
const result = { ...target };
|
|
115
|
-
for (const key in source) {
|
|
116
|
-
const sourceValue = source[key];
|
|
117
|
-
const targetValue = target[key];
|
|
118
|
-
if (sourceValue && typeof sourceValue === "object" && !Array.isArray(sourceValue) && targetValue && typeof targetValue === "object" && !Array.isArray(targetValue)) {
|
|
119
|
-
result[key] = deepMerge(
|
|
120
|
-
targetValue,
|
|
121
|
-
sourceValue
|
|
122
|
-
);
|
|
123
|
-
} else {
|
|
124
|
-
result[key] = sourceValue;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// src/utils/colors.ts
|
|
131
|
-
function isValidHex(hex) {
|
|
132
|
-
const cleanHex = hex.replace(/^#/, "");
|
|
133
|
-
return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);
|
|
134
|
-
}
|
|
135
|
-
function normalizeHex(hex) {
|
|
136
|
-
const cleanHex = hex.replace(/^#/, "");
|
|
137
|
-
if (cleanHex.length === 3) {
|
|
138
|
-
return cleanHex.split("").map((c) => c + c).join("");
|
|
139
|
-
}
|
|
140
|
-
return cleanHex;
|
|
141
|
-
}
|
|
142
|
-
function hexToRgb(hex) {
|
|
143
|
-
const normalizedHex = normalizeHex(hex);
|
|
144
|
-
return {
|
|
145
|
-
r: parseInt(normalizedHex.slice(0, 2), 16),
|
|
146
|
-
g: parseInt(normalizedHex.slice(2, 4), 16),
|
|
147
|
-
b: parseInt(normalizedHex.slice(4, 6), 16)
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
function srgbToLinear(value) {
|
|
151
|
-
const normalized = value / 255;
|
|
152
|
-
return normalized <= 0.04045 ? normalized / 12.92 : Math.pow((normalized + 0.055) / 1.055, 2.4);
|
|
153
|
-
}
|
|
154
|
-
function linearRgbToXyz(r, g, b) {
|
|
155
|
-
return {
|
|
156
|
-
x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,
|
|
157
|
-
y: 0.2126729 * r + 0.7151522 * g + 0.072175 * b,
|
|
158
|
-
z: 0.0193339 * r + 0.119192 * g + 0.9503041 * b
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
function xyzToOklab(x, y, z) {
|
|
162
|
-
const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);
|
|
163
|
-
const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);
|
|
164
|
-
const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.633851707 * z);
|
|
165
|
-
return {
|
|
166
|
-
l: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
|
|
167
|
-
a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
|
|
168
|
-
b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
function oklabToOklch(l, a, b) {
|
|
172
|
-
const c = Math.sqrt(a * a + b * b);
|
|
173
|
-
let h = Math.atan2(b, a) * (180 / Math.PI);
|
|
174
|
-
if (h < 0) h += 360;
|
|
175
|
-
return { l, c, h };
|
|
176
|
-
}
|
|
177
|
-
function hexToOklch(hex) {
|
|
178
|
-
if (!isValidHex(hex)) {
|
|
179
|
-
throw new Error(`Invalid hex color: ${hex}`);
|
|
180
|
-
}
|
|
181
|
-
const { r, g, b } = hexToRgb(hex);
|
|
182
|
-
const linearR = srgbToLinear(r);
|
|
183
|
-
const linearG = srgbToLinear(g);
|
|
184
|
-
const linearB = srgbToLinear(b);
|
|
185
|
-
const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);
|
|
186
|
-
const oklab = xyzToOklab(x, y, z);
|
|
187
|
-
const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);
|
|
188
|
-
const lightness = Math.round(l * 100);
|
|
189
|
-
const chroma = Math.round(c * 100) / 100;
|
|
190
|
-
const hue = Math.round(h);
|
|
191
|
-
return `oklch(${lightness}% ${chroma} ${hue})`;
|
|
192
|
-
}
|
|
193
|
-
function getForegroundColor(oklchOrHex) {
|
|
194
|
-
let lightness;
|
|
195
|
-
if (oklchOrHex.startsWith("oklch")) {
|
|
196
|
-
const match = oklchOrHex.match(/oklch\((\d+)%/);
|
|
197
|
-
lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;
|
|
198
|
-
} else {
|
|
199
|
-
const oklch = hexToOklch(oklchOrHex);
|
|
200
|
-
const match = oklch.match(/oklch\((\d+)%/);
|
|
201
|
-
lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;
|
|
202
|
-
}
|
|
203
|
-
return lightness > 0.6 ? "oklch(20% 0 0)" : "oklch(100% 0 0)";
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// src/utils/css.ts
|
|
207
|
-
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
208
|
-
function upsertCssVar(content, varName, value) {
|
|
209
|
-
const varRegex = new RegExp(`(${varName}\\s*:\\s*)([^;]+)(;)`, "g");
|
|
210
|
-
if (varRegex.test(content)) {
|
|
211
|
-
return content.replace(varRegex, `$1${value}$3`);
|
|
212
|
-
} else {
|
|
213
|
-
return content.trimEnd() + `
|
|
214
|
-
${varName}: ${value};`;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
async function injectCssVars(cssPath, vars) {
|
|
218
|
-
const content = await readFile2(cssPath, "utf-8");
|
|
219
|
-
const rootRegex = /:root\s*\{([^}]*)\}/;
|
|
220
|
-
const match = content.match(rootRegex);
|
|
221
|
-
if (match && match[1] !== void 0) {
|
|
222
|
-
let rootContent = match[1];
|
|
223
|
-
rootContent = upsertCssVar(rootContent, "--brand", vars.brand);
|
|
224
|
-
rootContent = upsertCssVar(
|
|
225
|
-
rootContent,
|
|
226
|
-
"--brand-foreground",
|
|
227
|
-
vars.brandForeground
|
|
228
|
-
);
|
|
229
|
-
rootContent = upsertCssVar(rootContent, "--radius", vars.radius);
|
|
230
|
-
const newContent = content.replace(rootRegex, `:root {${rootContent}
|
|
231
|
-
}`);
|
|
232
|
-
await writeFile2(cssPath, newContent);
|
|
233
|
-
} else {
|
|
234
|
-
const rootBlock = `:root {
|
|
235
|
-
--brand: ${vars.brand};
|
|
236
|
-
--brand-foreground: ${vars.brandForeground};
|
|
237
|
-
--radius: ${vars.radius};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
`;
|
|
241
|
-
await writeFile2(cssPath, rootBlock + content);
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// src/commands/init.ts
|
|
246
|
-
function registerInitCommand(program2) {
|
|
247
|
-
program2.command("init").description("Initialize Frontic UI in your Nuxt project").option("-y, --yes", "Skip confirmation prompts").option("-d, --defaults", "Use default configuration").option("-f, --force", "Force overwrite of existing configuration").option("-b, --brand <color>", "Brand color in hex format (e.g., #6366f1)").option(
|
|
248
|
-
"-r, --radius <option>",
|
|
249
|
-
"Border radius (none, small, medium, large, full)"
|
|
250
|
-
).action(async (options) => {
|
|
251
|
-
await init(options);
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
async function init(options) {
|
|
255
|
-
console.log();
|
|
256
|
-
console.log(chalk.bold("Frontic UI"));
|
|
257
|
-
console.log(chalk.dim("Initializing your project..."));
|
|
258
|
-
console.log();
|
|
259
|
-
const hasConfig = await configExists();
|
|
260
|
-
let brandColor = DEFAULT_BRAND_COLOR;
|
|
261
|
-
let radiusValue = DEFAULT_RADIUS;
|
|
262
|
-
if (!hasConfig) {
|
|
263
|
-
if (options.brand) {
|
|
264
|
-
if (isValidHex(options.brand)) {
|
|
265
|
-
brandColor = hexToOklch(options.brand);
|
|
266
|
-
console.log(
|
|
267
|
-
chalk.dim(`Using brand color: ${options.brand} \u2192 ${brandColor}`)
|
|
268
|
-
);
|
|
269
|
-
} else {
|
|
270
|
-
console.log(
|
|
271
|
-
chalk.yellow(`Invalid hex color: ${options.brand}, using default`)
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
if (options.radius) {
|
|
276
|
-
const radiusKey = options.radius.toLowerCase();
|
|
277
|
-
if (radiusKey in RADIUS_OPTIONS) {
|
|
278
|
-
radiusValue = RADIUS_OPTIONS[radiusKey];
|
|
279
|
-
console.log(chalk.dim(`Using border radius: ${options.radius}`));
|
|
280
|
-
} else {
|
|
281
|
-
console.log(
|
|
282
|
-
chalk.yellow(
|
|
283
|
-
`Invalid radius option: ${options.radius}, using default (medium)`
|
|
284
|
-
)
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
if (!options.yes && !options.defaults) {
|
|
289
|
-
const response = await prompts([
|
|
290
|
-
{
|
|
291
|
-
type: options.brand ? null : "text",
|
|
292
|
-
name: "brand",
|
|
293
|
-
message: "Brand color (hex, e.g., #6366f1)",
|
|
294
|
-
initial: "#6366f1",
|
|
295
|
-
validate: (value) => {
|
|
296
|
-
if (!value) return true;
|
|
297
|
-
return isValidHex(value) || "Please enter a valid hex color (e.g., #6366f1)";
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
type: options.radius ? null : "select",
|
|
302
|
-
name: "radius",
|
|
303
|
-
message: "Border radius",
|
|
304
|
-
choices: [
|
|
305
|
-
{ title: "None", value: "none" },
|
|
306
|
-
{ title: "Small", value: "small" },
|
|
307
|
-
{ title: "Medium (recommended)", value: "medium" },
|
|
308
|
-
{ title: "Large", value: "large" },
|
|
309
|
-
{ title: "Full", value: "full" }
|
|
310
|
-
],
|
|
311
|
-
initial: 2
|
|
312
|
-
}
|
|
313
|
-
]);
|
|
314
|
-
if (response.brand && isValidHex(response.brand)) {
|
|
315
|
-
brandColor = hexToOklch(response.brand);
|
|
316
|
-
console.log(chalk.dim(`Converted: ${response.brand} \u2192 ${brandColor}`));
|
|
317
|
-
}
|
|
318
|
-
if (response.radius) {
|
|
319
|
-
radiusValue = RADIUS_OPTIONS[response.radius];
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
console.log();
|
|
323
|
-
console.log(chalk.blue("Setting up your project..."));
|
|
324
|
-
console.log();
|
|
325
|
-
const args = ["init"];
|
|
326
|
-
if (options.yes) args.push("--yes");
|
|
327
|
-
if (options.defaults) args.push("--defaults");
|
|
328
|
-
if (options.force) args.push("--force");
|
|
329
|
-
try {
|
|
330
|
-
await spawnShadcn(args, { filterOutput: true });
|
|
331
|
-
} catch {
|
|
332
|
-
console.log();
|
|
333
|
-
console.log(chalk.red("Failed to initialize project."));
|
|
334
|
-
console.log();
|
|
335
|
-
console.log(chalk.yellow("Common issues:"));
|
|
336
|
-
console.log(
|
|
337
|
-
chalk.dim(
|
|
338
|
-
" \u2022 Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss"
|
|
339
|
-
)
|
|
340
|
-
);
|
|
341
|
-
console.log(chalk.dim(" \u2022 Not in a Vue/Nuxt project root directory"));
|
|
342
|
-
console.log(
|
|
343
|
-
chalk.dim(
|
|
344
|
-
" \u2022 Existing components.json with invalid config - try: npx @frontic/ui init --force"
|
|
345
|
-
)
|
|
346
|
-
);
|
|
347
|
-
console.log();
|
|
348
|
-
process.exit(1);
|
|
349
|
-
}
|
|
350
|
-
console.log();
|
|
351
|
-
}
|
|
352
|
-
const brandForeground = getForegroundColor(brandColor);
|
|
353
|
-
const config = await readConfig();
|
|
354
|
-
const cssPath = config?.tailwind?.css;
|
|
355
|
-
if (cssPath) {
|
|
356
|
-
const cssSpinner = ora("Injecting theme variables...").start();
|
|
357
|
-
try {
|
|
358
|
-
const fullCssPath = join2(process.cwd(), cssPath);
|
|
359
|
-
await injectCssVars(fullCssPath, {
|
|
360
|
-
brand: brandColor,
|
|
361
|
-
brandForeground,
|
|
362
|
-
radius: radiusValue
|
|
363
|
-
});
|
|
364
|
-
cssSpinner.succeed("Theme variables injected");
|
|
365
|
-
} catch {
|
|
366
|
-
cssSpinner.warn(
|
|
367
|
-
"Could not inject theme variables (you may need to add them manually)"
|
|
368
|
-
);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
const spinner = ora("Configuring Frontic registry...").start();
|
|
372
|
-
try {
|
|
373
|
-
await updateConfig({
|
|
374
|
-
registries: {
|
|
375
|
-
"@frontic": {
|
|
376
|
-
url: FRONTIC_REGISTRY_URL
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
spinner.succeed("Frontic registry configured");
|
|
381
|
-
} catch (error) {
|
|
382
|
-
spinner.fail("Failed to configure registry");
|
|
383
|
-
throw error;
|
|
384
|
-
}
|
|
385
|
-
const themeSpinner = ora("Installing Frontic theme...").start();
|
|
386
|
-
try {
|
|
387
|
-
await spawnShadcn(["add", "@frontic/theme", "--yes"], { silent: true });
|
|
388
|
-
themeSpinner.succeed("Frontic theme installed");
|
|
389
|
-
} catch {
|
|
390
|
-
themeSpinner.warn(
|
|
391
|
-
"Theme installation skipped (may already exist or registry not available)"
|
|
392
|
-
);
|
|
393
|
-
}
|
|
394
|
-
console.log();
|
|
395
|
-
console.log(chalk.green("\u2713 Frontic UI initialized successfully!"));
|
|
396
|
-
console.log();
|
|
397
|
-
console.log(chalk.dim("Your theme settings:"));
|
|
398
|
-
console.log(` --brand: ${chalk.cyan(brandColor)}`);
|
|
399
|
-
console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);
|
|
400
|
-
console.log(` --radius: ${chalk.cyan(radiusValue)}`);
|
|
401
|
-
console.log();
|
|
402
|
-
console.log("Next steps:");
|
|
403
|
-
console.log(chalk.dim(" 1. Add components:"));
|
|
404
|
-
console.log(` ${chalk.cyan("npx @frontic/ui add button")}`);
|
|
405
|
-
console.log();
|
|
406
|
-
console.log(chalk.dim(" 2. Set up MCP for AI assistants (optional):"));
|
|
407
|
-
console.log(` ${chalk.cyan("npx @frontic/ui mcp init")}`);
|
|
408
|
-
console.log();
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
// src/commands/add.ts
|
|
412
|
-
import chalk2 from "chalk";
|
|
413
|
-
import ora2 from "ora";
|
|
414
|
-
function resolveComponentNames(components) {
|
|
415
|
-
return components.map((component) => {
|
|
416
|
-
if (component.startsWith("@")) {
|
|
417
|
-
return component;
|
|
418
|
-
}
|
|
419
|
-
return `@frontic/${component}`;
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
function registerAddCommand(program2) {
|
|
423
|
-
program2.command("add").description("Add components to your project").argument("[components...]", "Components to add").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("-p, --path <path>", "Custom installation path").option("-y, --yes", "Skip confirmation prompts").action(async (components, options) => {
|
|
424
|
-
await add(components, options);
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
|
-
async function add(components, options) {
|
|
428
|
-
if (!options.all && components.length === 0) {
|
|
429
|
-
console.log(chalk2.red("Error: Please specify components to add or use --all"));
|
|
430
|
-
console.log();
|
|
431
|
-
console.log("Usage:");
|
|
432
|
-
console.log(` ${chalk2.cyan("npx @frontic/ui add button")}`);
|
|
433
|
-
console.log(` ${chalk2.cyan("npx @frontic/ui add button dialog card")}`);
|
|
434
|
-
console.log(` ${chalk2.cyan("npx @frontic/ui add --all")}`);
|
|
435
|
-
process.exit(1);
|
|
436
|
-
}
|
|
437
|
-
const spinner = ora2("Checking configuration...").start();
|
|
438
|
-
try {
|
|
439
|
-
await ensureFronticRegistry();
|
|
440
|
-
spinner.succeed("Configuration verified");
|
|
441
|
-
} catch {
|
|
442
|
-
spinner.fail("Configuration error");
|
|
443
|
-
console.log();
|
|
444
|
-
console.log(chalk2.yellow("Run `npx @frontic/ui init` first to set up your project."));
|
|
445
|
-
process.exit(1);
|
|
446
|
-
}
|
|
447
|
-
const resolvedComponents = resolveComponentNames(components);
|
|
448
|
-
if (resolvedComponents.length > 0) {
|
|
449
|
-
console.log(
|
|
450
|
-
chalk2.cyan("Components:"),
|
|
451
|
-
resolvedComponents.map((c) => c.replace("@frontic/", "")).join(", ")
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
const args = ["add"];
|
|
455
|
-
if (options.all) {
|
|
456
|
-
args.push("--all");
|
|
457
|
-
} else {
|
|
458
|
-
args.push(...resolvedComponents);
|
|
459
|
-
}
|
|
460
|
-
if (options.overwrite) {
|
|
461
|
-
args.push("--overwrite");
|
|
462
|
-
}
|
|
463
|
-
if (options.path) {
|
|
464
|
-
args.push("--path", options.path);
|
|
465
|
-
}
|
|
466
|
-
if (options.yes) {
|
|
467
|
-
args.push("--yes");
|
|
468
|
-
}
|
|
469
|
-
console.log();
|
|
470
|
-
console.log(chalk2.blue("Adding components..."));
|
|
471
|
-
console.log();
|
|
472
|
-
await spawnShadcn(args);
|
|
473
|
-
console.log();
|
|
474
|
-
console.log(chalk2.green("\u2713 Components added successfully!"));
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
// src/commands/mcp.ts
|
|
478
|
-
import chalk3 from "chalk";
|
|
479
|
-
import ora3 from "ora";
|
|
480
|
-
import { writeFile as writeFile3, readFile as readFile3, mkdir } from "fs/promises";
|
|
481
|
-
import { existsSync } from "fs";
|
|
482
|
-
import { join as join3 } from "path";
|
|
483
|
-
import prompts2 from "prompts";
|
|
484
|
-
function registerMcpCommand(program2) {
|
|
485
|
-
const mcp = program2.command("mcp").description("MCP (Model Context Protocol) commands");
|
|
486
|
-
mcp.command("init").description("Set up MCP for AI assistants").option("-c, --client <client>", "Target client (claude, cursor, vscode)").action(async (options) => {
|
|
487
|
-
await initMcp(options);
|
|
488
|
-
});
|
|
489
|
-
}
|
|
490
|
-
async function initMcp(options) {
|
|
491
|
-
console.log();
|
|
492
|
-
console.log(chalk3.bold("Frontic UI - MCP Setup"));
|
|
493
|
-
console.log(chalk3.dim("Configure AI assistant integration"));
|
|
494
|
-
console.log();
|
|
495
|
-
let client = options.client;
|
|
496
|
-
if (!client) {
|
|
497
|
-
const response = await prompts2({
|
|
498
|
-
type: "select",
|
|
499
|
-
name: "client",
|
|
500
|
-
message: "Select your AI client:",
|
|
501
|
-
choices: [
|
|
502
|
-
{ title: "Claude Code", value: "claude" },
|
|
503
|
-
{ title: "Cursor", value: "cursor" },
|
|
504
|
-
{ title: "VS Code", value: "vscode" }
|
|
505
|
-
]
|
|
506
|
-
});
|
|
507
|
-
client = response.client;
|
|
508
|
-
if (!client) {
|
|
509
|
-
console.log(chalk3.yellow("Setup cancelled."));
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
const spinner = ora3("Creating MCP configuration...").start();
|
|
514
|
-
try {
|
|
515
|
-
await createMcpConfig(client);
|
|
516
|
-
spinner.succeed("MCP configuration created");
|
|
517
|
-
} catch (error) {
|
|
518
|
-
spinner.fail("Failed to create MCP configuration");
|
|
519
|
-
throw error;
|
|
520
|
-
}
|
|
521
|
-
console.log();
|
|
522
|
-
console.log(chalk3.green("\u2713 MCP configured successfully!"));
|
|
523
|
-
console.log();
|
|
524
|
-
console.log("Your AI assistant can now:");
|
|
525
|
-
console.log(chalk3.dim(" \u2022 Browse available Frontic UI components"));
|
|
526
|
-
console.log(chalk3.dim(" \u2022 Add components using natural language"));
|
|
527
|
-
console.log(chalk3.dim(' \u2022 Example: "Add a button component"'));
|
|
528
|
-
console.log();
|
|
529
|
-
}
|
|
530
|
-
async function createMcpConfig(client) {
|
|
531
|
-
const config = getMcpConfig();
|
|
532
|
-
const configPath = getMcpConfigPath(client);
|
|
533
|
-
const configDir = join3(process.cwd(), configPath.split("/").slice(0, -1).join("/"));
|
|
534
|
-
if (!existsSync(configDir)) {
|
|
535
|
-
await mkdir(configDir, { recursive: true });
|
|
536
|
-
}
|
|
537
|
-
const fullPath = join3(process.cwd(), configPath);
|
|
538
|
-
let existingConfig = {};
|
|
539
|
-
try {
|
|
540
|
-
const content = await readFile3(fullPath, "utf-8");
|
|
541
|
-
existingConfig = JSON.parse(content);
|
|
542
|
-
} catch {
|
|
543
|
-
}
|
|
544
|
-
const mergedConfig = {
|
|
545
|
-
...existingConfig,
|
|
546
|
-
mcpServers: {
|
|
547
|
-
...existingConfig.mcpServers || {},
|
|
548
|
-
...config.mcpServers
|
|
549
|
-
}
|
|
550
|
-
};
|
|
551
|
-
await writeFile3(fullPath, JSON.stringify(mergedConfig, null, 2));
|
|
552
|
-
console.log(chalk3.dim(` Config written to: ${configPath}`));
|
|
553
|
-
}
|
|
554
|
-
function getMcpConfigPath(client) {
|
|
555
|
-
switch (client) {
|
|
556
|
-
case "claude":
|
|
557
|
-
return ".mcp.json";
|
|
558
|
-
case "cursor":
|
|
559
|
-
return ".cursor/mcp.json";
|
|
560
|
-
case "vscode":
|
|
561
|
-
return ".vscode/mcp.json";
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
function getMcpConfig() {
|
|
565
|
-
return {
|
|
566
|
-
mcpServers: {
|
|
567
|
-
"frontic-ui": {
|
|
568
|
-
command: "npx",
|
|
569
|
-
args: ["shadcn-vue@latest", "mcp"],
|
|
570
|
-
env: {
|
|
571
|
-
SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
// src/index.ts
|
|
579
|
-
var program = new Command();
|
|
580
|
-
program.name("frontic-ui").description("CLI for adding Frontic UI components to your Nuxt project").version("0.3.1");
|
|
581
|
-
registerInitCommand(program);
|
|
582
|
-
registerAddCommand(program);
|
|
583
|
-
registerMcpCommand(program);
|
|
584
|
-
function run() {
|
|
585
|
-
program.parse();
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
// bin/frontic-ui.ts
|
|
589
|
-
run();
|
|
590
|
-
//# sourceMappingURL=frontic-ui.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts","../../src/commands/init.ts","../../src/utils/spawn-shadcn.ts","../../src/utils/config.ts","../../src/utils/constants.ts","../../src/utils/colors.ts","../../src/utils/css.ts","../../src/commands/add.ts","../../src/commands/mcp.ts","../../bin/frontic-ui.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerInitCommand } from \"./commands/init.js\";\nimport { registerAddCommand } from \"./commands/add.js\";\nimport { registerMcpCommand } from \"./commands/mcp.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"frontic-ui\")\n .description(\"CLI for adding Frontic UI components to your Nuxt project\")\n .version(\"0.3.1\");\n\nregisterInitCommand(program);\nregisterAddCommand(program);\nregisterMcpCommand(program);\n\nexport function run() {\n program.parse();\n}\n\nexport { program };\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport prompts from \"prompts\";\nimport { join } from \"path\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { updateConfig, configExists, readConfig } from \"../utils/config.js\";\nimport {\n FRONTIC_REGISTRY_URL,\n DEFAULT_BRAND_COLOR,\n DEFAULT_RADIUS,\n RADIUS_OPTIONS,\n type RadiusOption,\n} from \"../utils/constants.js\";\nimport { hexToOklch, isValidHex, getForegroundColor } from \"../utils/colors.js\";\nimport { injectCssVars } from \"../utils/css.js\";\n\ninterface InitOptions {\n yes?: boolean;\n defaults?: boolean;\n force?: boolean;\n brand?: string;\n radius?: string;\n}\n\nexport function registerInitCommand(program: Command) {\n program\n .command(\"init\")\n .description(\"Initialize Frontic UI in your Nuxt project\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .option(\"-d, --defaults\", \"Use default configuration\")\n .option(\"-f, --force\", \"Force overwrite of existing configuration\")\n .option(\"-b, --brand <color>\", \"Brand color in hex format (e.g., #6366f1)\")\n .option(\n \"-r, --radius <option>\",\n \"Border radius (none, small, medium, large, full)\"\n )\n .action(async (options: InitOptions) => {\n await init(options);\n });\n}\n\nasync function init(options: InitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI\"));\n console.log(chalk.dim(\"Initializing your project...\"));\n console.log();\n\n const hasConfig = await configExists();\n\n // Collect preferences BEFORE running shadcn-vue init\n let brandColor = DEFAULT_BRAND_COLOR;\n let radiusValue = DEFAULT_RADIUS;\n\n if (!hasConfig) {\n // Get brand color from CLI flag or prompt\n if (options.brand) {\n if (isValidHex(options.brand)) {\n brandColor = hexToOklch(options.brand);\n console.log(\n chalk.dim(`Using brand color: ${options.brand} → ${brandColor}`)\n );\n } else {\n console.log(\n chalk.yellow(`Invalid hex color: ${options.brand}, using default`)\n );\n }\n }\n\n // Get radius from CLI flag or validate it\n if (options.radius) {\n const radiusKey = options.radius.toLowerCase() as RadiusOption;\n if (radiusKey in RADIUS_OPTIONS) {\n radiusValue = RADIUS_OPTIONS[radiusKey];\n console.log(chalk.dim(`Using border radius: ${options.radius}`));\n } else {\n console.log(\n chalk.yellow(\n `Invalid radius option: ${options.radius}, using default (medium)`\n )\n );\n }\n }\n\n // Interactive prompts if not using --yes or --defaults\n if (!options.yes && !options.defaults) {\n const response = await prompts([\n {\n type: options.brand ? null : \"text\",\n name: \"brand\",\n message: \"Brand color (hex, e.g., #6366f1)\",\n initial: \"#6366f1\",\n validate: (value: string) => {\n if (!value) return true;\n return (\n isValidHex(value) ||\n \"Please enter a valid hex color (e.g., #6366f1)\"\n );\n },\n },\n {\n type: options.radius ? null : \"select\",\n name: \"radius\",\n message: \"Border radius\",\n choices: [\n { title: \"None\", value: \"none\" },\n { title: \"Small\", value: \"small\" },\n { title: \"Medium (recommended)\", value: \"medium\" },\n { title: \"Large\", value: \"large\" },\n { title: \"Full\", value: \"full\" },\n ],\n initial: 2,\n },\n ]);\n\n if (response.brand && isValidHex(response.brand)) {\n brandColor = hexToOklch(response.brand);\n console.log(chalk.dim(`Converted: ${response.brand} → ${brandColor}`));\n }\n\n if (response.radius) {\n radiusValue = RADIUS_OPTIONS[response.radius as RadiusOption];\n }\n }\n\n // Now run shadcn-vue init with output filtering\n console.log();\n console.log(chalk.blue(\"Setting up your project...\"));\n console.log();\n\n const args = [\"init\"];\n if (options.yes) args.push(\"--yes\");\n if (options.defaults) args.push(\"--defaults\");\n if (options.force) args.push(\"--force\");\n\n try {\n await spawnShadcn(args, { filterOutput: true });\n } catch {\n console.log();\n console.log(chalk.red(\"Failed to initialize project.\"));\n console.log();\n console.log(chalk.yellow(\"Common issues:\"));\n console.log(\n chalk.dim(\n \" • Tailwind CSS not installed - run: npx nuxi module add @nuxtjs/tailwindcss\"\n )\n );\n console.log(chalk.dim(\" • Not in a Vue/Nuxt project root directory\"));\n console.log(\n chalk.dim(\n \" • Existing components.json with invalid config - try: npx @frontic/ui init --force\"\n )\n );\n console.log();\n process.exit(1);\n }\n console.log();\n }\n\n // Calculate foreground color based on brand\n const brandForeground = getForegroundColor(brandColor);\n\n // Read config to get CSS file path\n const config = await readConfig();\n const cssPath = config?.tailwind?.css;\n\n // Inject CSS variables into the user's CSS file\n if (cssPath) {\n const cssSpinner = ora(\"Injecting theme variables...\").start();\n try {\n const fullCssPath = join(process.cwd(), cssPath);\n await injectCssVars(fullCssPath, {\n brand: brandColor,\n brandForeground: brandForeground,\n radius: radiusValue,\n });\n cssSpinner.succeed(\"Theme variables injected\");\n } catch {\n cssSpinner.warn(\n \"Could not inject theme variables (you may need to add them manually)\"\n );\n }\n }\n\n // Update components.json with Frontic registry\n const spinner = ora(\"Configuring Frontic registry...\").start();\n\n try {\n await updateConfig({\n registries: {\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n spinner.succeed(\"Frontic registry configured\");\n } catch (error) {\n spinner.fail(\"Failed to configure registry\");\n throw error;\n }\n\n // Install Frontic theme from registry\n const themeSpinner = ora(\"Installing Frontic theme...\").start();\n try {\n await spawnShadcn([\"add\", \"@frontic/theme\", \"--yes\"], { silent: true });\n themeSpinner.succeed(\"Frontic theme installed\");\n } catch {\n themeSpinner.warn(\n \"Theme installation skipped (may already exist or registry not available)\"\n );\n }\n\n console.log();\n console.log(chalk.green(\"✓ Frontic UI initialized successfully!\"));\n console.log();\n console.log(chalk.dim(\"Your theme settings:\"));\n console.log(` --brand: ${chalk.cyan(brandColor)}`);\n console.log(` --brand-foreground: ${chalk.cyan(brandForeground)}`);\n console.log(` --radius: ${chalk.cyan(radiusValue)}`);\n console.log();\n console.log(\"Next steps:\");\n console.log(chalk.dim(\" 1. Add components:\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log();\n console.log(chalk.dim(\" 2. Set up MCP for AI assistants (optional):\"));\n console.log(` ${chalk.cyan(\"npx @frontic/ui mcp init\")}`);\n console.log();\n}\n","import { execa } from \"execa\";\n\ninterface SpawnOptions {\n silent?: boolean;\n filterOutput?: boolean;\n}\n\nexport async function spawnShadcn(\n args: string[],\n options: SpawnOptions = {}\n): Promise<void> {\n const { silent = false, filterOutput = false } = options;\n\n try {\n if (filterOutput) {\n // Capture output, replace \"shadcn-vue\" → \"frontic-ui\", forward to stdout\n const proc = execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: [\"inherit\", \"pipe\", \"pipe\"],\n shell: true,\n });\n\n proc.stdout?.on(\"data\", (data: Buffer) => {\n process.stdout.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n proc.stderr?.on(\"data\", (data: Buffer) => {\n process.stderr.write(\n data.toString().replace(/shadcn-vue/gi, \"frontic-ui\")\n );\n });\n\n await proc;\n } else {\n await execa(\"npx\", [\"shadcn-vue@latest\", ...args], {\n stdio: silent ? \"pipe\" : \"inherit\",\n shell: true,\n });\n }\n } catch (error) {\n if (!silent) {\n throw error;\n }\n // Silently ignore errors when silent mode is enabled\n }\n}\n","import { readFile, writeFile, access } from \"fs/promises\";\nimport { join } from \"path\";\nimport { CONFIG_FILE, FRONTIC_REGISTRY_URL } from \"./constants.js\";\n\nexport interface ComponentsConfig {\n $schema?: string;\n style?: string;\n typescript?: boolean;\n tailwind?: {\n css?: string;\n baseColor?: string;\n cssVariables?: boolean;\n };\n aliases?: {\n components?: string;\n utils?: string;\n ui?: string;\n lib?: string;\n composables?: string;\n };\n registries?: {\n [key: string]: {\n url: string;\n };\n };\n}\n\nexport async function configExists(): Promise<boolean> {\n try {\n await access(join(process.cwd(), CONFIG_FILE));\n return true;\n } catch {\n return false;\n }\n}\n\nexport async function readConfig(): Promise<ComponentsConfig | null> {\n try {\n const content = await readFile(join(process.cwd(), CONFIG_FILE), \"utf-8\");\n return JSON.parse(content);\n } catch {\n return null;\n }\n}\n\nexport async function writeConfig(config: ComponentsConfig): Promise<void> {\n await writeFile(\n join(process.cwd(), CONFIG_FILE),\n JSON.stringify(config, null, 2)\n );\n}\n\nexport async function updateConfig(\n updates: Partial<ComponentsConfig>\n): Promise<void> {\n const existing = await readConfig();\n\n if (!existing) {\n throw new Error(\n \"components.json not found. Run `npx @frontic/ui init` first.\"\n );\n }\n\n const merged = deepMerge(existing, updates);\n await writeConfig(merged);\n}\n\nexport async function ensureFronticRegistry(): Promise<void> {\n const config = await readConfig();\n\n if (!config) {\n throw new Error(\"components.json not found\");\n }\n\n // Check if Frontic registry is already configured\n if (config.registries?.[\"@frontic\"]?.url === FRONTIC_REGISTRY_URL) {\n return;\n }\n\n // Add Frontic registry\n await updateConfig({\n registries: {\n ...config.registries,\n \"@frontic\": {\n url: FRONTIC_REGISTRY_URL,\n },\n },\n });\n}\n\nfunction deepMerge<T extends object>(target: T, source: Partial<T>): T {\n const result = { ...target };\n\n for (const key in source) {\n const sourceValue = source[key];\n const targetValue = target[key];\n\n if (\n sourceValue &&\n typeof sourceValue === \"object\" &&\n !Array.isArray(sourceValue) &&\n targetValue &&\n typeof targetValue === \"object\" &&\n !Array.isArray(targetValue)\n ) {\n (result as Record<string, unknown>)[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>\n );\n } else {\n (result as Record<string, unknown>)[key] = sourceValue;\n }\n }\n\n return result;\n}\n","// Use FRONTIC_REGISTRY_LOCAL=1 to test with local registry\nexport const FRONTIC_REGISTRY_URL =\n process.env.FRONTIC_REGISTRY_LOCAL === \"1\"\n ? \"http://localhost:3333/r/{name}.json\"\n : \"https://registry.frontic.io/r/{name}.json\";\n\nexport const CONFIG_FILE = \"components.json\";\n\n// Default brand color (purple - similar to Indigo 500)\nexport const DEFAULT_BRAND_COLOR = \"oklch(58% 0.25 265)\";\n\n// Default radius (medium)\nexport const DEFAULT_RADIUS = \"0.5rem\";\n\n// Radius options for CLI prompt\n// These are base values for --radius. The derived Tailwind vars (--radius-sm, etc.)\n// are calculated by shadcn's @theme inline block using calc() offsets.\nexport const RADIUS_OPTIONS = {\n none: \"0\",\n small: \"0.3rem\",\n medium: \"0.5rem\",\n large: \"0.75rem\",\n full: \"1rem\",\n} as const;\n\nexport type RadiusOption = keyof typeof RADIUS_OPTIONS;\n","/**\n * Color conversion utilities for Frontic UI CLI\n * Converts hex colors to OKLCH format for CSS variables\n */\n\n/**\n * Validates a hex color string\n * Accepts formats: #RGB, #RRGGBB, RGB, RRGGBB\n */\nexport function isValidHex(hex: string): boolean {\n const cleanHex = hex.replace(/^#/, \"\");\n return /^([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6})$/.test(cleanHex);\n}\n\n/**\n * Normalizes a hex color to 6-character format without #\n */\nfunction normalizeHex(hex: string): string {\n const cleanHex = hex.replace(/^#/, \"\");\n if (cleanHex.length === 3) {\n return cleanHex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n return cleanHex;\n}\n\n/**\n * Converts hex color to RGB values (0-255)\n */\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n const normalizedHex = normalizeHex(hex);\n return {\n r: parseInt(normalizedHex.slice(0, 2), 16),\n g: parseInt(normalizedHex.slice(2, 4), 16),\n b: parseInt(normalizedHex.slice(4, 6), 16),\n };\n}\n\n/**\n * Converts sRGB to linear RGB\n */\nfunction srgbToLinear(value: number): number {\n const normalized = value / 255;\n return normalized <= 0.04045\n ? normalized / 12.92\n : Math.pow((normalized + 0.055) / 1.055, 2.4);\n}\n\n/**\n * Converts linear RGB to XYZ color space\n */\nfunction linearRgbToXyz(r: number, g: number, b: number): { x: number; y: number; z: number } {\n return {\n x: 0.4124564 * r + 0.3575761 * g + 0.1804375 * b,\n y: 0.2126729 * r + 0.7151522 * g + 0.0721750 * b,\n z: 0.0193339 * r + 0.1191920 * g + 0.9503041 * b,\n };\n}\n\n/**\n * Converts XYZ to OKLAB color space\n */\nfunction xyzToOklab(x: number, y: number, z: number): { l: number; a: number; b: number } {\n const l_ = Math.cbrt(0.8189330101 * x + 0.3618667424 * y - 0.1288597137 * z);\n const m_ = Math.cbrt(0.0329845436 * x + 0.9293118715 * y + 0.0361456387 * z);\n const s_ = Math.cbrt(-0.0482003018 * x + 0.2643662691 * y + 0.6338517070 * z);\n\n return {\n l: 0.2104542553 * l_ + 0.7936177850 * m_ - 0.0040720468 * s_,\n a: 1.9779984951 * l_ - 2.4285922050 * m_ + 0.4505937099 * s_,\n b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.8086757660 * s_,\n };\n}\n\n/**\n * Converts OKLAB to OKLCH color space\n */\nfunction oklabToOklch(l: number, a: number, b: number): { l: number; c: number; h: number } {\n const c = Math.sqrt(a * a + b * b);\n let h = Math.atan2(b, a) * (180 / Math.PI);\n if (h < 0) h += 360;\n\n return { l, c, h };\n}\n\n/**\n * Converts a hex color to OKLCH format string\n * @param hex - Hex color (e.g., \"#6366f1\" or \"6366f1\")\n * @returns OKLCH string (e.g., \"oklch(55% 0.24 265)\")\n */\nexport function hexToOklch(hex: string): string {\n if (!isValidHex(hex)) {\n throw new Error(`Invalid hex color: ${hex}`);\n }\n\n const { r, g, b } = hexToRgb(hex);\n\n // Convert to linear RGB\n const linearR = srgbToLinear(r);\n const linearG = srgbToLinear(g);\n const linearB = srgbToLinear(b);\n\n // Convert to XYZ\n const { x, y, z } = linearRgbToXyz(linearR, linearG, linearB);\n\n // Convert to OKLAB\n const oklab = xyzToOklab(x, y, z);\n\n // Convert to OKLCH\n const { l, c, h } = oklabToOklch(oklab.l, oklab.a, oklab.b);\n\n // Format as OKLCH string\n // Lightness as percentage, chroma with 2 decimals, hue as integer\n const lightness = Math.round(l * 100);\n const chroma = Math.round(c * 100) / 100;\n const hue = Math.round(h);\n\n return `oklch(${lightness}% ${chroma} ${hue})`;\n}\n\n/**\n * Calculates appropriate foreground color (black or white) based on background lightness\n * @param oklchOrHex - Either an OKLCH string or hex color\n * @returns OKLCH string for foreground (white or dark)\n */\nexport function getForegroundColor(oklchOrHex: string): string {\n let lightness: number;\n\n if (oklchOrHex.startsWith(\"oklch\")) {\n // Parse OKLCH string\n const match = oklchOrHex.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n } else {\n // Convert hex to get lightness\n const oklch = hexToOklch(oklchOrHex);\n const match = oklch.match(/oklch\\((\\d+)%/);\n lightness = match?.[1] ? parseInt(match[1], 10) / 100 : 0.5;\n }\n\n // Use white foreground for dark backgrounds, dark for light backgrounds\n return lightness > 0.6 ? \"oklch(20% 0 0)\" : \"oklch(100% 0 0)\";\n}\n","import { readFile, writeFile } from \"fs/promises\";\n\n/**\n * Upsert a CSS variable in a CSS content string.\n * If the variable exists, replace its value. If not, add it at the end.\n */\nfunction upsertCssVar(content: string, varName: string, value: string): string {\n const varRegex = new RegExp(`(${varName}\\\\s*:\\\\s*)([^;]+)(;)`, \"g\");\n\n if (varRegex.test(content)) {\n // Variable exists, replace its value\n return content.replace(varRegex, `$1${value}$3`);\n } else {\n // Variable doesn't exist, add it before the closing brace area\n // Add with proper indentation\n return content.trimEnd() + `\\n ${varName}: ${value};`;\n }\n}\n\n/**\n * Inject CSS variables into the :root block of a CSS file.\n * Handles both adding new variables and updating existing ones.\n */\nexport async function injectCssVars(\n cssPath: string,\n vars: { brand: string; brandForeground: string; radius: string }\n): Promise<void> {\n const content = await readFile(cssPath, \"utf-8\");\n\n // Match :root { ... } block - use a more robust pattern that handles nested content\n const rootRegex = /:root\\s*\\{([^}]*)\\}/;\n const match = content.match(rootRegex);\n\n if (match && match[1] !== undefined) {\n let rootContent = match[1];\n\n // Add or replace --brand, --brand-foreground, --radius\n rootContent = upsertCssVar(rootContent, \"--brand\", vars.brand);\n rootContent = upsertCssVar(\n rootContent,\n \"--brand-foreground\",\n vars.brandForeground\n );\n rootContent = upsertCssVar(rootContent, \"--radius\", vars.radius);\n\n const newContent = content.replace(rootRegex, `:root {${rootContent}\\n}`);\n await writeFile(cssPath, newContent);\n } else {\n // No :root block found, create one at the beginning\n const rootBlock = `:root {\n --brand: ${vars.brand};\n --brand-foreground: ${vars.brandForeground};\n --radius: ${vars.radius};\n}\n\n`;\n await writeFile(cssPath, rootBlock + content);\n }\n}\n\n/**\n * Get the CSS file path from components.json config.\n */\nexport function getCssPathFromConfig(config: {\n tailwind?: { css?: string };\n}): string | null {\n return config.tailwind?.css || null;\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { spawnShadcn } from \"../utils/spawn-shadcn.js\";\nimport { ensureFronticRegistry } from \"../utils/config.js\";\n\ninterface AddOptions {\n overwrite?: boolean;\n all?: boolean;\n path?: string;\n yes?: boolean;\n}\n\n/**\n * Resolves component names to their @frontic/ prefixed form.\n *\n * All components go through the Frontic registry proxy which:\n * - Serves Frontic components if available (theme, button, fancy-button, etc.)\n * - Proxies to shadcn-vue for all other components (card, dialog, etc.)\n *\n * This allows the proxy to control routing centrally without CLI updates.\n */\nfunction resolveComponentNames(components: string[]): string[] {\n return components.map((component) => {\n // Already has a registry prefix - leave as-is\n if (component.startsWith(\"@\")) {\n return component;\n }\n // Prefix with @frontic/ - proxy handles the routing\n return `@frontic/${component}`;\n });\n}\n\nexport function registerAddCommand(program: Command) {\n program\n .command(\"add\")\n .description(\"Add components to your project\")\n .argument(\"[components...]\", \"Components to add\")\n .option(\"-o, --overwrite\", \"Overwrite existing files\")\n .option(\"-a, --all\", \"Add all available components\")\n .option(\"-p, --path <path>\", \"Custom installation path\")\n .option(\"-y, --yes\", \"Skip confirmation prompts\")\n .action(async (components: string[], options: AddOptions) => {\n await add(components, options);\n });\n}\n\nasync function add(components: string[], options: AddOptions) {\n // Validate input\n if (!options.all && components.length === 0) {\n console.log(chalk.red(\"Error: Please specify components to add or use --all\"));\n console.log();\n console.log(\"Usage:\");\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add button dialog card\")}`);\n console.log(` ${chalk.cyan(\"npx @frontic/ui add --all\")}`);\n process.exit(1);\n }\n\n // Ensure Frontic registry is configured\n const spinner = ora(\"Checking configuration...\").start();\n try {\n await ensureFronticRegistry();\n spinner.succeed(\"Configuration verified\");\n } catch {\n spinner.fail(\"Configuration error\");\n console.log();\n console.log(chalk.yellow(\"Run `npx @frontic/ui init` first to set up your project.\"));\n process.exit(1);\n }\n\n // Resolve component names (prefix with @frontic/ for proxy routing)\n const resolvedComponents = resolveComponentNames(components);\n\n // Show what we're adding\n if (resolvedComponents.length > 0) {\n console.log(\n chalk.cyan(\"Components:\"),\n resolvedComponents.map((c) => c.replace(\"@frontic/\", \"\")).join(\", \")\n );\n }\n\n // Build shadcn-vue arguments\n const args = [\"add\"];\n\n if (options.all) {\n args.push(\"--all\");\n } else {\n args.push(...resolvedComponents);\n }\n\n if (options.overwrite) {\n args.push(\"--overwrite\");\n }\n\n if (options.path) {\n args.push(\"--path\", options.path);\n }\n\n if (options.yes) {\n args.push(\"--yes\");\n }\n\n console.log();\n console.log(chalk.blue(\"Adding components...\"));\n console.log();\n\n // Run shadcn-vue add\n await spawnShadcn(args);\n\n console.log();\n console.log(chalk.green(\"✓ Components added successfully!\"));\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { writeFile, readFile, mkdir } from \"fs/promises\";\nimport { existsSync } from \"fs\";\nimport { join } from \"path\";\nimport prompts from \"prompts\";\nimport { FRONTIC_REGISTRY_URL } from \"../utils/constants.js\";\n\ntype McpClient = \"claude\" | \"cursor\" | \"vscode\";\n\ninterface McpInitOptions {\n client?: McpClient;\n}\n\nexport function registerMcpCommand(program: Command) {\n const mcp = program\n .command(\"mcp\")\n .description(\"MCP (Model Context Protocol) commands\");\n\n mcp\n .command(\"init\")\n .description(\"Set up MCP for AI assistants\")\n .option(\"-c, --client <client>\", \"Target client (claude, cursor, vscode)\")\n .action(async (options: McpInitOptions) => {\n await initMcp(options);\n });\n}\n\nasync function initMcp(options: McpInitOptions) {\n console.log();\n console.log(chalk.bold(\"Frontic UI - MCP Setup\"));\n console.log(chalk.dim(\"Configure AI assistant integration\"));\n console.log();\n\n let client = options.client as McpClient | undefined;\n\n // Prompt for client if not specified\n if (!client) {\n const response = await prompts({\n type: \"select\",\n name: \"client\",\n message: \"Select your AI client:\",\n choices: [\n { title: \"Claude Code\", value: \"claude\" },\n { title: \"Cursor\", value: \"cursor\" },\n { title: \"VS Code\", value: \"vscode\" },\n ],\n });\n\n client = response.client;\n\n if (!client) {\n console.log(chalk.yellow(\"Setup cancelled.\"));\n return;\n }\n }\n\n const spinner = ora(\"Creating MCP configuration...\").start();\n\n try {\n await createMcpConfig(client);\n spinner.succeed(\"MCP configuration created\");\n } catch (error) {\n spinner.fail(\"Failed to create MCP configuration\");\n throw error;\n }\n\n console.log();\n console.log(chalk.green(\"✓ MCP configured successfully!\"));\n console.log();\n console.log(\"Your AI assistant can now:\");\n console.log(chalk.dim(\" • Browse available Frontic UI components\"));\n console.log(chalk.dim(\" • Add components using natural language\"));\n console.log(chalk.dim(' • Example: \"Add a button component\"'));\n console.log();\n}\n\nasync function createMcpConfig(client: McpClient) {\n const config = getMcpConfig();\n const configPath = getMcpConfigPath(client);\n const configDir = join(process.cwd(), configPath.split(\"/\").slice(0, -1).join(\"/\"));\n\n // Create directory if needed\n if (!existsSync(configDir)) {\n await mkdir(configDir, { recursive: true });\n }\n\n const fullPath = join(process.cwd(), configPath);\n\n // Read existing config or create new\n let existingConfig: Record<string, unknown> = {};\n try {\n const content = await readFile(fullPath, \"utf-8\");\n existingConfig = JSON.parse(content);\n } catch {\n // File doesn't exist, use empty config\n }\n\n // Merge with existing config\n const mergedConfig = {\n ...existingConfig,\n mcpServers: {\n ...(existingConfig.mcpServers as Record<string, unknown> || {}),\n ...config.mcpServers,\n },\n };\n\n await writeFile(fullPath, JSON.stringify(mergedConfig, null, 2));\n\n console.log(chalk.dim(` Config written to: ${configPath}`));\n}\n\nfunction getMcpConfigPath(client: McpClient): string {\n switch (client) {\n case \"claude\":\n return \".mcp.json\";\n case \"cursor\":\n return \".cursor/mcp.json\";\n case \"vscode\":\n return \".vscode/mcp.json\";\n }\n}\n\nfunction getMcpConfig() {\n return {\n mcpServers: {\n \"frontic-ui\": {\n command: \"npx\",\n args: [\"shadcn-vue@latest\", \"mcp\"],\n env: {\n SHADCN_REGISTRY_URL: FRONTIC_REGISTRY_URL,\n },\n },\n },\n };\n}\n","#!/usr/bin/env node\nimport { run } from '../src/index.js'\n\nrun()\n"],"mappings":"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","names":["join","readFile","writeFile","program","join","chalk","ora","program","chalk","ora","chalk","ora","writeFile","readFile","join","prompts","program","chalk","prompts","ora","join","readFile","writeFile"]}
|