jixoai-ui 0.0.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -0
- package/bin/jixoai-ui.mjs +172 -0
- package/package.json +28 -5
- package/index.js +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# jixoai-ui CLI
|
|
2
|
+
|
|
3
|
+
The official jixoai design-language CLI. It **shares shadcn's
|
|
4
|
+
`components.json`** and extends it with a non-conflicting `jixoai` block:
|
|
5
|
+
|
|
6
|
+
```jsonc
|
|
7
|
+
{
|
|
8
|
+
// ...shadcn fields stay untouched (style, aliases, registries, ...)...
|
|
9
|
+
"registries": { "@jixoai": "https://ui.jixoai.com/r/{name}.json" },
|
|
10
|
+
"jixoai": { "brandHue": 160 }
|
|
11
|
+
}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx jixoai-ui init --hue 160 # namespace + config + theme + hue, one shot
|
|
18
|
+
npx jixoai-ui add toc # = shadcn add @jixoai/toc, hue re-applied
|
|
19
|
+
npx jixoai-ui hue 165 # retheme by changing one number
|
|
20
|
+
npx jixoai-ui config # print the resolved jixoai config
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires `components.json` (run `npx shadcn init` first in fresh projects —
|
|
24
|
+
this CLI extends shadcn's config, it never replaces it).
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* jixoai-ui — the official jixoai design-language CLI (bin/jixoai-ui.mjs).
|
|
4
|
+
*
|
|
5
|
+
* Orthogonal intents (2026-08-20): components.json extension management;
|
|
6
|
+
* brand-hue application; registry add delegation.
|
|
7
|
+
*
|
|
8
|
+
* Config contract (Owner decision, 2026-08-20): the CLI SHARES shadcn's
|
|
9
|
+
* components.json and extends it with a non-conflicting `jixoai` object:
|
|
10
|
+
*
|
|
11
|
+
* {
|
|
12
|
+
* ...shadcn fields (style, aliases, registries, ...) untouched...,
|
|
13
|
+
* "registries": { "@jixoai": "https://ui.jixoai.com/r/{name}.json" },
|
|
14
|
+
* "jixoai": { "brandHue": 160 }
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* The registry URL points at the official Pages-hosted registry; hue lives
|
|
18
|
+
* in ONE config field and is written into the installed jixoai.css
|
|
19
|
+
* (--brand-hue) on every init/add/hue run.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { spawnSync } from "node:child_process";
|
|
23
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
24
|
+
import { join, resolve } from "node:path";
|
|
25
|
+
import process from "node:process";
|
|
26
|
+
|
|
27
|
+
const REGISTRY_URL = "https://ui.jixoai.com/r/{name}.json";
|
|
28
|
+
const NAMESPACE = "@jixoai";
|
|
29
|
+
const THEME_ITEM = "jixoai-theme";
|
|
30
|
+
const DEFAULT_HUE = 0;
|
|
31
|
+
|
|
32
|
+
const USAGE = `jixoai-ui — the jixoai design language CLI
|
|
33
|
+
|
|
34
|
+
Commands:
|
|
35
|
+
jixoai-ui init [--hue <degrees>] register the @jixoai namespace, add the
|
|
36
|
+
jixoai config block, install the theme,
|
|
37
|
+
and apply the brand hue
|
|
38
|
+
jixoai-ui hue <degrees> set the project brand hue (config + css)
|
|
39
|
+
jixoai-ui add <item...> install registry items (delegates to
|
|
40
|
+
\`shadcn add ${NAMESPACE}/<item>\`), then
|
|
41
|
+
re-applies the brand hue
|
|
42
|
+
jixoai-ui config print the resolved jixoai config
|
|
43
|
+
|
|
44
|
+
The CLI extends shadcn's components.json — run \`npx shadcn init\` first in
|
|
45
|
+
projects that don't have one yet.`;
|
|
46
|
+
|
|
47
|
+
function fail(message) {
|
|
48
|
+
console.error(`jixoai-ui: ${message}`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function readConfig(cwd) {
|
|
53
|
+
const path = join(cwd, "components.json");
|
|
54
|
+
if (!existsSync(path)) {
|
|
55
|
+
fail(
|
|
56
|
+
"components.json not found. Run `npx shadcn init` first — this CLI extends shadcn's config, it does not replace it.",
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return { path, config: JSON.parse(readFileSync(path, "utf8")) };
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function writeConfig(path, config) {
|
|
63
|
+
writeFileSync(path, JSON.stringify(config, null, 2) + "\n");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function ensureNamespace(config) {
|
|
67
|
+
config.registries ??= {};
|
|
68
|
+
config.registries[NAMESPACE] ??= REGISTRY_URL;
|
|
69
|
+
if (config.registries[NAMESPACE] !== REGISTRY_URL) {
|
|
70
|
+
console.warn(
|
|
71
|
+
`jixoai-ui: keeping existing ${NAMESPACE} registry url (${config.registries[NAMESPACE]})`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function themeCssPath(config, cwd) {
|
|
77
|
+
const lib = config.aliases?.lib;
|
|
78
|
+
if (typeof lib !== "string") return null;
|
|
79
|
+
const candidates = [resolve(cwd, lib, "jixoai.css"), resolve(cwd, `${lib}.css`)];
|
|
80
|
+
for (const candidate of candidates) {
|
|
81
|
+
if (existsSync(candidate)) return candidate;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function applyHue(cssPath, hue) {
|
|
87
|
+
if (!cssPath) {
|
|
88
|
+
console.warn(
|
|
89
|
+
"jixoai-ui: jixoai.css not found yet — the hue will be applied on the next init/add.",
|
|
90
|
+
);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const css = readFileSync(cssPath, "utf8");
|
|
94
|
+
const next = css.replace(/--brand-hue:\s*[\d.]+/, `--brand-hue: ${hue}`);
|
|
95
|
+
if (next !== css) {
|
|
96
|
+
writeFileSync(cssPath, next);
|
|
97
|
+
console.log(`jixoai-ui: --brand-hue: ${hue} → ${cssPath}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function shadcn(args, cwd, configPath, config) {
|
|
102
|
+
// shadcn 4.18 rejects unknown top-level keys (our jixoai block), so the
|
|
103
|
+
// extension fields are stripped for the call and restored afterwards.
|
|
104
|
+
const { jixoai, ...rest } = config;
|
|
105
|
+
writeConfig(configPath, rest);
|
|
106
|
+
const result = spawnSync(
|
|
107
|
+
"npx",
|
|
108
|
+
["--yes", "shadcn", ...args, "--yes"],
|
|
109
|
+
{ stdio: "inherit", cwd, env: { ...process.env, npm_config_yes: "true" } },
|
|
110
|
+
);
|
|
111
|
+
if (result.status !== 0) {
|
|
112
|
+
writeConfig(configPath, config); // restore even on failure
|
|
113
|
+
fail(`\`shadcn ${args.join(" ")}\` exited with ${result.status}`);
|
|
114
|
+
}
|
|
115
|
+
const after = readConfig(cwd);
|
|
116
|
+
after.config.jixoai = jixoai;
|
|
117
|
+
writeConfig(after.path, after.config);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function hueFromArgs(args, fallback = DEFAULT_HUE) {
|
|
121
|
+
// accepts --hue <n> OR a bare positional degree value
|
|
122
|
+
const positional = args.find((a, i) => i > 0 && Number.isFinite(Number(a)));
|
|
123
|
+
const index = args.indexOf("--hue");
|
|
124
|
+
const value = index !== -1 ? Number(args[index + 1]) : (positional !== undefined ? Number(positional) : fallback);
|
|
125
|
+
if (!Number.isFinite(value) || value < 0 || value >= 360) {
|
|
126
|
+
fail("hue must be a number in [0, 360)");
|
|
127
|
+
}
|
|
128
|
+
return Math.round(value);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
132
|
+
const cwd = process.cwd();
|
|
133
|
+
|
|
134
|
+
switch (command) {
|
|
135
|
+
case "init": {
|
|
136
|
+
const { path, config } = readConfig(cwd);
|
|
137
|
+
const hue = hueFromArgs(rest, config.jixoai?.brandHue ?? DEFAULT_HUE);
|
|
138
|
+
ensureNamespace(config);
|
|
139
|
+
config.jixoai = { ...(config.jixoai ?? {}), brandHue: hue };
|
|
140
|
+
writeConfig(path, config);
|
|
141
|
+
console.log(`jixoai-ui: ${NAMESPACE} namespace + jixoai config written → ${path}`);
|
|
142
|
+
shadcn(["add", `${NAMESPACE}/${THEME_ITEM}`], cwd, path, config);
|
|
143
|
+
applyHue(themeCssPath(config, cwd), hue);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
case "hue": {
|
|
147
|
+
const hue = hueFromArgs(["--hue", rest[0]]);
|
|
148
|
+
const { path, config } = readConfig(cwd);
|
|
149
|
+
config.jixoai = { ...(config.jixoai ?? {}), brandHue: hue };
|
|
150
|
+
writeConfig(path, config);
|
|
151
|
+
applyHue(themeCssPath(config, cwd), hue);
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case "add": {
|
|
155
|
+
if (rest.length === 0) fail("add needs at least one item name (e.g. `toc`)");
|
|
156
|
+
const { path, config } = readConfig(cwd);
|
|
157
|
+
const hue = config.jixoai?.brandHue ?? DEFAULT_HUE;
|
|
158
|
+
for (const item of rest) {
|
|
159
|
+
shadcn(["add", `${NAMESPACE}/${item}`], cwd, path, readConfig(cwd).config);
|
|
160
|
+
}
|
|
161
|
+
applyHue(themeCssPath(config, cwd), hue);
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
case "config": {
|
|
165
|
+
const { config } = readConfig(cwd);
|
|
166
|
+
console.log(JSON.stringify({ registry: REGISTRY_URL, ...config.jixoai }, null, 2));
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
default:
|
|
170
|
+
console.log(USAGE);
|
|
171
|
+
process.exit(command && command !== "help" && command !== "--help" ? 1 : 0);
|
|
172
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jixoai-ui",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "Official jixoai design-language CLI: initializes the @jixoai shadcn registry namespace, manages the jixoai extension fields in components.json, and applies the per-project brand hue.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"jixoai-ui": "./bin/jixoai-ui.mjs"
|
|
9
|
+
},
|
|
6
10
|
"files": [
|
|
7
|
-
"
|
|
8
|
-
|
|
11
|
+
"bin/",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=20"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"jixoai",
|
|
19
|
+
"shadcn",
|
|
20
|
+
"registry",
|
|
21
|
+
"cli",
|
|
22
|
+
"design-system"
|
|
23
|
+
],
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/jixoai/ui",
|
|
30
|
+
"directory": "cli"
|
|
31
|
+
}
|
|
9
32
|
}
|
package/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
module.exports = {};
|