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.
- package/package.json +24 -0
- 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()
|