novaui-cli 1.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.
Files changed (2) hide show
  1. package/package.json +24 -0
  2. package/src/bin.js +309 -0
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "novaui-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI for NovaUI - React Native component library with NativeWind",
5
+ "type": "module",
6
+ "bin": {
7
+ "novaui": "./src/bin.js"
8
+ },
9
+ "files": [
10
+ "src"
11
+ ],
12
+ "keywords": [
13
+ "novaui",
14
+ "react-native",
15
+ "cli",
16
+ "nativewind",
17
+ "ui-components"
18
+ ],
19
+ "license": "MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "https://github.com/KaloyanBehov/native-ui"
23
+ }
24
+ }
package/src/bin.js ADDED
@@ -0,0 +1,309 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs"
4
+ import path from "node:path"
5
+ import { execSync } from "node:child_process"
6
+
7
+ const BASE_URL =
8
+ "https://raw.githubusercontent.com/KaloyanBehov/native-ui/main"
9
+
10
+ // ─── CSS Variables (global.css) ─────────────────────────────────────────────
11
+
12
+ const GLOBAL_CSS_CONTENT = `@tailwind base;
13
+ @tailwind components;
14
+ @tailwind utilities;
15
+
16
+ @layer base {
17
+ :root {
18
+ --background: 0 0% 100%;
19
+ --foreground: 240 10% 3.9%;
20
+ --card: 0 0% 100%;
21
+ --card-foreground: 240 10% 3.9%;
22
+ --popover: 0 0% 100%;
23
+ --popover-foreground: 240 10% 3.9%;
24
+ --primary: 240 5.9% 10%;
25
+ --primary-foreground: 0 0% 98%;
26
+ --secondary: 240 4.8% 95.9%;
27
+ --secondary-foreground: 240 5.9% 10%;
28
+ --muted: 240 4.8% 95.9%;
29
+ --muted-foreground: 240 3.8% 46.1%;
30
+ --accent: 240 4.8% 95.9%;
31
+ --accent-foreground: 240 5.9% 10%;
32
+ --destructive: 0 84.2% 60.2%;
33
+ --destructive-foreground: 0 0% 98%;
34
+ --border: 240 5.9% 90%;
35
+ --input: 240 5.9% 90%;
36
+ --ring: 240 5.9% 10%;
37
+ --radius: 0.5rem;
38
+ }
39
+
40
+ .dark {
41
+ --background: 240 10% 3.9%;
42
+ --foreground: 0 0% 98%;
43
+ --card: 240 10% 3.9%;
44
+ --card-foreground: 0 0% 98%;
45
+ --popover: 240 10% 3.9%;
46
+ --popover-foreground: 0 0% 98%;
47
+ --primary: 0 0% 98%;
48
+ --primary-foreground: 240 5.9% 10%;
49
+ --secondary: 240 3.7% 15.9%;
50
+ --secondary-foreground: 0 0% 98%;
51
+ --muted: 240 3.7% 15.9%;
52
+ --muted-foreground: 240 5% 64.9%;
53
+ --accent: 240 3.7% 15.9%;
54
+ --accent-foreground: 0 0% 98%;
55
+ --destructive: 0 62.8% 30.6%;
56
+ --destructive-foreground: 0 0% 98%;
57
+ --border: 240 3.7% 15.9%;
58
+ --input: 240 3.7% 15.9%;
59
+ --ring: 240 4.9% 83.9%;
60
+ }
61
+ }
62
+ `
63
+
64
+ // ─── Tailwind Config ────────────────────────────────────────────────────────
65
+
66
+ const TAILWIND_CONFIG_CONTENT = `/** @type {import('tailwindcss').Config} */
67
+ const novaui = require("novaui-components/tailwind");
68
+
69
+ module.exports = {
70
+ content: [
71
+ "./App.{js,jsx,ts,tsx}",
72
+ "./src/**/*.{js,jsx,ts,tsx}",
73
+ "./node_modules/novaui-components/src/**/*.{js,jsx,ts,tsx}",
74
+ ],
75
+ presets: [require("nativewind/preset"), novaui],
76
+ theme: {
77
+ extend: {},
78
+ },
79
+ plugins: [],
80
+ };
81
+ `
82
+
83
+ // ─── Utils ──────────────────────────────────────────────────────────────────
84
+
85
+ const UTILS_CONTENT = `import { type ClassValue, clsx } from "clsx"
86
+ import { twMerge } from "tailwind-merge"
87
+
88
+ export function cn(...inputs: ClassValue[]) {
89
+ return twMerge(clsx(inputs))
90
+ }
91
+ `
92
+
93
+ // ─── Helpers ────────────────────────────────────────────────────────────────
94
+
95
+ function detectPackageManager() {
96
+ const userAgent = process.env.npm_config_user_agent || ""
97
+ if (userAgent.startsWith("yarn")) return "yarn add"
98
+ if (userAgent.startsWith("pnpm")) return "pnpm add"
99
+ if (userAgent.startsWith("bun")) return "bun add"
100
+ return "npm install"
101
+ }
102
+
103
+ function ensureDir(dir) {
104
+ if (!fs.existsSync(dir)) {
105
+ fs.mkdirSync(dir, { recursive: true })
106
+ }
107
+ }
108
+
109
+ function writeIfNotExists(filePath, content, label) {
110
+ if (fs.existsSync(filePath)) {
111
+ console.log(`ℹ ${label} already exists, skipping.`)
112
+ return false
113
+ }
114
+ fs.writeFileSync(filePath, content)
115
+ console.log(`✓ Created ${label}`)
116
+ return true
117
+ }
118
+
119
+ // ─── Commands ───────────────────────────────────────────────────────────────
120
+
121
+ async function init() {
122
+ console.log("")
123
+ console.log(" ◆ NovaUI – Initializing project...")
124
+ console.log("")
125
+
126
+ const cwd = process.cwd()
127
+
128
+ // 1. Create src/lib/utils.ts
129
+ const utilsDir = path.join(cwd, "src", "lib")
130
+ ensureDir(utilsDir)
131
+ writeIfNotExists(path.join(utilsDir, "utils.ts"), UTILS_CONTENT, "src/lib/utils.ts")
132
+
133
+ // 2. Create src/global.css
134
+ const srcDir = path.join(cwd, "src")
135
+ ensureDir(srcDir)
136
+ writeIfNotExists(path.join(srcDir, "global.css"), GLOBAL_CSS_CONTENT, "src/global.css")
137
+
138
+ // 3. Create tailwind.config.js
139
+ writeIfNotExists(
140
+ path.join(cwd, "tailwind.config.js"),
141
+ TAILWIND_CONFIG_CONTENT,
142
+ "tailwind.config.js"
143
+ )
144
+
145
+ // 4. Install core dependencies
146
+ console.log("")
147
+ console.log(" ◆ Installing dependencies...")
148
+ console.log("")
149
+
150
+ const installCmd = detectPackageManager()
151
+ const deps = [
152
+ "novaui-components",
153
+ "nativewind",
154
+ "tailwindcss",
155
+ "clsx",
156
+ "tailwind-merge",
157
+ "class-variance-authority",
158
+ ]
159
+
160
+ try {
161
+ execSync(`${installCmd} ${deps.join(" ")}`, { stdio: "inherit" })
162
+ } catch {
163
+ console.error("")
164
+ console.error(" ✗ Failed to install dependencies. Please install manually:")
165
+ console.error(` ${installCmd} ${deps.join(" ")}`)
166
+ }
167
+
168
+ console.log("")
169
+ console.log(" ✓ Project initialized!")
170
+ console.log("")
171
+ console.log(" Next steps:")
172
+ console.log(' 1. Import "src/global.css" in your root layout/entry file')
173
+ console.log(" 2. Start adding components:")
174
+ console.log(" npx novaui add button")
175
+ console.log("")
176
+ }
177
+
178
+ async function add(componentName) {
179
+ if (!componentName) {
180
+ console.error("Usage: novaui add <component-name>")
181
+ process.exit(1)
182
+ }
183
+
184
+ const cwd = process.cwd()
185
+
186
+ console.log("")
187
+ console.log(` ◆ NovaUI – Adding "${componentName}"...`)
188
+ console.log("")
189
+
190
+ // 1. Fetch registry
191
+ console.log(" Fetching registry...")
192
+ const registryResponse = await fetch(`${BASE_URL}/registry.json`)
193
+
194
+ if (!registryResponse.ok) {
195
+ throw new Error(`Failed to fetch registry: ${registryResponse.statusText}`)
196
+ }
197
+
198
+ const registry = await registryResponse.json()
199
+
200
+ if (!registry[componentName]) {
201
+ console.error(` ✗ Component "${componentName}" not found in registry.`)
202
+ console.log("")
203
+ console.log(" Available components:")
204
+ console.log(" " + Object.keys(registry).join(", "))
205
+ process.exit(1)
206
+ }
207
+
208
+ const config = registry[componentName]
209
+ const targetBaseDir = path.join(cwd, "src", "components", "ui")
210
+ ensureDir(targetBaseDir)
211
+
212
+ // 2. Ensure utils.ts exists
213
+ const utilsDir = path.join(cwd, "src", "lib")
214
+ const utilsPath = path.join(utilsDir, "utils.ts")
215
+
216
+ if (!fs.existsSync(utilsPath)) {
217
+ ensureDir(utilsDir)
218
+ fs.writeFileSync(utilsPath, UTILS_CONTENT)
219
+ console.log(" ✓ Created src/lib/utils.ts")
220
+ }
221
+
222
+ // 3. Fetch and write component files
223
+ for (const file of config.files) {
224
+ const fileUrl = `${BASE_URL}/${file}`
225
+ const fileName = path.basename(file)
226
+ const destPath = path.join(targetBaseDir, fileName)
227
+
228
+ console.log(` Downloading ${fileName}...`)
229
+ const fileResponse = await fetch(fileUrl)
230
+
231
+ if (!fileResponse.ok) {
232
+ console.error(` ✗ Failed to download ${fileName}`)
233
+ continue
234
+ }
235
+
236
+ const content = await fileResponse.text()
237
+ fs.writeFileSync(destPath, content)
238
+ console.log(` ✓ Added ${fileName}`)
239
+ }
240
+
241
+ // 4. Install component dependencies
242
+ if (config.dependencies && config.dependencies.length > 0) {
243
+ console.log("")
244
+ console.log(` Installing dependencies: ${config.dependencies.join(", ")}...`)
245
+ try {
246
+ const installCmd = detectPackageManager()
247
+ execSync(`${installCmd} ${config.dependencies.join(" ")}`, {
248
+ stdio: "inherit",
249
+ })
250
+ } catch {
251
+ console.error(" ✗ Failed to install dependencies automatically.")
252
+ }
253
+ }
254
+
255
+ console.log("")
256
+ console.log(` ✓ Successfully added "${componentName}"!`)
257
+ console.log("")
258
+ }
259
+
260
+ function showHelp() {
261
+ console.log("")
262
+ console.log(" NovaUI CLI")
263
+ console.log("")
264
+ console.log(" Usage:")
265
+ console.log(" novaui init Initialize project with Tailwind config, global.css, and utils")
266
+ console.log(" novaui add <component> Add a component to your project")
267
+ console.log("")
268
+ console.log(" Examples:")
269
+ console.log(" npx novaui-cli init")
270
+ console.log(" npx novaui-cli add button")
271
+ console.log(" npx novaui-cli add card")
272
+ console.log("")
273
+ }
274
+
275
+ // ─── Main ───────────────────────────────────────────────────────────────────
276
+
277
+ const command = process.argv[2]
278
+ const arg = process.argv[3]
279
+
280
+ async function main() {
281
+ try {
282
+ switch (command) {
283
+ case "init":
284
+ await init()
285
+ break
286
+ case "add":
287
+ await add(arg)
288
+ break
289
+ case "--help":
290
+ case "-h":
291
+ showHelp()
292
+ break
293
+ default:
294
+ if (command) {
295
+ // Backwards compatible: treat unknown command as component name
296
+ await add(command)
297
+ } else {
298
+ showHelp()
299
+ }
300
+ break
301
+ }
302
+ } catch (error) {
303
+ console.error("")
304
+ console.error(` ✗ Error: ${error.message}`)
305
+ process.exit(1)
306
+ }
307
+ }
308
+
309
+ main()