vaderjs-native 1.0.13 ā 1.0.15
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 +122 -83
- package/cli.ts +586 -196
- package/index.ts +73 -1
- package/main.ts +321 -161
- package/package.json +3 -2
- package/templates/i.txt +1 -0
- package/plugins/tailwind.ts +0 -53
package/cli.ts
CHANGED
|
@@ -5,162 +5,446 @@ import fsSync from "fs";
|
|
|
5
5
|
import path from "path";
|
|
6
6
|
import readline from "readline";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
)
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
|
|
10
|
+
/* ---------------------------------- utils --------------------------------- */
|
|
11
|
+
|
|
12
|
+
function ask(question: string): Promise<string> {
|
|
13
|
+
const rl = readline.createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout,
|
|
16
|
+
});
|
|
17
|
+
return new Promise((resolve) =>
|
|
18
|
+
rl.question(question + " ", (answer) => {
|
|
19
|
+
rl.close();
|
|
20
|
+
resolve(answer.trim());
|
|
21
|
+
})
|
|
22
|
+
);
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
async function run(cmd: string, args: string[] = []) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
} catch (error) {
|
|
34
|
-
console.error(`Error executing command: ${error}`);
|
|
35
|
-
process.exit(1);
|
|
25
|
+
async function run(cmd: string, args: string[] = []): Promise<void> {
|
|
26
|
+
try {
|
|
27
|
+
const proc = Bun.spawn([cmd, ...args], {
|
|
28
|
+
stdout: "inherit",
|
|
29
|
+
stderr: "inherit",
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const status = await proc.exited;
|
|
33
|
+
if (status !== 0) {
|
|
34
|
+
console.error(`Command failed: ${cmd} ${args.join(" ")}`);
|
|
35
|
+
process.exit(1);
|
|
36
36
|
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
console.error(`Error executing command: ${error}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
function logSection(title: string) {
|
|
44
|
+
console.log(`\n${title}`);
|
|
45
|
+
console.log("ā".repeat(title.length));
|
|
46
|
+
}
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
);
|
|
46
|
-
if (!projectDir) projectDir = ".";
|
|
48
|
+
function getFlags() {
|
|
49
|
+
return new Set(process.argv.slice(2));
|
|
50
|
+
}
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
if (!fsSync.existsSync(projectDir)) {
|
|
50
|
-
await fs.mkdir(projectDir, { recursive: true });
|
|
51
|
-
console.log(`Created directory: ${projectDir}`);
|
|
52
|
-
}
|
|
52
|
+
/* -------------------------- Vite-like Template --------------------------- */
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
const UI_FRAMEWORKS = {
|
|
55
|
+
none: {
|
|
56
|
+
name: "None (Basic)",
|
|
57
|
+
deps: [],
|
|
58
|
+
description: "Basic setup without UI framework"
|
|
59
|
+
},
|
|
60
|
+
daisyui: {
|
|
61
|
+
name: "VaderUI (DaisyUI)",
|
|
62
|
+
deps: ["vaderjs-daisyui", "daisyui", "@tailwindcss/postcss", "autoprefixer", "postcss"],
|
|
63
|
+
configNeeded: true,
|
|
64
|
+
cssFile: `@import "tailwindcss";
|
|
65
|
+
@plugin "daisyui";`,
|
|
66
|
+
description: "A comprehensive DaisyUI component library for Vader.js"
|
|
67
|
+
},
|
|
68
|
+
bootstrap: {
|
|
69
|
+
name: "Bootstrap 5",
|
|
70
|
+
deps: ["vaderjs-bootstrap", "bootstrap"],
|
|
71
|
+
configNeeded: false,
|
|
72
|
+
cssFile: `/* Import Bootstrap CSS in your HTML */
|
|
73
|
+
/* Or use CDN: <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet"> */`,
|
|
74
|
+
description: "Bootstrap 5 components rebuilt for Vader.js"
|
|
75
|
+
}
|
|
76
|
+
};
|
|
60
77
|
|
|
61
|
-
|
|
62
|
-
const appDir = path.join(projectDir, "app");
|
|
63
|
-
const srcDir = path.join(projectDir, "src");
|
|
64
|
-
const publicDir = path.join(projectDir, "public");
|
|
78
|
+
/* ---------------------------------- init ---------------------------------- */
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
80
|
+
/* ---------------------------------- init ---------------------------------- */
|
|
81
|
+
|
|
82
|
+
export async function initProject(dir?: string) {
|
|
83
|
+
const flags = getFlags();
|
|
84
|
+
const autoYes = flags.has("--yes");
|
|
85
|
+
|
|
86
|
+
console.log("š Initializing Vader.js project");
|
|
87
|
+
|
|
88
|
+
const projectDir = path.resolve(cwd, dir || ".");
|
|
89
|
+
if (!fsSync.existsSync(projectDir)) {
|
|
90
|
+
await fs.mkdir(projectDir, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const files = fsSync.readdirSync(projectDir);
|
|
94
|
+
if (files.length && !autoYes) {
|
|
95
|
+
const confirm = await ask("Directory is not empty. Continue? (y/n):");
|
|
96
|
+
if (confirm !== "y") process.exit(0);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Ask for TypeScript or JavaScript
|
|
100
|
+
console.log("\nSelect language:");
|
|
101
|
+
console.log(" 1. JavaScript (recommended for beginners)");
|
|
102
|
+
console.log(" 2. TypeScript (recommended for production)");
|
|
103
|
+
|
|
104
|
+
let langChoice = await ask("Choose (1-2):");
|
|
105
|
+
const useTypeScript = langChoice === "2";
|
|
106
|
+
const fileExt = useTypeScript ? "tsx" : "jsx";
|
|
107
|
+
const configExt = useTypeScript ? "ts" : "js";
|
|
108
|
+
|
|
109
|
+
// Ask for UI framework
|
|
110
|
+
console.log("\nSelect a UI framework:");
|
|
111
|
+
Object.entries(UI_FRAMEWORKS).forEach(([key, value], index) => {
|
|
112
|
+
console.log(` ${index + 1}. ${value.name}`);
|
|
113
|
+
console.log(` ${value.description}`);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
let frameworkChoice = await ask(`Choose (1-${Object.keys(UI_FRAMEWORKS).length}):`);
|
|
117
|
+
let selectedFramework = Object.keys(UI_FRAMEWORKS)[parseInt(frameworkChoice) - 1];
|
|
118
|
+
|
|
119
|
+
while (!selectedFramework || !UI_FRAMEWORKS[selectedFramework]) {
|
|
120
|
+
console.log(`Invalid choice. Please select 1-${Object.keys(UI_FRAMEWORKS).length}`);
|
|
121
|
+
frameworkChoice = await ask(`Choose (1-${Object.keys(UI_FRAMEWORKS).length}):`);
|
|
122
|
+
selectedFramework = Object.keys(UI_FRAMEWORKS)[parseInt(frameworkChoice) - 1];
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const framework = UI_FRAMEWORKS[selectedFramework];
|
|
126
|
+
|
|
127
|
+
// Ask for platform support
|
|
128
|
+
console.log("\nSelect platforms to support:");
|
|
129
|
+
const androidResponse = await ask(" Include Android support? (y/n):");
|
|
130
|
+
const windowsResponse = await ask(" Include Windows support? (y/n):");
|
|
131
|
+
|
|
132
|
+
const platforms = {
|
|
133
|
+
android: androidResponse.toLowerCase() === 'y',
|
|
134
|
+
windows: windowsResponse.toLowerCase() === 'y',
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
logSection("š Creating folders");
|
|
138
|
+
|
|
139
|
+
for (const d of ["app", "public", "src"]) {
|
|
140
|
+
const p = path.join(projectDir, d);
|
|
141
|
+
if (!fsSync.existsSync(p)) {
|
|
142
|
+
await fs.mkdir(p, { recursive: true });
|
|
143
|
+
console.log(`created ${d}/`);
|
|
71
144
|
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Create platform-specific asset directories
|
|
148
|
+
if (platforms.android) {
|
|
149
|
+
await fs.mkdir(path.join(projectDir, "assets/android"), { recursive: true });
|
|
150
|
+
}
|
|
151
|
+
if (platforms.windows) {
|
|
152
|
+
await fs.mkdir(path.join(projectDir, "assets/windows"), { recursive: true });
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
logSection("š§± Writing files");
|
|
72
156
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
157
|
+
// Create main app component based on framework and language
|
|
158
|
+
let appCode = "";
|
|
159
|
+
if (selectedFramework === "daisyui") {
|
|
160
|
+
appCode = `import * as Vader from "vaderjs-native"\nimport { useState } from "vaderjs-native";
|
|
161
|
+
import Button from "vaderjs-daisyui/Components/Actions/Button";
|
|
162
|
+
import { Card } from "vaderjs-daisyui/Components/Data/Display/Card";
|
|
163
|
+
import { Badge } from "vaderjs-daisyui/Components/Data/Display/Badge";
|
|
76
164
|
|
|
77
|
-
function
|
|
78
|
-
|
|
165
|
+
function Main() {
|
|
166
|
+
const [count, setCount] = useState(0);
|
|
167
|
+
|
|
79
168
|
return (
|
|
80
|
-
<div
|
|
81
|
-
<
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
169
|
+
<div className="min-h-screen bg-base-200 p-8">
|
|
170
|
+
<div className="max-w-4xl mx-auto">
|
|
171
|
+
<div className="text-center mb-8">
|
|
172
|
+
<h1 className="text-4xl font-bold text-primary mb-4">
|
|
173
|
+
š Welcome to Vader.js!
|
|
174
|
+
</h1>
|
|
175
|
+
<p className="text-lg text-base-content">
|
|
176
|
+
With ${framework.name} components
|
|
177
|
+
</p>
|
|
178
|
+
<Badge color="primary" className="mt-2">
|
|
179
|
+
v1.0.0
|
|
180
|
+
</Badge>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<Card className="mb-6" title="Interactive Demo">
|
|
184
|
+
<div className="space-y-4">
|
|
185
|
+
<div className="flex items-center justify-between">
|
|
186
|
+
<div>
|
|
187
|
+
<p className="text-xl font-semibold">Counter: {count}</p>
|
|
188
|
+
<p className="text-sm text-base-content/70">
|
|
189
|
+
Click the button to increment
|
|
190
|
+
</p>
|
|
191
|
+
</div>
|
|
192
|
+
<Badge color={count > 5 ? "success" : "warning"}>
|
|
193
|
+
{count > 5 ? "Pro User" : "Getting Started"}
|
|
194
|
+
</Badge>
|
|
195
|
+
</div>
|
|
196
|
+
<div className="flex gap-3">
|
|
197
|
+
<Button color="primary" onClick={() => setCount(count + 1)}>
|
|
198
|
+
Increment
|
|
199
|
+
</Button>
|
|
200
|
+
<Button color="secondary" onClick={() => setCount(0)}>
|
|
201
|
+
Reset
|
|
202
|
+
</Button>
|
|
203
|
+
<Button color="accent" onClick={() => alert(\`Count is: \${count}\`)}>
|
|
204
|
+
Show Alert
|
|
205
|
+
</Button>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div slot="actions" className="text-sm text-base-content/60">
|
|
209
|
+
Try editing app/index.${fileExt}
|
|
210
|
+
</div>
|
|
211
|
+
</Card>
|
|
212
|
+
|
|
213
|
+
<div className="grid md:grid-cols-2 gap-6">
|
|
214
|
+
<Card title="Quick Start">
|
|
215
|
+
<ul className="space-y-2">
|
|
216
|
+
<li>1. Edit <code>app/index.${fileExt}</code></li>
|
|
217
|
+
<li>2. Run <code>bun run dev</code></li>
|
|
218
|
+
<li>3. Open browser to localhost:3000</li>
|
|
219
|
+
</ul>
|
|
220
|
+
</Card>
|
|
221
|
+
|
|
222
|
+
<Card title="Features">
|
|
223
|
+
<ul className="space-y-2">
|
|
224
|
+
<li>ā
Vader.js reactive system</li>
|
|
225
|
+
<li>ā
${framework.name} components</li>
|
|
226
|
+
<li>ā
Hot reload development</li>
|
|
227
|
+
<li>ā
Multi-platform support</li>
|
|
228
|
+
</ul>
|
|
229
|
+
</Card>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
<div className="mt-8 text-center text-sm text-base-content/60">
|
|
233
|
+
Learn more at https://vaderjs.dev
|
|
234
|
+
</div>
|
|
235
|
+
</div>
|
|
89
236
|
</div>
|
|
90
237
|
);
|
|
91
|
-
}
|
|
238
|
+
}\n Vader.render(Vader.createElement(Main), document.getElementById("app"))`;
|
|
239
|
+
} else if (selectedFramework === "bootstrap") {
|
|
240
|
+
appCode = `import * as Vader from "vaderjs-native"\nimport { useState } from "vaderjs-native";
|
|
241
|
+
import { Container, Alert, Button, Card, Badge } from "vaderjs-bootstrap";
|
|
242
|
+
|
|
243
|
+
function Main() {
|
|
244
|
+
const [count, setCount] = useState(0);
|
|
92
245
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
246
|
+
return (
|
|
247
|
+
<Container className="py-5">
|
|
248
|
+
<Alert type="info" dismissible className="mb-4">
|
|
249
|
+
<strong>Welcome to Vader.js!</strong> This is a Bootstrap 5 starter.
|
|
250
|
+
</Alert>
|
|
251
|
+
|
|
252
|
+
<Card className="mb-4">
|
|
253
|
+
<Card.Header className="d-flex justify-content-between align-items-center">
|
|
254
|
+
<h5 className="mb-0">Interactive Demo</h5>
|
|
255
|
+
<Badge bg={count > 5 ? "success" : "warning"}>
|
|
256
|
+
{count > 5 ? "Advanced" : "Beginner"}
|
|
257
|
+
</Badge>
|
|
258
|
+
</Card.Header>
|
|
259
|
+
<Card.Body>
|
|
260
|
+
<p className="lead">Counter: {count}</p>
|
|
261
|
+
<p className="text-muted mb-3">Click the buttons to interact</p>
|
|
262
|
+
<div className="d-flex gap-2">
|
|
263
|
+
<Button variant="primary" onClick={() => setCount(count + 1)}>
|
|
264
|
+
Increment
|
|
265
|
+
</Button>
|
|
266
|
+
<Button variant="secondary" onClick={() => setCount(0)}>
|
|
267
|
+
Reset
|
|
268
|
+
</Button>
|
|
269
|
+
<Button variant="info" onClick={() => alert(\`Count is: \${count}\`)}>
|
|
270
|
+
Show Alert
|
|
271
|
+
</Button>
|
|
272
|
+
</div>
|
|
273
|
+
</Card.Body>
|
|
274
|
+
<Card.Footer className="text-muted">
|
|
275
|
+
Try editing app/index.${fileExt}
|
|
276
|
+
</Card.Footer>
|
|
277
|
+
</Card>
|
|
278
|
+
|
|
279
|
+
<div className="row">
|
|
280
|
+
<div className="col-md-6 mb-3">
|
|
281
|
+
<Card>
|
|
282
|
+
<Card.Body>
|
|
283
|
+
<Card.Title>Quick Start</Card.Title>
|
|
284
|
+
<ol className="mb-0">
|
|
285
|
+
<li>Edit <code>app/index.${fileExt}</code></li>
|
|
286
|
+
<li>Run <code>bun run dev</code></li>
|
|
287
|
+
<li>Open browser to localhost:3000</li>
|
|
288
|
+
</ol>
|
|
289
|
+
</Card.Body>
|
|
290
|
+
</Card>
|
|
291
|
+
</div>
|
|
292
|
+
<div className="col-md-6 mb-3">
|
|
293
|
+
<Card>
|
|
294
|
+
<Card.Body>
|
|
295
|
+
<Card.Title>Features</Card.Title>
|
|
296
|
+
<ul className="mb-0">
|
|
297
|
+
<li>ā
Vader.js reactive system</li>
|
|
298
|
+
<li>ā
Bootstrap 5 components</li>
|
|
299
|
+
<li>ā
Hot reload development</li>
|
|
300
|
+
<li>ā
Multi-platform support</li>
|
|
301
|
+
</ul>
|
|
302
|
+
</Card.Body>
|
|
303
|
+
</Card>
|
|
304
|
+
</div>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<footer className="mt-4 text-center text-muted small">
|
|
308
|
+
Learn more at https://vaderjs.dev
|
|
309
|
+
</footer>
|
|
310
|
+
</Container>
|
|
311
|
+
);
|
|
312
|
+
}\nVader.render(Vader.createElement(Main), document.getElementById("app"))`;
|
|
313
|
+
} else {
|
|
314
|
+
appCode = `import * as Vader from "vaderjs-native"\nimport { useState } from "vaderjs-native";
|
|
96
315
|
|
|
97
|
-
function
|
|
98
|
-
|
|
316
|
+
function Main() {
|
|
317
|
+
const [count, setCount] = useState(0);
|
|
318
|
+
|
|
99
319
|
return (
|
|
100
|
-
<div style={{
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
320
|
+
<div style={{
|
|
321
|
+
maxWidth: "600px",
|
|
322
|
+
margin: "0 auto",
|
|
323
|
+
padding: "2rem",
|
|
324
|
+
fontFamily: "system-ui, sans-serif",
|
|
325
|
+
lineHeight: 1.5
|
|
326
|
+
}}>
|
|
327
|
+
<h1 style={{ textAlign: "center", color: "#333" }}>
|
|
328
|
+
š Welcome to Vader.js!
|
|
329
|
+
</h1>
|
|
330
|
+
|
|
331
|
+
<div style={{
|
|
332
|
+
background: "#f8f9fa",
|
|
333
|
+
borderRadius: "12px",
|
|
334
|
+
padding: "2rem",
|
|
335
|
+
marginTop: "2rem",
|
|
336
|
+
boxShadow: "0 4px 6px rgba(0,0,0,0.1)"
|
|
337
|
+
}}>
|
|
338
|
+
<h2 style={{ marginTop: 0 }}>Interactive Demo</h2>
|
|
339
|
+
<p style={{ fontSize: "1.5rem", fontWeight: "bold", color: "#007bff" }}>
|
|
340
|
+
Counter: {count}
|
|
341
|
+
</p>
|
|
342
|
+
<p style={{ color: "#666" }}>
|
|
343
|
+
Click the buttons below to interact with the counter
|
|
344
|
+
</p>
|
|
345
|
+
|
|
346
|
+
<div style={{ display: "flex", gap: "1rem", marginTop: "1.5rem" }}>
|
|
347
|
+
<button
|
|
348
|
+
onClick={() => setCount(count + 1)}
|
|
349
|
+
style={{
|
|
350
|
+
padding: "0.75rem 1.5rem",
|
|
351
|
+
background: "#007bff",
|
|
352
|
+
color: "white",
|
|
353
|
+
border: "none",
|
|
354
|
+
borderRadius: "6px",
|
|
355
|
+
fontSize: "1rem",
|
|
356
|
+
cursor: "pointer"
|
|
357
|
+
}}
|
|
358
|
+
>
|
|
359
|
+
Increment
|
|
360
|
+
</button>
|
|
361
|
+
|
|
362
|
+
<button
|
|
363
|
+
onClick={() => setCount(0)}
|
|
364
|
+
style={{
|
|
365
|
+
padding: "0.75rem 1.5rem",
|
|
366
|
+
background: "#6c757d",
|
|
367
|
+
color: "white",
|
|
368
|
+
border: "none",
|
|
369
|
+
borderRadius: "6px",
|
|
370
|
+
fontSize: "1rem",
|
|
371
|
+
cursor: "pointer"
|
|
372
|
+
}}
|
|
373
|
+
>
|
|
374
|
+
Reset
|
|
375
|
+
</button>
|
|
376
|
+
|
|
377
|
+
<button
|
|
378
|
+
onClick={() => alert(\`Current count: \${count}\`)}
|
|
379
|
+
style={{
|
|
380
|
+
padding: "0.75rem 1.5rem",
|
|
381
|
+
background: "#28a745",
|
|
382
|
+
color: "white",
|
|
383
|
+
border: "none",
|
|
384
|
+
borderRadius: "6px",
|
|
385
|
+
fontSize: "1rem",
|
|
386
|
+
cursor: "pointer"
|
|
387
|
+
}}
|
|
388
|
+
>
|
|
389
|
+
Show Alert
|
|
390
|
+
</button>
|
|
391
|
+
</div>
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
<div style={{ marginTop: "2rem" }}>
|
|
395
|
+
<h3>Next Steps:</h3>
|
|
396
|
+
<ul>
|
|
397
|
+
<li>Edit <code>app/index.${fileExt}</code> to customize this page</li>
|
|
398
|
+
<li>Run <code>bun run dev</code> to start the development server</li>
|
|
399
|
+
<li>Visit <code>localhost:3000</code> in your browser</li>
|
|
400
|
+
<li>Check out <a href="https://vaderjs.dev">vaderjs.dev</a> for documentation</li>
|
|
401
|
+
</ul>
|
|
402
|
+
</div>
|
|
104
403
|
</div>
|
|
105
404
|
);
|
|
106
|
-
}
|
|
405
|
+
}\nVader.render(Vader.createElement(Main), document.getElementById("app"))`;
|
|
107
406
|
|
|
108
|
-
|
|
109
|
-
`;
|
|
407
|
+
}
|
|
110
408
|
|
|
111
|
-
|
|
112
|
-
|
|
409
|
+
await fs.writeFile(
|
|
410
|
+
path.join(projectDir, `app/index.${fileExt}`),
|
|
411
|
+
appCode
|
|
412
|
+
);
|
|
413
|
+
console.log(`created app/index.${fileExt}`);
|
|
113
414
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
console.log(`Created public/styles.css`);
|
|
415
|
+
await fs.writeFile(
|
|
416
|
+
path.join(projectDir, "public/styles.css"),
|
|
417
|
+
framework.cssFile || "/* Add your global styles here */"
|
|
418
|
+
);
|
|
419
|
+
console.log(`created public/styles.css`);
|
|
121
420
|
|
|
122
|
-
|
|
421
|
+
// Create root.css for Tailwind/DaisyUI if needed
|
|
422
|
+
if (selectedFramework === "daisyui") {
|
|
423
|
+
await fs.writeFile(
|
|
424
|
+
path.join(projectDir, "root.css"),
|
|
425
|
+
framework.cssFile
|
|
426
|
+
);
|
|
427
|
+
console.log(`created root.css (for Tailwind/DaisyUI)`);
|
|
428
|
+
}
|
|
123
429
|
|
|
430
|
+
// Create vaderjs.config.ts
|
|
431
|
+
let configImport = "";
|
|
432
|
+
let configPlugins = "[]";
|
|
124
433
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
await run("bun", ["install", ...deps]);
|
|
132
|
-
console.log("ā
Dependencies installed.");
|
|
133
|
-
|
|
134
|
-
// If Tailwind requested, create minimal tailwind.config.cjs and postcss.config.cjs
|
|
135
|
-
if (wantsTailwind) {
|
|
136
|
-
const tailwindConfig = `module.exports = {
|
|
137
|
-
content: ["./app/**/*.{js,jsx,ts,tsx}"],
|
|
138
|
-
theme: {
|
|
139
|
-
extend: {},
|
|
140
|
-
},
|
|
141
|
-
plugins: [],
|
|
142
|
-
};`;
|
|
143
|
-
await fs.writeFile(path.join(projectDir, "tailwind.config.cjs"), tailwindConfig);
|
|
144
|
-
console.log("Created tailwind.config.cjs");
|
|
145
|
-
|
|
146
|
-
const postcssConfig = `export default {
|
|
147
|
-
plugins: {
|
|
148
|
-
"@tailwindcss/postcss": {},
|
|
149
|
-
autoprefixer: {},
|
|
434
|
+
if (selectedFramework === "daisyui") {
|
|
435
|
+
configImport = `import daisyui from "vaderjs-daisyui";\n`;
|
|
436
|
+
configPlugins = "[daisyui]";
|
|
437
|
+
} else if (selectedFramework === "bootstrap") {
|
|
438
|
+
configImport = `import bootstrap from "vaderjs-bootstrap";\n`;
|
|
439
|
+
configPlugins = "[bootstrap]";
|
|
150
440
|
}
|
|
151
|
-
};`;
|
|
152
|
-
await fs.writeFile(path.join(projectDir, "postcss.config.cjs"), postcssConfig);
|
|
153
|
-
console.log("Created postcss.config.cjs");
|
|
154
|
-
}
|
|
155
441
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
import defineConfig from "vaderjs-native/config";
|
|
159
|
-
import tailwind from "vaderjs-native/plugins/tailwind";
|
|
442
|
+
const configContent = `${configImport}import defineConfig from "vaderjs-native/config";
|
|
443
|
+
|
|
160
444
|
export default defineConfig({
|
|
161
445
|
app: {
|
|
162
|
-
name: "
|
|
163
|
-
id: "com.example.
|
|
446
|
+
name: "${path.basename(projectDir)}",
|
|
447
|
+
id: "com.example.${path.basename(projectDir).toLowerCase()}",
|
|
164
448
|
version: {
|
|
165
449
|
code: 1,
|
|
166
450
|
name: "1.0.0",
|
|
@@ -168,7 +452,7 @@ export default defineConfig({
|
|
|
168
452
|
},
|
|
169
453
|
|
|
170
454
|
platforms: {
|
|
171
|
-
android: {
|
|
455
|
+
${platforms.android ? `android: {
|
|
172
456
|
minSdk: 24,
|
|
173
457
|
targetSdk: 34,
|
|
174
458
|
permissions: [
|
|
@@ -177,88 +461,194 @@ export default defineConfig({
|
|
|
177
461
|
],
|
|
178
462
|
icon: "./assets/android/icon.png",
|
|
179
463
|
splash: "./assets/android/splash.png",
|
|
180
|
-
}
|
|
181
|
-
|
|
464
|
+
},` : ''}
|
|
465
|
+
|
|
182
466
|
web: {
|
|
183
|
-
title: "
|
|
467
|
+
title: "${path.basename(projectDir)}",
|
|
184
468
|
themeColor: "#111827",
|
|
185
469
|
},
|
|
186
470
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
471
|
+
${platforms.windows ? `windows: {
|
|
472
|
+
width: 1200,
|
|
473
|
+
height: 800,
|
|
474
|
+
title: "${path.basename(projectDir)}"
|
|
475
|
+
},` : ''}
|
|
190
476
|
},
|
|
191
477
|
|
|
192
|
-
plugins:
|
|
478
|
+
plugins: ${configPlugins}
|
|
193
479
|
});`;
|
|
194
480
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
481
|
+
await fs.writeFile(
|
|
482
|
+
path.join(projectDir, `vaderjs.config.${configExt}`),
|
|
483
|
+
configContent
|
|
484
|
+
);
|
|
485
|
+
console.log(`created vaderjs.config.${configExt}`);
|
|
486
|
+
|
|
487
|
+
// Create package.json if it doesn't exist
|
|
488
|
+
const pkgPath = path.join(projectDir, "package.json");
|
|
489
|
+
if (!fsSync.existsSync(pkgPath)) {
|
|
490
|
+
const packageJson = {
|
|
491
|
+
name: path.basename(projectDir),
|
|
492
|
+
version: "1.0.0",
|
|
493
|
+
type: "module",
|
|
494
|
+
scripts: {
|
|
495
|
+
dev: "bun run vaderjs dev",
|
|
496
|
+
build: "bun run vaderjs build",
|
|
497
|
+
serve: "bun run vaderjs serve"
|
|
498
|
+
},
|
|
499
|
+
dependencies: {
|
|
500
|
+
"vaderjs-native": "latest"
|
|
501
|
+
},
|
|
502
|
+
devDependencies: {}
|
|
205
503
|
};
|
|
206
|
-
await fs.writeFile(path.join(projectDir, "jsconfig.json"), JSON.stringify(jsConfig, null, 2));
|
|
207
|
-
console.log("Created jsconfig.json");
|
|
208
|
-
|
|
209
|
-
// Final instructions
|
|
210
|
-
const pkgJsonPath = path.join(projectDir, "package.json");
|
|
211
|
-
|
|
212
|
-
if (!fsSync.existsSync(pkgJsonPath)) {
|
|
213
|
-
// If package.json doesn't exist, create it with basic content
|
|
214
|
-
const pkg = {
|
|
215
|
-
name: path.basename(projectDir),
|
|
216
|
-
version: "1.0.0",
|
|
217
|
-
scripts: {
|
|
218
|
-
"android:dev": "bun run vaderjs android:dev",
|
|
219
|
-
"android:build": "bun run vaderjs android:build",
|
|
220
|
-
dev: "bun run vaderjs dev",
|
|
221
|
-
build: "bun run vaderjs build",
|
|
222
|
-
serve: "bun run vaderjs serve",
|
|
223
|
-
},
|
|
224
|
-
dependencies: {
|
|
225
|
-
vaderjs: "latest",
|
|
226
|
-
},
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
// If Tailwind is requested, add it to the dependencies
|
|
230
|
-
if (wantsTailwind) {
|
|
231
|
-
pkg.dependencies.tailwindcss = "latest";
|
|
232
|
-
pkg.dependencies["@tailwindcss/postcss"] = "latest";
|
|
233
|
-
pkg.dependencies.postcss = "latest";
|
|
234
|
-
pkg.dependencies.autoprefixer = "latest";
|
|
235
|
-
}
|
|
236
504
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
pkgJson.dependencies["@tailwindcss/postcss"] = "latest";
|
|
247
|
-
pkgJson.dependencies.postcss = "latest";
|
|
248
|
-
pkgJson.dependencies.autoprefixer = "latest";
|
|
249
|
-
}
|
|
505
|
+
// Add TypeScript if selected
|
|
506
|
+
if (useTypeScript) {
|
|
507
|
+
packageJson.devDependencies = {
|
|
508
|
+
...packageJson.devDependencies,
|
|
509
|
+
"typescript": "^5.0.0",
|
|
510
|
+
"@types/bun": "latest",
|
|
511
|
+
"vaderjs-types"
|
|
512
|
+
};
|
|
513
|
+
}
|
|
250
514
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
515
|
+
// Add UI framework dependencies
|
|
516
|
+
if (selectedFramework !== "none") {
|
|
517
|
+
for (const dep of framework.deps) {
|
|
518
|
+
if (dep.startsWith("vaderjs-")) {
|
|
519
|
+
packageJson.dependencies[dep] = "latest";
|
|
520
|
+
} else {
|
|
521
|
+
packageJson.devDependencies[dep] = "latest";
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
256
525
|
|
|
257
|
-
|
|
258
|
-
|
|
526
|
+
// Add platform-specific scripts
|
|
527
|
+
if (platforms.android) {
|
|
528
|
+
packageJson.scripts["android:dev"] = "bun run vaderjs android:dev";
|
|
529
|
+
packageJson.scripts["android:build"] = "bun run vaderjs android:build";
|
|
530
|
+
}
|
|
531
|
+
if (platforms.windows) {
|
|
532
|
+
packageJson.scripts["windows:dev"] = "bun run vaderjs windows:dev";
|
|
533
|
+
packageJson.scripts["windows:build"] = "bun run vaderjs windows:build";
|
|
259
534
|
}
|
|
260
535
|
|
|
261
|
-
|
|
262
|
-
console.log(`
|
|
263
|
-
|
|
536
|
+
await fs.writeFile(pkgPath, JSON.stringify(packageJson, null, 2));
|
|
537
|
+
console.log(`created package.json`);
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
logSection("š¦ Installing dependencies");
|
|
541
|
+
await run("bun", ["install", "--force"]);
|
|
542
|
+
|
|
543
|
+
console.log("\nā
Project ready!");
|
|
544
|
+
console.log(`\nNext steps:`);
|
|
545
|
+
console.log(` cd ${path.relative(cwd, projectDir)}`);
|
|
546
|
+
console.log(` bun run dev`);
|
|
547
|
+
console.log(` Open http://localhost:3000`);
|
|
548
|
+
|
|
549
|
+
if (selectedFramework === "daisyui") {
|
|
550
|
+
console.log(`\nVaderUI components available:`);
|
|
551
|
+
console.log(` import Button from 'vaderjs-daisyui/Components/Actions/Button'`);
|
|
552
|
+
console.log(` import { Card } from 'vaderjs-daisyui/Components/Data/Display/Card'`);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if (selectedFramework === "bootstrap") {
|
|
556
|
+
console.log(`\nBootstrap components available:`);
|
|
557
|
+
console.log(` import { Button, Card } from 'vaderjs-bootstrap'`);
|
|
558
|
+
}
|
|
264
559
|
}
|
|
560
|
+
|
|
561
|
+
/* ---------------------------------- add ----------------------------------- */
|
|
562
|
+
|
|
563
|
+
export async function addPlugin(name: string) {
|
|
564
|
+
if (!name) {
|
|
565
|
+
console.error("Please specify a plugin to add.");
|
|
566
|
+
process.exit(1);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const flags = getFlags();
|
|
570
|
+
const force = flags.has("--force");
|
|
571
|
+
|
|
572
|
+
const pkgName = name.startsWith("vaderjs-") ? name : `vaderjs-${name}`;
|
|
573
|
+
const importName = pkgName.replace(/^vaderjs-/, "").replace(/-/g, "_");
|
|
574
|
+
|
|
575
|
+
logSection(`ā Adding plugin: ${pkgName}`);
|
|
576
|
+
|
|
577
|
+
const args = ["add", pkgName];
|
|
578
|
+
if (force) args.push("--force");
|
|
579
|
+
|
|
580
|
+
await run("bun", args);
|
|
581
|
+
|
|
582
|
+
const configPath = path.join(cwd, "vaderjs.config.ts");
|
|
583
|
+
if (!fsSync.existsSync(configPath)) {
|
|
584
|
+
console.warn("ā ļø vaderjs.config.ts not found, skipping registration");
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
let config = await fs.readFile(configPath, "utf8");
|
|
589
|
+
|
|
590
|
+
if (config.includes(`from "${pkgName}"`)) {
|
|
591
|
+
console.log("ā¹ļø Plugin already registered");
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
config =
|
|
596
|
+
`import ${importName} from "${pkgName}";\n` +
|
|
597
|
+
config.replace(/plugins:\s*\[/, `plugins: [${importName}, `);
|
|
598
|
+
|
|
599
|
+
await fs.writeFile(configPath, config);
|
|
600
|
+
console.log("ā Plugin registered");
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
/* -------------------------------- remove ---------------------------------- */
|
|
604
|
+
|
|
605
|
+
export async function removePlugin(name: string) {
|
|
606
|
+
if (!name) {
|
|
607
|
+
console.error("Please specify a plugin to remove.");
|
|
608
|
+
process.exit(1);
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
const pkgName = name.startsWith("vaderjs-") ? name : `vaderjs-${name}`;
|
|
612
|
+
const importName = pkgName.replace(/^vaderjs-/, "").replace(/-/g, "_");
|
|
613
|
+
|
|
614
|
+
logSection(`ā Removing plugin: ${pkgName}`);
|
|
615
|
+
|
|
616
|
+
await run("bun", ["remove", pkgName]);
|
|
617
|
+
|
|
618
|
+
const configPath = path.join(cwd, "vaderjs.config.ts");
|
|
619
|
+
if (!fsSync.existsSync(configPath)) return;
|
|
620
|
+
|
|
621
|
+
let config = await fs.readFile(configPath, "utf8");
|
|
622
|
+
|
|
623
|
+
config = config
|
|
624
|
+
.replace(new RegExp(`import ${importName} from ".*?";\\n?`, "g"), "")
|
|
625
|
+
.replace(new RegExp(`\\b${importName},?\\s*`, "g"), "");
|
|
626
|
+
|
|
627
|
+
await fs.writeFile(configPath, config);
|
|
628
|
+
console.log("ā Plugin removed");
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
/* ---------------------------------- list ---------------------------------- */
|
|
632
|
+
|
|
633
|
+
export async function listPlugins() {
|
|
634
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
635
|
+
if (!fsSync.existsSync(pkgPath)) {
|
|
636
|
+
console.log("No package.json found.");
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
|
|
641
|
+
const deps = Object.keys(pkg.dependencies || {}).filter((d) =>
|
|
642
|
+
d.startsWith("vaderjs-")
|
|
643
|
+
);
|
|
644
|
+
|
|
645
|
+
if (!deps.length) {
|
|
646
|
+
console.log("No Vader plugins installed.");
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
logSection("š Installed Vader plugins");
|
|
651
|
+
deps.forEach((d) => console.log("ā¢", d));
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
|