@vicket/create-support 1.1.1 → 1.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/bin/create-vicket-support.js +429 -389
- package/package.json +1 -1
- package/templates/next/src/app/api/vicket/[...path]/route.ts +2 -55
- package/templates/next/src/app/components/vicket/ReplyForm.tsx +154 -0
- package/templates/next/src/app/components/vicket/SupportContent.tsx +298 -0
- package/templates/next/src/app/components/vicket/TicketDialog.tsx +3 -3
- package/templates/next/src/app/support/page.tsx +27 -353
- package/templates/next/src/app/ticket/page.tsx +110 -325
- package/templates/next/src/app/vicket.css +1325 -1325
- package/templates/nuxt/app/assets/css/vicket.css +1325 -1325
- package/templates/nuxt/app/components/VicketReplyForm.vue +154 -0
- package/templates/nuxt/app/components/VicketSupportContent.vue +255 -0
- package/templates/nuxt/app/components/VicketTicketDialog.vue +2 -2
- package/templates/nuxt/app/pages/support.vue +7 -293
- package/templates/nuxt/app/pages/ticket.vue +36 -178
- package/templates/nuxt/server/api/vicket/[...path].ts +2 -85
- package/templates/sveltekit/src/lib/vicket/ReplyForm.svelte +134 -0
- package/templates/sveltekit/src/lib/vicket/SupportContent.svelte +263 -0
- package/templates/sveltekit/src/lib/vicket/TicketDialog.svelte +457 -459
- package/templates/sveltekit/src/lib/vicket.css +1325 -1325
- package/templates/sveltekit/src/routes/api/vicket/[...path]/+server.ts +2 -76
- package/templates/sveltekit/src/routes/support/+page.server.ts +13 -0
- package/templates/sveltekit/src/routes/support/+page.svelte +3 -312
- package/templates/sveltekit/src/routes/ticket/+page.server.ts +19 -0
- package/templates/sveltekit/src/routes/ticket/+page.svelte +13 -188
- package/templates-tailwind/next/src/app/api/vicket/[...path]/route.ts +6 -0
- package/templates-tailwind/next/src/app/support/page.tsx +33 -3
- package/templates-tailwind/next/src/app/ticket/page.tsx +249 -6
- package/templates-tailwind/next/src/components/vicket/reply-form.tsx +113 -0
- package/templates-tailwind/next/src/components/vicket/support-content.tsx +265 -0
- package/templates-tailwind/next/src/components/vicket/ticket-dialog.tsx +2 -2
- package/templates-tailwind/nuxt/app/components/VicketReplyForm.vue +169 -0
- package/templates-tailwind/nuxt/app/components/{VicketSupportPage.vue → VicketSupportContent.vue} +275 -317
- package/templates-tailwind/nuxt/app/components/VicketTicketDialog.vue +3 -0
- package/templates-tailwind/nuxt/app/pages/support.vue +10 -1
- package/templates-tailwind/nuxt/app/pages/ticket.vue +298 -1
- package/templates-tailwind/nuxt/server/api/vicket/[...path].ts +2 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/ReplyForm.svelte +127 -0
- package/templates-tailwind/sveltekit/src/lib/vicket/{SupportPage.svelte → SupportContent.svelte} +9 -71
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketDialog.svelte +405 -406
- package/templates-tailwind/sveltekit/src/routes/api/vicket/[...path]/+server.ts +3 -0
- package/templates-tailwind/sveltekit/src/routes/support/+page.server.ts +13 -0
- package/templates-tailwind/sveltekit/src/routes/support/+page.svelte +4 -2
- package/templates-tailwind/sveltekit/src/routes/ticket/+page.server.ts +19 -0
- package/templates-tailwind/sveltekit/src/routes/ticket/+page.svelte +292 -2
- package/templates/next/src/app/utils/vicket/api.ts +0 -149
- package/templates/next/src/app/utils/vicket/types.ts +0 -85
- package/templates/next/src/app/utils/vicket/utils.ts +0 -49
- package/templates/nuxt/app/composables/useVicket.ts +0 -274
- package/templates/sveltekit/src/lib/vicket/api.ts +0 -162
- package/templates/sveltekit/src/lib/vicket/types.ts +0 -87
- package/templates/sveltekit/src/lib/vicket/utils.ts +0 -55
- package/templates-tailwind/next/src/app/api/vicket/init/route.ts +0 -24
- package/templates-tailwind/next/src/app/api/vicket/messages/route.ts +0 -36
- package/templates-tailwind/next/src/app/api/vicket/thread/route.ts +0 -27
- package/templates-tailwind/next/src/app/api/vicket/tickets/route.ts +0 -37
- package/templates-tailwind/next/src/components/vicket/support-page.tsx +0 -359
- package/templates-tailwind/next/src/components/vicket/ticket-page.tsx +0 -425
- package/templates-tailwind/next/src/lib/vicket.ts +0 -257
- package/templates-tailwind/nuxt/app/components/VicketTicketPage.vue +0 -449
- package/templates-tailwind/nuxt/app/composables/use-vicket.ts +0 -249
- package/templates-tailwind/nuxt/server/api/vicket/init.get.ts +0 -22
- package/templates-tailwind/nuxt/server/api/vicket/messages.post.ts +0 -56
- package/templates-tailwind/nuxt/server/api/vicket/thread.get.ts +0 -26
- package/templates-tailwind/nuxt/server/api/vicket/tickets.post.ts +0 -53
- package/templates-tailwind/sveltekit/src/lib/vicket/TicketPage.svelte +0 -465
- package/templates-tailwind/sveltekit/src/lib/vicket/index.ts +0 -257
- package/templates-tailwind/sveltekit/src/routes/api/vicket/init/+server.ts +0 -22
- package/templates-tailwind/sveltekit/src/routes/api/vicket/messages/+server.ts +0 -40
- package/templates-tailwind/sveltekit/src/routes/api/vicket/thread/+server.ts +0 -25
- package/templates-tailwind/sveltekit/src/routes/api/vicket/tickets/+server.ts +0 -37
|
@@ -1,389 +1,429 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require("node:fs");
|
|
4
|
-
const path = require("node:path");
|
|
5
|
-
const { stdin } = require("node:process");
|
|
6
|
-
|
|
7
|
-
const PKG_VERSION = require(
|
|
8
|
-
path.resolve(__dirname, "..", "package.json"),
|
|
9
|
-
).version;
|
|
10
|
-
|
|
11
|
-
const FRAMEWORK_ALIASES = {
|
|
12
|
-
next: "next",
|
|
13
|
-
nextjs: "next",
|
|
14
|
-
nuxt: "nuxt",
|
|
15
|
-
svelte: "sveltekit",
|
|
16
|
-
sveltekit: "sveltekit",
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
const FRAMEWORK_CHOICES = [
|
|
20
|
-
{ value: "next", label: "Next.js (App Router)" },
|
|
21
|
-
{ value: "nuxt", label: "Nuxt 4 (Vue)" },
|
|
22
|
-
{ value: "sveltekit", label: "SvelteKit" },
|
|
23
|
-
];
|
|
24
|
-
|
|
25
|
-
const DEFAULT_FRAMEWORK = "next";
|
|
26
|
-
const STYLING_ALIASES = {
|
|
27
|
-
css: "css",
|
|
28
|
-
tailwind: "tailwind",
|
|
29
|
-
tw: "tailwind",
|
|
30
|
-
};
|
|
31
|
-
const STYLING_CHOICES = [
|
|
32
|
-
{ value: "css", label: "CSS file (default)" },
|
|
33
|
-
{ value: "tailwind", label: "Tailwind CSS (inline utilities)" },
|
|
34
|
-
];
|
|
35
|
-
const DEFAULT_STYLING = "css";
|
|
36
|
-
let clack = null;
|
|
37
|
-
|
|
38
|
-
async function loadClack() {
|
|
39
|
-
if (clack) return clack;
|
|
40
|
-
const prompts = await import("@clack/prompts");
|
|
41
|
-
clack = prompts;
|
|
42
|
-
return prompts;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function printHelp() {
|
|
46
|
-
console.log(`
|
|
47
|
-
Usage:
|
|
48
|
-
create-vicket-support [options]
|
|
49
|
-
|
|
50
|
-
Options:
|
|
51
|
-
-f, --framework <name> Framework: next | nuxt | sveltekit
|
|
52
|
-
-s, --styling <name> Styling: css | tailwind (default: css)
|
|
53
|
-
--tailwind Shortcut for --styling tailwind
|
|
54
|
-
-d, --dir <path> Output directory (default: current directory)
|
|
55
|
-
-y, --yes Overwrite existing files without prompt
|
|
56
|
-
-v, --version Show version
|
|
57
|
-
-h, --help Show help
|
|
58
|
-
|
|
59
|
-
Examples:
|
|
60
|
-
npx @vicket/create-support --framework next
|
|
61
|
-
npx @vicket/create-support --framework next --styling tailwind
|
|
62
|
-
npx @vicket/create-support --framework nuxt --dir ./my-app
|
|
63
|
-
npx @vicket/create-support -f sveltekit -d . -y --tailwind
|
|
64
|
-
`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function parseArgs(argv) {
|
|
68
|
-
const options = {
|
|
69
|
-
framework: "",
|
|
70
|
-
styling: "",
|
|
71
|
-
dir: process.cwd(),
|
|
72
|
-
yes: false,
|
|
73
|
-
help: false,
|
|
74
|
-
version: false,
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
78
|
-
const arg = argv[i];
|
|
79
|
-
if (arg === "--version" || arg === "-v") {
|
|
80
|
-
options.version = true;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
if (arg === "--help" || arg === "-h") {
|
|
84
|
-
options.help = true;
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (arg === "--framework" || arg === "-f") {
|
|
88
|
-
options.framework = argv[i + 1] || "";
|
|
89
|
-
i += 1;
|
|
90
|
-
continue;
|
|
91
|
-
}
|
|
92
|
-
if (arg.startsWith("--framework=")) {
|
|
93
|
-
options.framework = arg.split("=")[1] || "";
|
|
94
|
-
continue;
|
|
95
|
-
}
|
|
96
|
-
if (arg === "--styling" || arg === "-s") {
|
|
97
|
-
options.styling = argv[i + 1] || options.styling;
|
|
98
|
-
i += 1;
|
|
99
|
-
continue;
|
|
100
|
-
}
|
|
101
|
-
if (arg.startsWith("--styling=")) {
|
|
102
|
-
options.styling = arg.split("=")[1] || options.styling;
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
if (arg === "--tailwind") {
|
|
106
|
-
options.styling = "tailwind";
|
|
107
|
-
continue;
|
|
108
|
-
}
|
|
109
|
-
if (arg === "--dir" || arg === "-d") {
|
|
110
|
-
options.dir = argv[i + 1] || options.dir;
|
|
111
|
-
i += 1;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
if (arg.startsWith("--dir=")) {
|
|
115
|
-
options.dir = arg.split("=")[1] || options.dir;
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
if (arg === "--yes" || arg === "-y") {
|
|
119
|
-
options.yes = true;
|
|
120
|
-
continue;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return options;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function normalizeFramework(input) {
|
|
128
|
-
return FRAMEWORK_ALIASES[(input || "").trim().toLowerCase()] || "";
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function normalizeStyling(input) {
|
|
132
|
-
return STYLING_ALIASES[(input || "").trim().toLowerCase()] || "";
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async function askFrameworkSelection() {
|
|
136
|
-
if (!stdin.isTTY) {
|
|
137
|
-
return "";
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const p = await loadClack();
|
|
141
|
-
p.intro("Create Vicket Support");
|
|
142
|
-
const value = await p.select({
|
|
143
|
-
message: "Select a framework",
|
|
144
|
-
initialValue: DEFAULT_FRAMEWORK,
|
|
145
|
-
options: FRAMEWORK_CHOICES.map((choice) => ({
|
|
146
|
-
value: choice.value,
|
|
147
|
-
label: choice.label,
|
|
148
|
-
})),
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
if (p.isCancel(value)) {
|
|
152
|
-
p.cancel("Operation cancelled.");
|
|
153
|
-
return "";
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
return value;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async function askStylingSelection() {
|
|
160
|
-
if (!stdin.isTTY) {
|
|
161
|
-
return DEFAULT_STYLING;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
const p = await loadClack();
|
|
165
|
-
const value = await p.select({
|
|
166
|
-
message: "Select a styling mode",
|
|
167
|
-
initialValue: DEFAULT_STYLING,
|
|
168
|
-
options: STYLING_CHOICES.map((choice) => ({
|
|
169
|
-
value: choice.value,
|
|
170
|
-
label: choice.label,
|
|
171
|
-
})),
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
if (p.isCancel(value)) {
|
|
175
|
-
p.cancel("Operation cancelled.");
|
|
176
|
-
return "";
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
return value;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
function collectFiles(baseDir, currentDir = baseDir, acc = []) {
|
|
183
|
-
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
184
|
-
for (const entry of entries) {
|
|
185
|
-
const absolute = path.join(currentDir, entry.name);
|
|
186
|
-
if (entry.isDirectory()) {
|
|
187
|
-
collectFiles(baseDir, absolute, acc);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const relative = path.relative(baseDir, absolute);
|
|
192
|
-
acc.push(relative);
|
|
193
|
-
}
|
|
194
|
-
return acc;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function ensureDirectory(filePath) {
|
|
198
|
-
const dir = path.dirname(filePath);
|
|
199
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Detect whether a Next.js project uses the src/ directory layout.
|
|
204
|
-
* Returns true if src/app exists, false if app/ exists at root,
|
|
205
|
-
* or falls back to checking for a src/ directory.
|
|
206
|
-
*/
|
|
207
|
-
function detectNextSrcLayout(targetRoot) {
|
|
208
|
-
if (fs.existsSync(path.join(targetRoot, "src", "app"))) {
|
|
209
|
-
return true;
|
|
210
|
-
}
|
|
211
|
-
if (fs.existsSync(path.join(targetRoot, "app"))) {
|
|
212
|
-
return false;
|
|
213
|
-
}
|
|
214
|
-
if (fs.existsSync(path.join(targetRoot, "src"))) {
|
|
215
|
-
return true;
|
|
216
|
-
}
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
async function confirmOverwrite(existingFiles) {
|
|
221
|
-
if (!stdin.isTTY) {
|
|
222
|
-
return false;
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const p = await loadClack();
|
|
226
|
-
p.log.warn("The following files already exist:");
|
|
227
|
-
for (const file of existingFiles) {
|
|
228
|
-
p.log.message(`- ${file}`);
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
const value = await p.confirm({
|
|
232
|
-
message: "Overwrite these files?",
|
|
233
|
-
initialValue: false,
|
|
234
|
-
});
|
|
235
|
-
|
|
236
|
-
if (p.isCancel(value)) {
|
|
237
|
-
p.cancel("Operation cancelled.");
|
|
238
|
-
return false;
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return Boolean(value);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
p
|
|
264
|
-
p.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { stdin } = require("node:process");
|
|
6
|
+
|
|
7
|
+
const PKG_VERSION = require(
|
|
8
|
+
path.resolve(__dirname, "..", "package.json"),
|
|
9
|
+
).version;
|
|
10
|
+
|
|
11
|
+
const FRAMEWORK_ALIASES = {
|
|
12
|
+
next: "next",
|
|
13
|
+
nextjs: "next",
|
|
14
|
+
nuxt: "nuxt",
|
|
15
|
+
svelte: "sveltekit",
|
|
16
|
+
sveltekit: "sveltekit",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const FRAMEWORK_CHOICES = [
|
|
20
|
+
{ value: "next", label: "Next.js (App Router)" },
|
|
21
|
+
{ value: "nuxt", label: "Nuxt 4 (Vue)" },
|
|
22
|
+
{ value: "sveltekit", label: "SvelteKit" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const DEFAULT_FRAMEWORK = "next";
|
|
26
|
+
const STYLING_ALIASES = {
|
|
27
|
+
css: "css",
|
|
28
|
+
tailwind: "tailwind",
|
|
29
|
+
tw: "tailwind",
|
|
30
|
+
};
|
|
31
|
+
const STYLING_CHOICES = [
|
|
32
|
+
{ value: "css", label: "CSS file (default)" },
|
|
33
|
+
{ value: "tailwind", label: "Tailwind CSS (inline utilities)" },
|
|
34
|
+
];
|
|
35
|
+
const DEFAULT_STYLING = "css";
|
|
36
|
+
let clack = null;
|
|
37
|
+
|
|
38
|
+
async function loadClack() {
|
|
39
|
+
if (clack) return clack;
|
|
40
|
+
const prompts = await import("@clack/prompts");
|
|
41
|
+
clack = prompts;
|
|
42
|
+
return prompts;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function printHelp() {
|
|
46
|
+
console.log(`
|
|
47
|
+
Usage:
|
|
48
|
+
create-vicket-support [options]
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
-f, --framework <name> Framework: next | nuxt | sveltekit
|
|
52
|
+
-s, --styling <name> Styling: css | tailwind (default: css)
|
|
53
|
+
--tailwind Shortcut for --styling tailwind
|
|
54
|
+
-d, --dir <path> Output directory (default: current directory)
|
|
55
|
+
-y, --yes Overwrite existing files without prompt
|
|
56
|
+
-v, --version Show version
|
|
57
|
+
-h, --help Show help
|
|
58
|
+
|
|
59
|
+
Examples:
|
|
60
|
+
npx @vicket/create-support --framework next
|
|
61
|
+
npx @vicket/create-support --framework next --styling tailwind
|
|
62
|
+
npx @vicket/create-support --framework nuxt --dir ./my-app
|
|
63
|
+
npx @vicket/create-support -f sveltekit -d . -y --tailwind
|
|
64
|
+
`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function parseArgs(argv) {
|
|
68
|
+
const options = {
|
|
69
|
+
framework: "",
|
|
70
|
+
styling: "",
|
|
71
|
+
dir: process.cwd(),
|
|
72
|
+
yes: false,
|
|
73
|
+
help: false,
|
|
74
|
+
version: false,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
78
|
+
const arg = argv[i];
|
|
79
|
+
if (arg === "--version" || arg === "-v") {
|
|
80
|
+
options.version = true;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (arg === "--help" || arg === "-h") {
|
|
84
|
+
options.help = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (arg === "--framework" || arg === "-f") {
|
|
88
|
+
options.framework = argv[i + 1] || "";
|
|
89
|
+
i += 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (arg.startsWith("--framework=")) {
|
|
93
|
+
options.framework = arg.split("=")[1] || "";
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (arg === "--styling" || arg === "-s") {
|
|
97
|
+
options.styling = argv[i + 1] || options.styling;
|
|
98
|
+
i += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
if (arg.startsWith("--styling=")) {
|
|
102
|
+
options.styling = arg.split("=")[1] || options.styling;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (arg === "--tailwind") {
|
|
106
|
+
options.styling = "tailwind";
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (arg === "--dir" || arg === "-d") {
|
|
110
|
+
options.dir = argv[i + 1] || options.dir;
|
|
111
|
+
i += 1;
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
if (arg.startsWith("--dir=")) {
|
|
115
|
+
options.dir = arg.split("=")[1] || options.dir;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (arg === "--yes" || arg === "-y") {
|
|
119
|
+
options.yes = true;
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return options;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function normalizeFramework(input) {
|
|
128
|
+
return FRAMEWORK_ALIASES[(input || "").trim().toLowerCase()] || "";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function normalizeStyling(input) {
|
|
132
|
+
return STYLING_ALIASES[(input || "").trim().toLowerCase()] || "";
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async function askFrameworkSelection() {
|
|
136
|
+
if (!stdin.isTTY) {
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const p = await loadClack();
|
|
141
|
+
p.intro("Create Vicket Support");
|
|
142
|
+
const value = await p.select({
|
|
143
|
+
message: "Select a framework",
|
|
144
|
+
initialValue: DEFAULT_FRAMEWORK,
|
|
145
|
+
options: FRAMEWORK_CHOICES.map((choice) => ({
|
|
146
|
+
value: choice.value,
|
|
147
|
+
label: choice.label,
|
|
148
|
+
})),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
if (p.isCancel(value)) {
|
|
152
|
+
p.cancel("Operation cancelled.");
|
|
153
|
+
return "";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return value;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function askStylingSelection() {
|
|
160
|
+
if (!stdin.isTTY) {
|
|
161
|
+
return DEFAULT_STYLING;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const p = await loadClack();
|
|
165
|
+
const value = await p.select({
|
|
166
|
+
message: "Select a styling mode",
|
|
167
|
+
initialValue: DEFAULT_STYLING,
|
|
168
|
+
options: STYLING_CHOICES.map((choice) => ({
|
|
169
|
+
value: choice.value,
|
|
170
|
+
label: choice.label,
|
|
171
|
+
})),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (p.isCancel(value)) {
|
|
175
|
+
p.cancel("Operation cancelled.");
|
|
176
|
+
return "";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return value;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function collectFiles(baseDir, currentDir = baseDir, acc = []) {
|
|
183
|
+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
|
|
184
|
+
for (const entry of entries) {
|
|
185
|
+
const absolute = path.join(currentDir, entry.name);
|
|
186
|
+
if (entry.isDirectory()) {
|
|
187
|
+
collectFiles(baseDir, absolute, acc);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const relative = path.relative(baseDir, absolute);
|
|
192
|
+
acc.push(relative);
|
|
193
|
+
}
|
|
194
|
+
return acc;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function ensureDirectory(filePath) {
|
|
198
|
+
const dir = path.dirname(filePath);
|
|
199
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Detect whether a Next.js project uses the src/ directory layout.
|
|
204
|
+
* Returns true if src/app exists, false if app/ exists at root,
|
|
205
|
+
* or falls back to checking for a src/ directory.
|
|
206
|
+
*/
|
|
207
|
+
function detectNextSrcLayout(targetRoot) {
|
|
208
|
+
if (fs.existsSync(path.join(targetRoot, "src", "app"))) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
if (fs.existsSync(path.join(targetRoot, "app"))) {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
if (fs.existsSync(path.join(targetRoot, "src"))) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
async function confirmOverwrite(existingFiles) {
|
|
221
|
+
if (!stdin.isTTY) {
|
|
222
|
+
return false;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const p = await loadClack();
|
|
226
|
+
p.log.warn("The following files already exist:");
|
|
227
|
+
for (const file of existingFiles) {
|
|
228
|
+
p.log.message(`- ${file}`);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const value = await p.confirm({
|
|
232
|
+
message: "Overwrite these files?",
|
|
233
|
+
initialValue: false,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
if (p.isCancel(value)) {
|
|
237
|
+
p.cancel("Operation cancelled.");
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return Boolean(value);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function detectPackageManager(targetRoot) {
|
|
245
|
+
if (fs.existsSync(path.join(targetRoot, "bun.lockb")) || fs.existsSync(path.join(targetRoot, "bun.lock"))) return "bun";
|
|
246
|
+
if (fs.existsSync(path.join(targetRoot, "pnpm-lock.yaml"))) return "pnpm";
|
|
247
|
+
if (fs.existsSync(path.join(targetRoot, "yarn.lock"))) return "yarn";
|
|
248
|
+
return "npm";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
async function installVicketPackage(targetRoot) {
|
|
252
|
+
const { execSync } = require("node:child_process");
|
|
253
|
+
const pm = detectPackageManager(targetRoot);
|
|
254
|
+
|
|
255
|
+
const installCmd = {
|
|
256
|
+
npm: "npm install vicket",
|
|
257
|
+
pnpm: "pnpm add vicket",
|
|
258
|
+
yarn: "yarn add vicket",
|
|
259
|
+
bun: "bun add vicket",
|
|
260
|
+
}[pm];
|
|
261
|
+
|
|
262
|
+
if (stdin.isTTY) {
|
|
263
|
+
const p = await loadClack();
|
|
264
|
+
const s = p.spinner();
|
|
265
|
+
s.start(`Installing vicket package with ${pm}...`);
|
|
266
|
+
try {
|
|
267
|
+
execSync(installCmd, { cwd: targetRoot, stdio: "pipe" });
|
|
268
|
+
s.stop(`Installed vicket with ${pm}.`);
|
|
269
|
+
} catch {
|
|
270
|
+
s.stop(`Could not auto-install. Run "${installCmd}" manually.`);
|
|
271
|
+
}
|
|
272
|
+
} else {
|
|
273
|
+
console.log(`Installing vicket with ${pm}...`);
|
|
274
|
+
try {
|
|
275
|
+
execSync(installCmd, { cwd: targetRoot, stdio: "pipe" });
|
|
276
|
+
console.log("Installed vicket.");
|
|
277
|
+
} catch {
|
|
278
|
+
console.log(`Could not auto-install. Run "${installCmd}" manually.`);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
async function printPostInstall(framework, styling) {
|
|
284
|
+
const envLinesByFramework = {
|
|
285
|
+
next: [
|
|
286
|
+
"- VICKET_API_URL (https://api.vicket.app/api/v1) — server-side only",
|
|
287
|
+
"- VICKET_API_KEY (website API key) — server-side only, NEVER expose to client",
|
|
288
|
+
],
|
|
289
|
+
nuxt: [
|
|
290
|
+
"- VICKET_API_URL (https://api.vicket.app/api/v1) — server-side only",
|
|
291
|
+
"- VICKET_API_KEY (website API key) — server-side only, NEVER expose to client",
|
|
292
|
+
],
|
|
293
|
+
sveltekit: [
|
|
294
|
+
"- VICKET_API_URL (https://api.vicket.app/api/v1) — server-side only",
|
|
295
|
+
"- VICKET_API_KEY (website API key) — server-side only, NEVER expose to client",
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
const envLines = envLinesByFramework[framework] || envLinesByFramework.next;
|
|
299
|
+
|
|
300
|
+
if (stdin.isTTY) {
|
|
301
|
+
const p = await loadClack();
|
|
302
|
+
p.outro("Scaffold complete.");
|
|
303
|
+
p.log.info("Set these environment variables in the target app:");
|
|
304
|
+
for (const line of envLines) {
|
|
305
|
+
p.log.message(line);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (framework === "nuxt") {
|
|
309
|
+
p.log.info(
|
|
310
|
+
"Nuxt note: if you prefer global styles, add ~/assets/css/vicket.css to nuxt.config.ts > css. Files are in the app/ directory (Nuxt 4 convention).",
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
if (styling === "tailwind") {
|
|
314
|
+
p.log.info(
|
|
315
|
+
"Tailwind mode: ensure Tailwind CSS is configured in the target app.",
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
console.log("\nScaffold complete.");
|
|
322
|
+
console.log("Set these environment variables in the target app:");
|
|
323
|
+
for (const line of envLines) {
|
|
324
|
+
console.log(line);
|
|
325
|
+
}
|
|
326
|
+
if (styling === "tailwind") {
|
|
327
|
+
console.log(
|
|
328
|
+
"Tailwind mode: ensure Tailwind CSS is configured in the target app.",
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function main() {
|
|
334
|
+
const options = parseArgs(process.argv.slice(2));
|
|
335
|
+
if (options.version) {
|
|
336
|
+
console.log(`@vicket/create-support v${PKG_VERSION}`);
|
|
337
|
+
process.exit(0);
|
|
338
|
+
}
|
|
339
|
+
if (options.help) {
|
|
340
|
+
printHelp();
|
|
341
|
+
process.exit(0);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
let framework = normalizeFramework(options.framework);
|
|
345
|
+
const requestedStyling = (options.styling || "").trim();
|
|
346
|
+
if (requestedStyling && !normalizeStyling(requestedStyling)) {
|
|
347
|
+
console.error("Unsupported styling. Use --styling css|tailwind");
|
|
348
|
+
printHelp();
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
let styling = normalizeStyling(options.styling) || DEFAULT_STYLING;
|
|
353
|
+
|
|
354
|
+
if (!framework) {
|
|
355
|
+
framework = await askFrameworkSelection();
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
if (!framework) {
|
|
359
|
+
console.error(
|
|
360
|
+
"Missing or unsupported framework. Use --framework next|nuxt|sveltekit",
|
|
361
|
+
);
|
|
362
|
+
printHelp();
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
if (
|
|
367
|
+
!normalizeStyling(options.styling) &&
|
|
368
|
+
stdin.isTTY &&
|
|
369
|
+
!process.argv.includes("--tailwind")
|
|
370
|
+
) {
|
|
371
|
+
const selectedStyling = await askStylingSelection();
|
|
372
|
+
if (!selectedStyling) {
|
|
373
|
+
console.log("Aborted. No files were written.");
|
|
374
|
+
process.exit(0);
|
|
375
|
+
}
|
|
376
|
+
styling = selectedStyling;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
380
|
+
const templateDir =
|
|
381
|
+
styling === "tailwind" ? "templates-tailwind" : "templates";
|
|
382
|
+
const templateRoot = path.join(packageRoot, templateDir, framework);
|
|
383
|
+
|
|
384
|
+
if (!fs.existsSync(templateRoot)) {
|
|
385
|
+
console.error(`Template not found: ${templateDir}/${framework}`);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const targetRoot = path.resolve(options.dir);
|
|
390
|
+
const files = collectFiles(templateRoot);
|
|
391
|
+
|
|
392
|
+
const stripSrc =
|
|
393
|
+
framework === "next" && !detectNextSrcLayout(targetRoot);
|
|
394
|
+
const srcPrefix = "src" + path.sep;
|
|
395
|
+
|
|
396
|
+
function toDestRelative(relativePath) {
|
|
397
|
+
if (stripSrc && relativePath.startsWith(srcPrefix)) {
|
|
398
|
+
return relativePath.slice(srcPrefix.length);
|
|
399
|
+
}
|
|
400
|
+
return relativePath;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
const existing = files
|
|
404
|
+
.map((f) => toDestRelative(f))
|
|
405
|
+
.filter((destPath) => fs.existsSync(path.join(targetRoot, destPath)));
|
|
406
|
+
|
|
407
|
+
if (existing.length > 0 && !options.yes) {
|
|
408
|
+
const shouldOverwrite = await confirmOverwrite(existing);
|
|
409
|
+
if (!shouldOverwrite) {
|
|
410
|
+
console.log("Aborted. No files were written.");
|
|
411
|
+
process.exit(0);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
for (const relativePath of files) {
|
|
416
|
+
const from = path.join(templateRoot, relativePath);
|
|
417
|
+
const to = path.join(targetRoot, toDestRelative(relativePath));
|
|
418
|
+
ensureDirectory(to);
|
|
419
|
+
fs.copyFileSync(from, to);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
await installVicketPackage(targetRoot);
|
|
423
|
+
await printPostInstall(framework, styling);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
main().catch((error) => {
|
|
427
|
+
console.error(error);
|
|
428
|
+
process.exit(1);
|
|
429
|
+
});
|