inai-react-components 1.6.1 → 2.0.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 +7 -1
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +126 -0
- package/dist/commands/demo.d.ts +20 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +15 -0
- package/dist/commands/generate.d.ts +47 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +204 -0
- package/dist/commands/init.d.ts +32 -6
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +175 -27
- package/dist/commands/list.js +1 -1
- package/dist/commands/manifest.d.ts +9 -0
- package/dist/commands/manifest.d.ts.map +1 -0
- package/dist/commands/manifest.js +89 -0
- package/dist/commands/mcp.d.ts +208 -0
- package/dist/commands/mcp.d.ts.map +1 -1
- package/dist/commands/mcp.js +511 -0
- package/dist/commands/status.d.ts +30 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/theme.d.ts +32 -0
- package/dist/commands/theme.d.ts.map +1 -1
- package/dist/commands/theme.js +113 -0
- package/dist/index.js +45 -3
- package/dist/schemas/init-config.schema.json +77 -0
- package/dist/schemas/registry-item.schema.json +9 -0
- package/dist/utils/registry-resolver.d.ts +4 -0
- package/dist/utils/registry-resolver.d.ts.map +1 -1
- package/dist/utils/registry-resolver.js +35 -2
- package/dist/utils/themes.d.ts.map +1 -1
- package/dist/utils/themes.js +7 -0
- package/package.json +1 -1
package/dist/commands/theme.js
CHANGED
|
@@ -72,6 +72,119 @@ export async function runThemeCreate(options, rootDir) {
|
|
|
72
72
|
message: `Theme "${name}" created at ${outputPath}`,
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
+
function srgbToLinear(v) {
|
|
76
|
+
const n = v / 255;
|
|
77
|
+
return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
|
|
78
|
+
}
|
|
79
|
+
export function hexToOklch(hex) {
|
|
80
|
+
const normalized = hex.trim().replace(/^#/, "");
|
|
81
|
+
if (!/^[0-9a-fA-F]{6}$/.test(normalized)) {
|
|
82
|
+
throw new Error(`Invalid hex color "${hex}"`);
|
|
83
|
+
}
|
|
84
|
+
const r = Number.parseInt(normalized.slice(0, 2), 16);
|
|
85
|
+
const g = Number.parseInt(normalized.slice(2, 4), 16);
|
|
86
|
+
const b = Number.parseInt(normalized.slice(4, 6), 16);
|
|
87
|
+
const rl = srgbToLinear(r);
|
|
88
|
+
const gl = srgbToLinear(g);
|
|
89
|
+
const bl = srgbToLinear(b);
|
|
90
|
+
const l1 = 0.4122214708 * rl + 0.5363325363 * gl + 0.0514459929 * bl;
|
|
91
|
+
const l2 = 0.2119034982 * rl + 0.6806995451 * gl + 0.1073969566 * bl;
|
|
92
|
+
const l3 = 0.0883024619 * rl + 0.2817188376 * gl + 0.6299787005 * bl;
|
|
93
|
+
const l_ = Math.cbrt(l1);
|
|
94
|
+
const m_ = Math.cbrt(l2);
|
|
95
|
+
const s_ = Math.cbrt(l3);
|
|
96
|
+
const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
|
|
97
|
+
const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
|
|
98
|
+
const bb = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
|
|
99
|
+
const C = Math.sqrt(a * a + bb * bb);
|
|
100
|
+
let H = (Math.atan2(bb, a) * 180) / Math.PI;
|
|
101
|
+
if (H < 0)
|
|
102
|
+
H += 360;
|
|
103
|
+
return { l: Number(L.toFixed(3)), c: Number(C.toFixed(3)), h: Number(H.toFixed(1)) };
|
|
104
|
+
}
|
|
105
|
+
function formatOklch({ l, c, h }, offsets) {
|
|
106
|
+
const ol = Math.min(Math.max(l + (offsets?.l ?? 0), 0), 1);
|
|
107
|
+
const oc = Math.max(c + (offsets?.c ?? 0), 0);
|
|
108
|
+
const oh = ((h + (offsets?.h ?? 0)) % 360 + 360) % 360;
|
|
109
|
+
return `oklch(${ol.toFixed(3)} ${oc.toFixed(3)} ${oh.toFixed(1)})`;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Produce a minimal CSS theme layer that overrides the brand-centric
|
|
113
|
+
* token slots. It is meant to be stacked on top of an existing theme
|
|
114
|
+
* (e.g. by `@import`-ing this file after `ultimate.css`) so the rest of
|
|
115
|
+
* the scheme stays coherent and accessible.
|
|
116
|
+
*/
|
|
117
|
+
export function generateThemeFromHexCss(name, hex, oklch) {
|
|
118
|
+
const capital = name.charAt(0).toUpperCase() + name.slice(1);
|
|
119
|
+
return `/*
|
|
120
|
+
* ${capital} Theme (Brand override)
|
|
121
|
+
* Generated by company-ui CLI from hex ${hex}
|
|
122
|
+
* Layer on top of a base theme: @import "./ultimate.css"; then this file.
|
|
123
|
+
*/
|
|
124
|
+
:root[data-theme="${name}"],
|
|
125
|
+
:root[data-theme="${name}"] .dark {
|
|
126
|
+
--color-primary: ${formatOklch(oklch)};
|
|
127
|
+
--color-primary-hover: ${formatOklch(oklch, { l: -0.05 })};
|
|
128
|
+
--color-primary-active: ${formatOklch(oklch, { l: -0.1 })};
|
|
129
|
+
--color-primary-foreground: oklch(0.985 0 0);
|
|
130
|
+
--color-focus-ring: ${formatOklch(oklch, { l: 0.04, c: -0.05 })};
|
|
131
|
+
--color-accent: ${formatOklch(oklch, { h: 35 })};
|
|
132
|
+
--color-accent-hover: ${formatOklch(oklch, { h: 35, l: -0.05 })};
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
}
|
|
136
|
+
export async function runThemeFromHex(options, rootDir) {
|
|
137
|
+
const { name, hex } = options;
|
|
138
|
+
if (!name || name.trim().length === 0) {
|
|
139
|
+
return { success: false, filePath: "", message: "Theme name is required." };
|
|
140
|
+
}
|
|
141
|
+
let oklch;
|
|
142
|
+
try {
|
|
143
|
+
oklch = hexToOklch(hex);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
147
|
+
return { success: false, filePath: "", message };
|
|
148
|
+
}
|
|
149
|
+
const themesDir = resolveThemesDir(rootDir);
|
|
150
|
+
fs.mkdirSync(themesDir, { recursive: true });
|
|
151
|
+
const outputPath = path.join(themesDir, `${name}.css`);
|
|
152
|
+
if (fs.existsSync(outputPath)) {
|
|
153
|
+
return {
|
|
154
|
+
success: false,
|
|
155
|
+
filePath: outputPath,
|
|
156
|
+
message: `Theme file "${name}.css" already exists at ${themesDir}.`,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const css = generateThemeFromHexCss(name, hex, oklch);
|
|
160
|
+
fs.writeFileSync(outputPath, css);
|
|
161
|
+
return {
|
|
162
|
+
success: true,
|
|
163
|
+
filePath: outputPath,
|
|
164
|
+
message: `Theme "${name}" generated from ${hex} at ${outputPath}`,
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export async function themeFromHexCommand(options) {
|
|
168
|
+
const spinner = ora(`Generating theme "${options.name}" from ${options.hex}...`).start();
|
|
169
|
+
try {
|
|
170
|
+
const rootDir = process.cwd();
|
|
171
|
+
const result = await runThemeFromHex(options, rootDir);
|
|
172
|
+
if (result.success) {
|
|
173
|
+
spinner.succeed(result.message);
|
|
174
|
+
console.log(chalk.dim(`\nTo use this theme, import it after the base theme:`));
|
|
175
|
+
console.log(chalk.cyan(` @import "@company/tokens/themes/ultimate.css";\n @import "@company/tokens/themes/${options.name}.css";`));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
spinner.fail(result.message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
spinner.fail("Theme generation failed.");
|
|
183
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
184
|
+
console.error(chalk.red(`\nError: ${message}`));
|
|
185
|
+
process.exit(1);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
75
188
|
export async function themeCreateCommand(options) {
|
|
76
189
|
const spinner = ora(`Creating theme "${options.name}" based on "${options.base}"...`).start();
|
|
77
190
|
try {
|
package/dist/index.js
CHANGED
|
@@ -7,21 +7,25 @@ import { diffCommand } from "./commands/diff.js";
|
|
|
7
7
|
import { listCommand } from "./commands/list.js";
|
|
8
8
|
import { updateCommand } from "./commands/update.js";
|
|
9
9
|
import { syncCommand } from "./commands/sync.js";
|
|
10
|
-
import { themeCreateCommand } from "./commands/theme.js";
|
|
10
|
+
import { themeCreateCommand, themeFromHexCommand, } from "./commands/theme.js";
|
|
11
|
+
import { demoStartCommand } from "./commands/demo.js";
|
|
11
12
|
import { mcpCommand } from "./commands/mcp.js";
|
|
12
13
|
import { migrateCommand } from "./commands/migrate.js";
|
|
13
14
|
import { runSchema } from "./commands/schema.js";
|
|
14
15
|
import { registriesListCommand, registriesAddCommand, registriesRemoveCommand, } from "./commands/registries.js";
|
|
15
16
|
import { removeCommand } from "./commands/remove.js";
|
|
17
|
+
import { generateBlockCommand } from "./commands/generate.js";
|
|
18
|
+
import { manifestCommand } from "./commands/manifest.js";
|
|
16
19
|
const program = new Command();
|
|
17
20
|
program
|
|
18
21
|
.name("inai-ui")
|
|
19
22
|
.description("CLI for InAI UI component library")
|
|
20
|
-
.version("
|
|
23
|
+
.version("2.0.0");
|
|
21
24
|
program
|
|
22
25
|
.command("init [repo-url]")
|
|
23
26
|
.description("Initialize InAI UI in your project. Optionally pass a Git repo URL to fetch components remotely.")
|
|
24
|
-
.
|
|
27
|
+
.option("--config <path>", "Path to a JSON config file. Skips interactive prompts (CI/automation).")
|
|
28
|
+
.action((repoUrl, options) => initCommand(repoUrl, options));
|
|
25
29
|
program
|
|
26
30
|
.command("add [component]")
|
|
27
31
|
.description("Add a component to your project. Without arguments, opens an interactive picker to select multiple components.")
|
|
@@ -41,6 +45,12 @@ program
|
|
|
41
45
|
.description("Show installed components with drift / outdated / missing state")
|
|
42
46
|
.option("--json", "Emit the status report as JSON (machine-readable)")
|
|
43
47
|
.action((options) => statusCommand(options));
|
|
48
|
+
program
|
|
49
|
+
.command("manifest")
|
|
50
|
+
.description("List installed components with their pinned versions and outdated state.")
|
|
51
|
+
.option("--json", "Emit the manifest as JSON (machine-readable)")
|
|
52
|
+
.option("--outdated", "Show only components whose version drifts from the registry")
|
|
53
|
+
.action((options) => manifestCommand(options));
|
|
44
54
|
const mcpCmd = program
|
|
45
55
|
.command("mcp")
|
|
46
56
|
.description("Start the MCP (Model Context Protocol) server over stdio so AI assistants can drive the CLI.")
|
|
@@ -77,6 +87,18 @@ themeCmd
|
|
|
77
87
|
.requiredOption("-n, --name <name>", "Name for the new theme")
|
|
78
88
|
.requiredOption("-b, --base <base>", "Base theme to extend (monday, linear, notion, vercel)")
|
|
79
89
|
.action((options) => themeCreateCommand(options));
|
|
90
|
+
themeCmd
|
|
91
|
+
.command("from-hex")
|
|
92
|
+
.description("Generate a brand override theme from a single hex color (converts to OKLCH and writes a layered .css file).")
|
|
93
|
+
.requiredOption("-n, --name <name>", "Theme slug, used as filename")
|
|
94
|
+
.requiredOption("-c, --hex <hex>", "Brand hex color, e.g. #6b46c1")
|
|
95
|
+
.action((options) => themeFromHexCommand(options));
|
|
96
|
+
program
|
|
97
|
+
.command("demo")
|
|
98
|
+
.description("Launch the docs app in pitch-mode-ready demo state. Use ⌘⇧P once the app is up.")
|
|
99
|
+
.option("--theme <name>", "Preselect a theme preset for the demo")
|
|
100
|
+
.option("--port <number>", "Vite dev port", (value) => Number.parseInt(value, 10))
|
|
101
|
+
.action((options) => demoStartCommand(options));
|
|
80
102
|
program
|
|
81
103
|
.command("migrate")
|
|
82
104
|
.description("Apply deprecated-prop rename codemods to your project (inputSize→size, selectSize→size, comboBoxSize→size, checkboxState→state).")
|
|
@@ -123,4 +145,24 @@ registriesCmd
|
|
|
123
145
|
.action(async (name) => {
|
|
124
146
|
await registriesRemoveCommand(name);
|
|
125
147
|
});
|
|
148
|
+
const generateCmd = program
|
|
149
|
+
.command("generate")
|
|
150
|
+
.alias("gen")
|
|
151
|
+
.description("Generate new content from natural language using the Anthropic API");
|
|
152
|
+
generateCmd
|
|
153
|
+
.command("block [description...]")
|
|
154
|
+
.description("Generate a new block (page section) from a natural-language description. Requires ANTHROPIC_API_KEY.")
|
|
155
|
+
.option("--slug <slug>", "Slug for the new block (kebab-case). Derived from the description if omitted.")
|
|
156
|
+
.option("--output <dir>", "Output directory root", "apps/docs/src/registry/blocks")
|
|
157
|
+
.option("--model <model>", "Claude model id", "claude-sonnet-4-6")
|
|
158
|
+
.option("--max-tokens <n>", "Max tokens for the response", (v) => Number.parseInt(v, 10))
|
|
159
|
+
.option("--dry-run", "Print the generated files without writing them")
|
|
160
|
+
.option("--force", "Overwrite an existing block with the same slug")
|
|
161
|
+
.option("--api-key <key>", "Anthropic API key (otherwise ANTHROPIC_API_KEY env var)")
|
|
162
|
+
.action((descriptionParts, options) => {
|
|
163
|
+
const description = descriptionParts && descriptionParts.length > 0
|
|
164
|
+
? descriptionParts.join(" ")
|
|
165
|
+
: undefined;
|
|
166
|
+
return generateBlockCommand(description, options);
|
|
167
|
+
});
|
|
126
168
|
program.parse();
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://inai-ui.dev/init-config.schema.json",
|
|
4
|
+
"title": "InAI UI Init Config",
|
|
5
|
+
"description": "JSON config consumed by `inai-ui init --config <path>` to skip interactive prompts in CI / automation flows. Every required field has a sensible default if omitted.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"componentPath": {
|
|
10
|
+
"type": "string",
|
|
11
|
+
"description": "Where to install components. Defaults to `<sourceRoot>/components/ui`.",
|
|
12
|
+
"default": "src/components/ui"
|
|
13
|
+
},
|
|
14
|
+
"blockPath": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Where to install blocks. Defaults to `<sourceRoot>/components/blocks`.",
|
|
17
|
+
"default": "src/components/blocks"
|
|
18
|
+
},
|
|
19
|
+
"theme": {
|
|
20
|
+
"type": "string",
|
|
21
|
+
"description": "Base theme. Must be one of the values returned by `inai-ui list themes`.",
|
|
22
|
+
"default": "inai"
|
|
23
|
+
},
|
|
24
|
+
"fontBody": {
|
|
25
|
+
"type": "string",
|
|
26
|
+
"description": "Font preset for body text. See `FONT_PRESETS` in init.ts for the full list.",
|
|
27
|
+
"default": "outfit"
|
|
28
|
+
},
|
|
29
|
+
"fontHeading": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"description": "Font preset for headings.",
|
|
32
|
+
"default": "outfit"
|
|
33
|
+
},
|
|
34
|
+
"radius": {
|
|
35
|
+
"type": "number",
|
|
36
|
+
"description": "Border radius in rem. Common values: 0, 0.25, 0.5, 0.75, 1.0.",
|
|
37
|
+
"default": 0.5
|
|
38
|
+
},
|
|
39
|
+
"tanstackRouter": {
|
|
40
|
+
"type": "boolean",
|
|
41
|
+
"description": "Generate TanStack Router-aware integrations.",
|
|
42
|
+
"default": false
|
|
43
|
+
},
|
|
44
|
+
"tanstackQuery": {
|
|
45
|
+
"type": "boolean",
|
|
46
|
+
"description": "Generate TanStack Query-aware integrations.",
|
|
47
|
+
"default": false
|
|
48
|
+
},
|
|
49
|
+
"tanstackForm": {
|
|
50
|
+
"type": "boolean",
|
|
51
|
+
"description": "Generate TanStack Form-aware integrations.",
|
|
52
|
+
"default": false
|
|
53
|
+
},
|
|
54
|
+
"tanstackTable": {
|
|
55
|
+
"type": "boolean",
|
|
56
|
+
"description": "Generate TanStack Table-aware integrations.",
|
|
57
|
+
"default": false
|
|
58
|
+
},
|
|
59
|
+
"framework": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"enum": [
|
|
62
|
+
"next-app",
|
|
63
|
+
"next-pages",
|
|
64
|
+
"vite",
|
|
65
|
+
"remix",
|
|
66
|
+
"astro",
|
|
67
|
+
"tanstack-start",
|
|
68
|
+
"unknown"
|
|
69
|
+
],
|
|
70
|
+
"description": "Framework. When omitted, the CLI detects it from the consumer's package.json."
|
|
71
|
+
},
|
|
72
|
+
"cssEntryPoint": {
|
|
73
|
+
"type": "string",
|
|
74
|
+
"description": "Path to the project's root CSS file where tokens get imported. When omitted, the CLI derives it from the framework."
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -18,6 +18,15 @@
|
|
|
18
18
|
"description": {
|
|
19
19
|
"type": "string"
|
|
20
20
|
},
|
|
21
|
+
"tags": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"items": { "type": "string" },
|
|
24
|
+
"description": "Free-form tags used by the CLI picker and `inai-ui list` filters"
|
|
25
|
+
},
|
|
26
|
+
"category": {
|
|
27
|
+
"type": "string",
|
|
28
|
+
"description": "High-level grouping used by the docs site and `inai-ui list -c <category>`"
|
|
29
|
+
},
|
|
21
30
|
"files": {
|
|
22
31
|
"type": "array",
|
|
23
32
|
"items": { "type": "string" },
|
|
@@ -10,6 +10,10 @@ export declare function getRegistryCacheDir(name: string): string;
|
|
|
10
10
|
* diverged history, interrupted previous run), the cache is reset to
|
|
11
11
|
* match origin; if that also fails, the directory is nuked and a fresh
|
|
12
12
|
* clone is done. Users should never have to touch `~/.inai-ui/registry`.
|
|
13
|
+
*
|
|
14
|
+
* The clone is shallow (`--depth 1 --filter=blob:none --single-branch`)
|
|
15
|
+
* by default — set `INAI_UI_FULL_CLONE=1` to get a full clone if you
|
|
16
|
+
* need full git history (e.g. cross-version diffing).
|
|
13
17
|
*/
|
|
14
18
|
export declare function cloneRegistry(repoUrl: string): string;
|
|
15
19
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;
|
|
1
|
+
{"version":3,"file":"registry-resolver.d.ts","sourceRoot":"","sources":["../../src/utils/registry-resolver.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAS7E,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD;AAsED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAiBrD;AAmBD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,MAAM,CAAC,CA+FjB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAS7D"}
|
|
@@ -45,6 +45,12 @@ function refreshGitCache(cacheDir) {
|
|
|
45
45
|
const remoteHead = execSync("git symbolic-ref refs/remotes/origin/HEAD", { cwd: cacheDir, stdio: ["pipe", "pipe", "pipe"] })
|
|
46
46
|
.toString()
|
|
47
47
|
.trim();
|
|
48
|
+
// Defense-in-depth: `remoteHead` comes from git's own output, but we
|
|
49
|
+
// interpolate it into a shell command. Refuse anything that isn't a
|
|
50
|
+
// well-formed ref so a poisoned upstream can't smuggle metachars.
|
|
51
|
+
if (!/^refs\/remotes\/origin\/[A-Za-z0-9._/-]+$/.test(remoteHead)) {
|
|
52
|
+
throw new Error(`Unexpected remote HEAD ref: ${remoteHead}`);
|
|
53
|
+
}
|
|
48
54
|
execSync(`git reset --hard ${remoteHead}`, {
|
|
49
55
|
cwd: cacheDir,
|
|
50
56
|
stdio: "pipe",
|
|
@@ -57,6 +63,23 @@ function refreshGitCache(cacheDir) {
|
|
|
57
63
|
}
|
|
58
64
|
}
|
|
59
65
|
}
|
|
66
|
+
/**
|
|
67
|
+
* Build the argument string for `git clone`. Defaults to a shallow,
|
|
68
|
+
* blob-filtered clone so registries with large histories (e.g. the InAI
|
|
69
|
+
* monorepo at v2.0.0 with 600+ blocks/templates) finish in seconds
|
|
70
|
+
* instead of minutes and save ~70% bandwidth on CI.
|
|
71
|
+
*
|
|
72
|
+
* Set `INAI_UI_FULL_CLONE=1` (or pass `{ shallow: false }`) to opt out —
|
|
73
|
+
* needed if the consumer wants to run `git log` across history or diff
|
|
74
|
+
* cross-version.
|
|
75
|
+
*/
|
|
76
|
+
function buildCloneArgs(branch, shallow = true) {
|
|
77
|
+
const branchArg = branch ? `--branch "${branch}" ` : "";
|
|
78
|
+
if (process.env.INAI_UI_FULL_CLONE === "1" || !shallow) {
|
|
79
|
+
return `${branchArg}`.trim();
|
|
80
|
+
}
|
|
81
|
+
return `${branchArg}--depth 1 --filter=blob:none --single-branch`.trim();
|
|
82
|
+
}
|
|
60
83
|
/**
|
|
61
84
|
* Clone (or fast-forward) a git registry into the legacy single-cache
|
|
62
85
|
* directory. Preserved for backward compatibility with the v0.5.0
|
|
@@ -66,6 +89,10 @@ function refreshGitCache(cacheDir) {
|
|
|
66
89
|
* diverged history, interrupted previous run), the cache is reset to
|
|
67
90
|
* match origin; if that also fails, the directory is nuked and a fresh
|
|
68
91
|
* clone is done. Users should never have to touch `~/.inai-ui/registry`.
|
|
92
|
+
*
|
|
93
|
+
* The clone is shallow (`--depth 1 --filter=blob:none --single-branch`)
|
|
94
|
+
* by default — set `INAI_UI_FULL_CLONE=1` to get a full clone if you
|
|
95
|
+
* need full git history (e.g. cross-version diffing).
|
|
69
96
|
*/
|
|
70
97
|
export function cloneRegistry(repoUrl) {
|
|
71
98
|
if (fs.existsSync(path.join(LEGACY_CACHE_DIR, ".git"))) {
|
|
@@ -79,7 +106,10 @@ export function cloneRegistry(repoUrl) {
|
|
|
79
106
|
if (fs.existsSync(LEGACY_CACHE_DIR)) {
|
|
80
107
|
fs.rmSync(LEGACY_CACHE_DIR, { recursive: true });
|
|
81
108
|
}
|
|
82
|
-
|
|
109
|
+
const cloneArgs = buildCloneArgs();
|
|
110
|
+
execSync(`git clone ${cloneArgs} "${repoUrl}" "${LEGACY_CACHE_DIR}"`, {
|
|
111
|
+
stdio: "pipe",
|
|
112
|
+
});
|
|
83
113
|
return LEGACY_CACHE_DIR;
|
|
84
114
|
}
|
|
85
115
|
/**
|
|
@@ -145,7 +175,10 @@ export async function resolveRegistry(registry, projectDir, options = {}) {
|
|
|
145
175
|
}
|
|
146
176
|
if (!fs.existsSync(path.join(cacheDir, ".git"))) {
|
|
147
177
|
fs.mkdirSync(REGISTRIES_CACHE_DIR, { recursive: true });
|
|
148
|
-
|
|
178
|
+
const cloneArgs = buildCloneArgs(branch);
|
|
179
|
+
execSync(`git clone ${cloneArgs} "${cloneUrl}" "${cacheDir}"`, {
|
|
180
|
+
stdio: "pipe",
|
|
181
|
+
});
|
|
149
182
|
}
|
|
150
183
|
return cacheDir;
|
|
151
184
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../src/utils/themes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,MAAM,EAAE,SAAS,
|
|
1
|
+
{"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../src/utils/themes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,QAAQ,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,MAAM,EAAE,SAAS,EA+C7B,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,MAAM,EAA8B,CAAC;AAE/D,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD"}
|
package/dist/utils/themes.js
CHANGED
|
@@ -42,6 +42,13 @@ export const THEMES = [
|
|
|
42
42
|
{ name: "cosmic", label: "Cosmic", category: "creative", description: "Space-inspired violet and nebula hues." },
|
|
43
43
|
{ name: "matcha", label: "Matcha", category: "creative", description: "Earthy matcha greens and cream." },
|
|
44
44
|
{ name: "volcanic", label: "Volcanic", category: "creative", description: "Charcoal and lava orange contrast." },
|
|
45
|
+
{ name: "brutalist", label: "Brutalist", category: "creative", description: "Neon yellow over pure black and white with ink borders." },
|
|
46
|
+
{ name: "glassmorphism-pro", label: "Glassmorphism Pro", category: "creative", description: "Pastel teal on frosted-mist surfaces." },
|
|
47
|
+
{ name: "y2k-chrome", label: "Y2K Chrome", category: "creative", description: "Cyber-blue and hot pink over chrome silver." },
|
|
48
|
+
{ name: "editorial", label: "Editorial", category: "creative", description: "Serif ink on cream paper with muted rust accents." },
|
|
49
|
+
{ name: "cyber-punk-v2", label: "Cyber Punk v2", category: "creative", description: "Neon red + cyan on deep night, glowing borders." },
|
|
50
|
+
{ name: "neumorphism-soft", label: "Neumorphism Soft", category: "creative", description: "Soft lavender with dual inner/outer shadows." },
|
|
51
|
+
{ name: "swiss-grid", label: "Swiss Grid", category: "creative", description: "Helvetica red + pure black on paper, zero radius." },
|
|
45
52
|
];
|
|
46
53
|
export const THEME_NAMES = THEMES.map((t) => t.name);
|
|
47
54
|
export function isKnownTheme(name) {
|
package/package.json
CHANGED