orizon 0.1.0 → 0.2.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.
Files changed (3) hide show
  1. package/bin/cli.mjs +52 -0
  2. package/bin/init.mjs +257 -0
  3. package/package.json +8 -2
package/bin/cli.mjs ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { readFileSync } from "node:fs";
4
+ import { dirname, resolve } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const pkg = JSON.parse(
9
+ readFileSync(resolve(__dirname, "..", "package.json"), "utf8"),
10
+ );
11
+
12
+ const [command] = process.argv.slice(2);
13
+
14
+ function printHelp() {
15
+ console.log(`
16
+ orizon v${pkg.version}
17
+
18
+ Usage:
19
+ npx orizon <command>
20
+
21
+ Commands:
22
+ init Set up Orizon in your React + Vite project
23
+
24
+ Options:
25
+ --version Show version number
26
+ --help Show this help message
27
+ `);
28
+ }
29
+
30
+ switch (command) {
31
+ case "init": {
32
+ const { init } = await import("./init.mjs");
33
+ await init();
34
+ break;
35
+ }
36
+
37
+ case "--version":
38
+ case "-v":
39
+ console.log(pkg.version);
40
+ break;
41
+
42
+ case "--help":
43
+ case "-h":
44
+ case undefined:
45
+ printHelp();
46
+ break;
47
+
48
+ default:
49
+ console.error(`Unknown command: ${command}\n`);
50
+ printHelp();
51
+ process.exit(1);
52
+ }
package/bin/init.mjs ADDED
@@ -0,0 +1,257 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
4
+ import { resolve, join } from "node:path";
5
+ import { execSync } from "node:child_process";
6
+ import pc from "picocolors";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Logging helpers
10
+ // ---------------------------------------------------------------------------
11
+ const log = {
12
+ step: (msg) => console.log(pc.cyan("●") + " " + msg),
13
+ success: (msg) => console.log(pc.green("✔") + " " + msg),
14
+ skip: (msg) => console.log(pc.yellow("⊘") + " " + pc.dim(msg)),
15
+ error: (msg) => console.error(pc.red("✖") + " " + msg),
16
+ info: (msg) => console.log(pc.dim(" " + msg)),
17
+ };
18
+
19
+ // ---------------------------------------------------------------------------
20
+ // Detect package manager
21
+ // ---------------------------------------------------------------------------
22
+ function detectPM(cwd) {
23
+ if (existsSync(join(cwd, "bun.lock")) || existsSync(join(cwd, "bun.lockb")))
24
+ return { name: "bun", install: "bun add -D" };
25
+ if (existsSync(join(cwd, "pnpm-lock.yaml")))
26
+ return { name: "pnpm", install: "pnpm add -D" };
27
+ if (existsSync(join(cwd, "yarn.lock")))
28
+ return { name: "yarn", install: "yarn add -D" };
29
+ return { name: "npm", install: "npm install -D" };
30
+ }
31
+
32
+ // ---------------------------------------------------------------------------
33
+ // Check if a package is already installed (deps or devDeps)
34
+ // ---------------------------------------------------------------------------
35
+ function isInstalled(pkg, pkgJson) {
36
+ const deps = pkgJson.dependencies || {};
37
+ const devDeps = pkgJson.devDependencies || {};
38
+ return Boolean(deps[pkg] || devDeps[pkg]);
39
+ }
40
+
41
+ // ---------------------------------------------------------------------------
42
+ // Patch vite.config.ts — add tailwindcss import + plugin
43
+ // ---------------------------------------------------------------------------
44
+ function patchViteConfig(filePath) {
45
+ let content = readFileSync(filePath, "utf8");
46
+ let modified = false;
47
+
48
+ // 1. Add import if missing
49
+ if (!content.includes("@tailwindcss/vite")) {
50
+ // Find the last import statement and add after it
51
+ const importRegex = /^import\s.+$/gm;
52
+ let lastImportMatch = null;
53
+ let match;
54
+ while ((match = importRegex.exec(content)) !== null) {
55
+ lastImportMatch = match;
56
+ }
57
+
58
+ const importLine = 'import tailwindcss from "@tailwindcss/vite";';
59
+
60
+ if (lastImportMatch) {
61
+ const insertPos = lastImportMatch.index + lastImportMatch[0].length;
62
+ content =
63
+ content.slice(0, insertPos) + "\n" + importLine + content.slice(insertPos);
64
+ } else {
65
+ // No imports found — add at top
66
+ content = importLine + "\n" + content;
67
+ }
68
+ modified = true;
69
+ log.success("Added tailwindcss import to " + filePath.split(/[\\/]/).pop());
70
+ } else {
71
+ log.skip("tailwindcss import already in vite config");
72
+ }
73
+
74
+ // 2. Add plugin if missing
75
+ if (!content.includes("tailwindcss()")) {
76
+ // Find plugins: [ and insert tailwindcss() after the opening bracket
77
+ const pluginsMatch = content.match(/plugins\s*:\s*\[/);
78
+ if (pluginsMatch) {
79
+ const insertPos = pluginsMatch.index + pluginsMatch[0].length;
80
+ content =
81
+ content.slice(0, insertPos) +
82
+ "tailwindcss(), " +
83
+ content.slice(insertPos);
84
+ modified = true;
85
+ log.success("Added tailwindcss() plugin to vite config");
86
+ } else {
87
+ log.error(
88
+ "Could not find plugins array in vite config — please add tailwindcss() manually",
89
+ );
90
+ }
91
+ } else {
92
+ log.skip("tailwindcss() plugin already in vite config");
93
+ }
94
+
95
+ if (modified) {
96
+ writeFileSync(filePath, content, "utf8");
97
+ }
98
+ }
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // Patch CSS file — prepend required @import / @source lines
102
+ // ---------------------------------------------------------------------------
103
+ function patchCSS(filePath, created) {
104
+ let content = created ? "" : readFileSync(filePath, "utf8");
105
+ const requiredLines = [
106
+ '@import "tailwindcss";',
107
+ '@import "orizon/preset.css";',
108
+ '@source "../node_modules/orizon/dist";',
109
+ ];
110
+
111
+ const toAdd = [];
112
+ for (const line of requiredLines) {
113
+ if (!content.includes(line)) {
114
+ toAdd.push(line);
115
+ }
116
+ }
117
+
118
+ if (toAdd.length === 0) {
119
+ log.skip("CSS file already has all required imports");
120
+ return;
121
+ }
122
+
123
+ // Prepend missing lines at the top
124
+ content = toAdd.join("\n") + (content ? "\n" + content : "\n");
125
+ writeFileSync(filePath, content, "utf8");
126
+ log.success(
127
+ `Added ${toAdd.length} line${toAdd.length > 1 ? "s" : ""} to ${filePath.split(/[\\/]/).pop()}`,
128
+ );
129
+ }
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // Main init function
133
+ // ---------------------------------------------------------------------------
134
+ export async function init() {
135
+ const cwd = process.cwd();
136
+
137
+ console.log();
138
+ console.log(pc.bold(" Orizon") + pc.dim(" — setting up your project"));
139
+ console.log();
140
+
141
+ // -----------------------------------------------------------------------
142
+ // Step 0: Validate we're in a project
143
+ // -----------------------------------------------------------------------
144
+ const pkgPath = join(cwd, "package.json");
145
+ if (!existsSync(pkgPath)) {
146
+ log.error("No package.json found in current directory.");
147
+ log.info("Run this command from the root of your project.");
148
+ process.exit(1);
149
+ }
150
+
151
+ // Check for vite config
152
+ const viteConfigTS = join(cwd, "vite.config.ts");
153
+ const viteConfigJS = join(cwd, "vite.config.js");
154
+ const viteConfigMTS = join(cwd, "vite.config.mts");
155
+ const viteConfigPath = existsSync(viteConfigTS)
156
+ ? viteConfigTS
157
+ : existsSync(viteConfigJS)
158
+ ? viteConfigJS
159
+ : existsSync(viteConfigMTS)
160
+ ? viteConfigMTS
161
+ : null;
162
+
163
+ if (!viteConfigPath) {
164
+ log.error("No vite.config.ts/js found. Currently only Vite projects are supported.");
165
+ process.exit(1);
166
+ }
167
+
168
+ log.success("Detected Vite project");
169
+
170
+ // -----------------------------------------------------------------------
171
+ // Step 1: Detect package manager
172
+ // -----------------------------------------------------------------------
173
+ const pm = detectPM(cwd);
174
+ log.info(`Using ${pc.bold(pm.name)}`);
175
+ console.log();
176
+
177
+ // -----------------------------------------------------------------------
178
+ // Step 2: Install dependencies
179
+ // -----------------------------------------------------------------------
180
+ log.step("Installing dependencies...");
181
+
182
+ const pkgJson = JSON.parse(readFileSync(pkgPath, "utf8"));
183
+ const toInstall = [];
184
+
185
+ if (!isInstalled("tailwindcss", pkgJson)) toInstall.push("tailwindcss");
186
+ if (!isInstalled("@tailwindcss/vite", pkgJson))
187
+ toInstall.push("@tailwindcss/vite");
188
+
189
+ if (toInstall.length > 0) {
190
+ const cmd = `${pm.install} ${toInstall.join(" ")}`;
191
+ log.info(pc.dim(`$ ${cmd}`));
192
+ try {
193
+ execSync(cmd, { cwd, stdio: "pipe" });
194
+ log.success(`Installed ${toInstall.join(", ")}`);
195
+ } catch (err) {
196
+ log.error(`Failed to install dependencies. Run manually:\n ${cmd}`);
197
+ process.exit(1);
198
+ }
199
+ } else {
200
+ log.skip("tailwindcss & @tailwindcss/vite already installed");
201
+ }
202
+
203
+ console.log();
204
+
205
+ // -----------------------------------------------------------------------
206
+ // Step 3: Patch vite config
207
+ // -----------------------------------------------------------------------
208
+ log.step("Configuring Vite...");
209
+ patchViteConfig(viteConfigPath);
210
+ console.log();
211
+
212
+ // -----------------------------------------------------------------------
213
+ // Step 4: Patch CSS
214
+ // -----------------------------------------------------------------------
215
+ log.step("Setting up CSS...");
216
+
217
+ const cssSearchOrder = [
218
+ "src/index.css",
219
+ "src/main.css",
220
+ "src/styles.css",
221
+ "src/globals.css",
222
+ "src/app.css",
223
+ "src/App.css",
224
+ ];
225
+
226
+ let cssPath = null;
227
+ let cssCreated = false;
228
+
229
+ for (const candidate of cssSearchOrder) {
230
+ const full = join(cwd, candidate);
231
+ if (existsSync(full)) {
232
+ cssPath = full;
233
+ break;
234
+ }
235
+ }
236
+
237
+ if (!cssPath) {
238
+ // Create src/index.css
239
+ const srcDir = join(cwd, "src");
240
+ if (!existsSync(srcDir)) mkdirSync(srcDir, { recursive: true });
241
+ cssPath = join(srcDir, "index.css");
242
+ cssCreated = true;
243
+ log.info("Creating src/index.css");
244
+ }
245
+
246
+ patchCSS(cssPath, cssCreated);
247
+ console.log();
248
+
249
+ // -----------------------------------------------------------------------
250
+ // Step 5: Done!
251
+ // -----------------------------------------------------------------------
252
+ console.log(pc.green(pc.bold(" ✓ Orizon is ready!")));
253
+ console.log();
254
+ console.log(" You can now import components:");
255
+ console.log(pc.cyan(' import { Button } from "orizon";'));
256
+ console.log();
257
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orizon",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Ant Design API on shadcn/ui primitives — 68 components for React with Tailwind CSS",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -17,6 +17,9 @@
17
17
  "typescript",
18
18
  "accessible"
19
19
  ],
20
+ "bin": {
21
+ "orizon": "./bin/cli.mjs"
22
+ },
20
23
  "sideEffects": false,
21
24
  "main": "./dist/orizon.cjs.js",
22
25
  "module": "./dist/orizon.es.js",
@@ -31,6 +34,7 @@
31
34
  },
32
35
  "files": [
33
36
  "dist",
37
+ "bin",
34
38
  "README.md",
35
39
  "LICENSE"
36
40
  ],
@@ -58,7 +62,9 @@
58
62
  "optional": true
59
63
  }
60
64
  },
61
- "dependencies": {},
65
+ "dependencies": {
66
+ "picocolors": "^1.1.1"
67
+ },
62
68
  "devDependencies": {
63
69
  "@base-ui/react": "^1.2.0",
64
70
  "@eslint/js": "^9.39.1",