create-next-style-guide 0.1.3 → 0.1.4
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/dist/index.js +379 -74
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/template/.env.example +12 -2
- package/template/.env.production.example +11 -0
- package/template/.env.staging.example +12 -0
- package/template/README.md +3 -0
- package/template/docs/style-guide/ops/env.md +23 -0
- package/template/docs/style-guide/overview/architecture.md +1 -1
- package/template/gitignore +2 -0
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import * as p4 from "@clack/prompts";
|
|
5
5
|
import color4 from "picocolors";
|
|
6
|
-
import
|
|
6
|
+
import path31 from "path";
|
|
7
7
|
|
|
8
8
|
// src/constants.ts
|
|
9
9
|
import path from "path";
|
|
@@ -78,6 +78,7 @@ var PRESET_SEEDS = {
|
|
|
78
78
|
auth: "none",
|
|
79
79
|
styling: "none",
|
|
80
80
|
ui: "none",
|
|
81
|
+
shadcnSet: "minimal",
|
|
81
82
|
data: "rsc",
|
|
82
83
|
store: "none",
|
|
83
84
|
icons: "none",
|
|
@@ -90,7 +91,7 @@ var PRESET_SEEDS = {
|
|
|
90
91
|
eslint: false,
|
|
91
92
|
prettier: false,
|
|
92
93
|
husky: false,
|
|
93
|
-
|
|
94
|
+
deploy: "none",
|
|
94
95
|
ci: false,
|
|
95
96
|
testing: false,
|
|
96
97
|
playwright: false
|
|
@@ -100,6 +101,7 @@ var PRESET_SEEDS = {
|
|
|
100
101
|
auth: "jwt",
|
|
101
102
|
styling: "tailwind",
|
|
102
103
|
ui: "shadcn",
|
|
104
|
+
shadcnSet: "starter",
|
|
103
105
|
data: "tanstack-query",
|
|
104
106
|
store: "zustand",
|
|
105
107
|
icons: "lucide",
|
|
@@ -112,7 +114,7 @@ var PRESET_SEEDS = {
|
|
|
112
114
|
eslint: true,
|
|
113
115
|
prettier: true,
|
|
114
116
|
husky: true,
|
|
115
|
-
|
|
117
|
+
deploy: "none",
|
|
116
118
|
ci: true,
|
|
117
119
|
testing: true,
|
|
118
120
|
playwright: false
|
|
@@ -122,6 +124,7 @@ var PRESET_SEEDS = {
|
|
|
122
124
|
auth: "none",
|
|
123
125
|
styling: "tailwind",
|
|
124
126
|
ui: "shadcn",
|
|
127
|
+
shadcnSet: "minimal",
|
|
125
128
|
data: "rsc",
|
|
126
129
|
store: "none",
|
|
127
130
|
icons: "lucide",
|
|
@@ -134,7 +137,7 @@ var PRESET_SEEDS = {
|
|
|
134
137
|
eslint: true,
|
|
135
138
|
prettier: true,
|
|
136
139
|
husky: true,
|
|
137
|
-
|
|
140
|
+
deploy: "vercel",
|
|
138
141
|
ci: true,
|
|
139
142
|
testing: true,
|
|
140
143
|
playwright: false
|
|
@@ -144,6 +147,7 @@ var PRESET_SEEDS = {
|
|
|
144
147
|
auth: "none",
|
|
145
148
|
styling: "tailwind",
|
|
146
149
|
ui: "shadcn",
|
|
150
|
+
shadcnSet: "starter",
|
|
147
151
|
data: "tanstack-query",
|
|
148
152
|
store: "zustand",
|
|
149
153
|
icons: "lucide",
|
|
@@ -156,7 +160,7 @@ var PRESET_SEEDS = {
|
|
|
156
160
|
eslint: true,
|
|
157
161
|
prettier: true,
|
|
158
162
|
husky: true,
|
|
159
|
-
|
|
163
|
+
deploy: "none",
|
|
160
164
|
ci: true,
|
|
161
165
|
testing: true,
|
|
162
166
|
playwright: false
|
|
@@ -166,19 +170,20 @@ function describePreset(id) {
|
|
|
166
170
|
const seed = PRESET_SEEDS[id];
|
|
167
171
|
return [
|
|
168
172
|
`styling=${seed.styling}`,
|
|
169
|
-
seed.ui === "shadcn" ?
|
|
173
|
+
seed.ui === "shadcn" ? `shadcn:${seed.shadcnSet}` : null,
|
|
170
174
|
`auth=${seed.auth}`,
|
|
171
175
|
seed.store !== "none" ? `store=${seed.store}` : null,
|
|
172
176
|
`validation=${seed.validation}`,
|
|
173
177
|
seed.endpoints ? "endpoints" : null,
|
|
174
178
|
seed.data === "tanstack-query" ? "query" : null,
|
|
175
179
|
seed.darkMode ? "dark" : null,
|
|
180
|
+
seed.deploy !== "none" ? `deploy=${seed.deploy}` : null,
|
|
176
181
|
seed.seo ? "seo" : null,
|
|
177
182
|
seed.i18n ? "i18n" : null,
|
|
178
183
|
seed.testing ? "vitest" : null
|
|
179
184
|
].filter(Boolean).join(" \xB7 ");
|
|
180
185
|
}
|
|
181
|
-
function collectOptionWarnings(options) {
|
|
186
|
+
function collectOptionWarnings(options, { verbose = false } = {}) {
|
|
182
187
|
const warnings = [];
|
|
183
188
|
if (options.auth === "jwt" && !options.endpoints) {
|
|
184
189
|
warnings.push(
|
|
@@ -199,9 +204,9 @@ function collectOptionWarnings(options) {
|
|
|
199
204
|
if (options.playwright && !options.testing) {
|
|
200
205
|
warnings.push("Playwright was requested without Vitest \u2014 enabling testing.");
|
|
201
206
|
}
|
|
202
|
-
if (options.store !== "none" && options.data === "tanstack-query") {
|
|
207
|
+
if (verbose && options.store !== "none" && options.data === "tanstack-query") {
|
|
203
208
|
warnings.push(
|
|
204
|
-
"
|
|
209
|
+
"Tip: Query = server cache; store = UI/session only. See docs/style-guide/overview/architecture.md"
|
|
205
210
|
);
|
|
206
211
|
}
|
|
207
212
|
return warnings;
|
|
@@ -217,6 +222,7 @@ var DEFAULT_OPTIONS = {
|
|
|
217
222
|
auth: "none",
|
|
218
223
|
styling: "none",
|
|
219
224
|
ui: "none",
|
|
225
|
+
shadcnSet: "minimal",
|
|
220
226
|
data: "rsc",
|
|
221
227
|
store: "none",
|
|
222
228
|
icons: "none",
|
|
@@ -230,7 +236,7 @@ var DEFAULT_OPTIONS = {
|
|
|
230
236
|
eslint: true,
|
|
231
237
|
prettier: true,
|
|
232
238
|
husky: true,
|
|
233
|
-
|
|
239
|
+
deploy: "none",
|
|
234
240
|
ci: true,
|
|
235
241
|
testing: true,
|
|
236
242
|
playwright: false,
|
|
@@ -245,6 +251,9 @@ function normalizeOptions(options) {
|
|
|
245
251
|
if (next.styling !== "tailwind" && next.ui === "shadcn") {
|
|
246
252
|
next = { ...next, ui: "none" };
|
|
247
253
|
}
|
|
254
|
+
if (next.ui !== "shadcn") {
|
|
255
|
+
next = { ...next, shadcnSet: "minimal" };
|
|
256
|
+
}
|
|
248
257
|
if (next.styling !== "tailwind" && next.darkMode) {
|
|
249
258
|
next = { ...next, darkMode: false };
|
|
250
259
|
}
|
|
@@ -283,6 +292,7 @@ async function promptCustomOptions(base) {
|
|
|
283
292
|
})
|
|
284
293
|
);
|
|
285
294
|
let ui = "none";
|
|
295
|
+
let shadcnSet = "minimal";
|
|
286
296
|
let darkMode = false;
|
|
287
297
|
if (styling === "tailwind") {
|
|
288
298
|
const useShadcn = assertNotCancel(
|
|
@@ -292,6 +302,26 @@ async function promptCustomOptions(base) {
|
|
|
292
302
|
})
|
|
293
303
|
);
|
|
294
304
|
ui = useShadcn ? "shadcn" : "none";
|
|
305
|
+
if (useShadcn) {
|
|
306
|
+
shadcnSet = assertNotCancel(
|
|
307
|
+
await p.select({
|
|
308
|
+
message: "shadcn component set?",
|
|
309
|
+
options: [
|
|
310
|
+
{
|
|
311
|
+
value: "minimal",
|
|
312
|
+
label: "Minimal",
|
|
313
|
+
hint: "Button only"
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
value: "starter",
|
|
317
|
+
label: "Starter",
|
|
318
|
+
hint: "Button \xB7 Input \xB7 Card \xB7 Dialog"
|
|
319
|
+
}
|
|
320
|
+
],
|
|
321
|
+
initialValue: base.shadcnSet
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
}
|
|
295
325
|
darkMode = assertNotCancel(
|
|
296
326
|
await p.confirm({
|
|
297
327
|
message: "Add dark mode (next-themes)?",
|
|
@@ -439,10 +469,27 @@ async function promptCustomOptions(base) {
|
|
|
439
469
|
initialValue: base.husky
|
|
440
470
|
})
|
|
441
471
|
);
|
|
442
|
-
const
|
|
443
|
-
await p.
|
|
444
|
-
message: "
|
|
445
|
-
|
|
472
|
+
const deploy = assertNotCancel(
|
|
473
|
+
await p.select({
|
|
474
|
+
message: "Deployment target?",
|
|
475
|
+
options: [
|
|
476
|
+
{
|
|
477
|
+
value: "none",
|
|
478
|
+
label: "None",
|
|
479
|
+
hint: "no deploy files"
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
value: "vercel",
|
|
483
|
+
label: "Vercel",
|
|
484
|
+
hint: "vercel.json + docs"
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
value: "docker",
|
|
488
|
+
label: "Docker",
|
|
489
|
+
hint: "standalone production image"
|
|
490
|
+
}
|
|
491
|
+
],
|
|
492
|
+
initialValue: base.deploy
|
|
446
493
|
})
|
|
447
494
|
);
|
|
448
495
|
const ci = assertNotCancel(
|
|
@@ -455,6 +502,7 @@ async function promptCustomOptions(base) {
|
|
|
455
502
|
...base,
|
|
456
503
|
styling,
|
|
457
504
|
ui,
|
|
505
|
+
shadcnSet,
|
|
458
506
|
darkMode,
|
|
459
507
|
icons,
|
|
460
508
|
validation,
|
|
@@ -470,7 +518,7 @@ async function promptCustomOptions(base) {
|
|
|
470
518
|
eslint,
|
|
471
519
|
prettier,
|
|
472
520
|
husky,
|
|
473
|
-
|
|
521
|
+
deploy,
|
|
474
522
|
ci
|
|
475
523
|
};
|
|
476
524
|
}
|
|
@@ -576,8 +624,8 @@ async function runPrompts(initialName) {
|
|
|
576
624
|
}
|
|
577
625
|
|
|
578
626
|
// src/scaffold.ts
|
|
579
|
-
import
|
|
580
|
-
import
|
|
627
|
+
import fs28 from "fs-extra";
|
|
628
|
+
import path29 from "path";
|
|
581
629
|
import * as p2 from "@clack/prompts";
|
|
582
630
|
import { execSync } from "child_process";
|
|
583
631
|
import color2 from "picocolors";
|
|
@@ -1771,7 +1819,7 @@ CMD ["node", "server.js"]
|
|
|
1771
1819
|
}
|
|
1772
1820
|
var dockerInstaller = {
|
|
1773
1821
|
id: "docker",
|
|
1774
|
-
active: (o) => o.docker,
|
|
1822
|
+
active: (o) => o.deploy === "docker",
|
|
1775
1823
|
async run({ projectDir, options }) {
|
|
1776
1824
|
const addon = path11.join(ADDONS_DIR, "docker");
|
|
1777
1825
|
const pm = getPackageManager(options.packageManager);
|
|
@@ -2424,7 +2472,154 @@ export function Button({
|
|
|
2424
2472
|
);
|
|
2425
2473
|
}
|
|
2426
2474
|
`;
|
|
2427
|
-
var
|
|
2475
|
+
var INPUT = `import type { ComponentProps } from "react";
|
|
2476
|
+
|
|
2477
|
+
import { cn } from "@/lib/utils";
|
|
2478
|
+
|
|
2479
|
+
export function Input({ className, type, ...props }: ComponentProps<"input">) {
|
|
2480
|
+
return (
|
|
2481
|
+
<input
|
|
2482
|
+
type={type}
|
|
2483
|
+
className={cn(
|
|
2484
|
+
"flex h-9 w-full rounded-md border border-neutral-300 bg-transparent px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-neutral-400 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-400 disabled:cursor-not-allowed disabled:opacity-50",
|
|
2485
|
+
className,
|
|
2486
|
+
)}
|
|
2487
|
+
{...props}
|
|
2488
|
+
/>
|
|
2489
|
+
);
|
|
2490
|
+
}
|
|
2491
|
+
`;
|
|
2492
|
+
var CARD = `import type { ComponentProps } from "react";
|
|
2493
|
+
|
|
2494
|
+
import { cn } from "@/lib/utils";
|
|
2495
|
+
|
|
2496
|
+
export function Card({ className, ...props }: ComponentProps<"div">) {
|
|
2497
|
+
return (
|
|
2498
|
+
<div
|
|
2499
|
+
className={cn(
|
|
2500
|
+
"rounded-xl border border-neutral-200 bg-white text-neutral-950 shadow-sm",
|
|
2501
|
+
className,
|
|
2502
|
+
)}
|
|
2503
|
+
{...props}
|
|
2504
|
+
/>
|
|
2505
|
+
);
|
|
2506
|
+
}
|
|
2507
|
+
|
|
2508
|
+
export function CardHeader({ className, ...props }: ComponentProps<"div">) {
|
|
2509
|
+
return (
|
|
2510
|
+
<div className={cn("flex flex-col gap-1.5 p-6", className)} {...props} />
|
|
2511
|
+
);
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
export function CardTitle({ className, ...props }: ComponentProps<"h3">) {
|
|
2515
|
+
return (
|
|
2516
|
+
<h3
|
|
2517
|
+
className={cn("font-semibold leading-none tracking-tight", className)}
|
|
2518
|
+
{...props}
|
|
2519
|
+
/>
|
|
2520
|
+
);
|
|
2521
|
+
}
|
|
2522
|
+
|
|
2523
|
+
export function CardDescription({ className, ...props }: ComponentProps<"p">) {
|
|
2524
|
+
return (
|
|
2525
|
+
<p className={cn("text-sm text-neutral-500", className)} {...props} />
|
|
2526
|
+
);
|
|
2527
|
+
}
|
|
2528
|
+
|
|
2529
|
+
export function CardContent({ className, ...props }: ComponentProps<"div">) {
|
|
2530
|
+
return <div className={cn("p-6 pt-0", className)} {...props} />;
|
|
2531
|
+
}
|
|
2532
|
+
|
|
2533
|
+
export function CardFooter({ className, ...props }: ComponentProps<"div">) {
|
|
2534
|
+
return (
|
|
2535
|
+
<div className={cn("flex items-center p-6 pt-0", className)} {...props} />
|
|
2536
|
+
);
|
|
2537
|
+
}
|
|
2538
|
+
`;
|
|
2539
|
+
var DIALOG = `"use client";
|
|
2540
|
+
|
|
2541
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
2542
|
+
import type { ComponentProps } from "react";
|
|
2543
|
+
|
|
2544
|
+
import { cn } from "@/lib/utils";
|
|
2545
|
+
|
|
2546
|
+
export const Dialog = DialogPrimitive.Root;
|
|
2547
|
+
export const DialogTrigger = DialogPrimitive.Trigger;
|
|
2548
|
+
export const DialogClose = DialogPrimitive.Close;
|
|
2549
|
+
export const DialogPortal = DialogPrimitive.Portal;
|
|
2550
|
+
|
|
2551
|
+
export function DialogOverlay({
|
|
2552
|
+
className,
|
|
2553
|
+
...props
|
|
2554
|
+
}: ComponentProps<typeof DialogPrimitive.Overlay>) {
|
|
2555
|
+
return (
|
|
2556
|
+
<DialogPrimitive.Overlay
|
|
2557
|
+
className={cn(
|
|
2558
|
+
"fixed inset-0 z-50 bg-black/50 data-[state=open]:animate-in data-[state=closed]:animate-out",
|
|
2559
|
+
className,
|
|
2560
|
+
)}
|
|
2561
|
+
{...props}
|
|
2562
|
+
/>
|
|
2563
|
+
);
|
|
2564
|
+
}
|
|
2565
|
+
|
|
2566
|
+
export function DialogContent({
|
|
2567
|
+
className,
|
|
2568
|
+
children,
|
|
2569
|
+
...props
|
|
2570
|
+
}: ComponentProps<typeof DialogPrimitive.Content>) {
|
|
2571
|
+
return (
|
|
2572
|
+
<DialogPortal>
|
|
2573
|
+
<DialogOverlay />
|
|
2574
|
+
<DialogPrimitive.Content
|
|
2575
|
+
className={cn(
|
|
2576
|
+
"fixed left-1/2 top-1/2 z-50 grid w-full max-w-lg -translate-x-1/2 -translate-y-1/2 gap-4 border border-neutral-200 bg-white p-6 shadow-lg duration-200 sm:rounded-xl",
|
|
2577
|
+
className,
|
|
2578
|
+
)}
|
|
2579
|
+
{...props}
|
|
2580
|
+
>
|
|
2581
|
+
{children}
|
|
2582
|
+
</DialogPrimitive.Content>
|
|
2583
|
+
</DialogPortal>
|
|
2584
|
+
);
|
|
2585
|
+
}
|
|
2586
|
+
|
|
2587
|
+
export function DialogHeader({ className, ...props }: ComponentProps<"div">) {
|
|
2588
|
+
return (
|
|
2589
|
+
<div
|
|
2590
|
+
className={cn("flex flex-col gap-1.5 text-center sm:text-left", className)}
|
|
2591
|
+
{...props}
|
|
2592
|
+
/>
|
|
2593
|
+
);
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2596
|
+
export function DialogTitle({
|
|
2597
|
+
className,
|
|
2598
|
+
...props
|
|
2599
|
+
}: ComponentProps<typeof DialogPrimitive.Title>) {
|
|
2600
|
+
return (
|
|
2601
|
+
<DialogPrimitive.Title
|
|
2602
|
+
className={cn("text-lg font-semibold leading-none", className)}
|
|
2603
|
+
{...props}
|
|
2604
|
+
/>
|
|
2605
|
+
);
|
|
2606
|
+
}
|
|
2607
|
+
|
|
2608
|
+
export function DialogDescription({
|
|
2609
|
+
className,
|
|
2610
|
+
...props
|
|
2611
|
+
}: ComponentProps<typeof DialogPrimitive.Description>) {
|
|
2612
|
+
return (
|
|
2613
|
+
<DialogPrimitive.Description
|
|
2614
|
+
className={cn("text-sm text-neutral-500", className)}
|
|
2615
|
+
{...props}
|
|
2616
|
+
/>
|
|
2617
|
+
);
|
|
2618
|
+
}
|
|
2619
|
+
`;
|
|
2620
|
+
function ruleFor(set) {
|
|
2621
|
+
const setLine = set === "starter" ? "- Starter set: `button`, `input`, `card`, `dialog`." : "- Minimal set: `button` only.";
|
|
2622
|
+
return `---
|
|
2428
2623
|
description: shadcn/ui conventions
|
|
2429
2624
|
globs: components.json,src/components/ui/**,src/lib/utils.ts
|
|
2430
2625
|
alwaysApply: false
|
|
@@ -2433,41 +2628,59 @@ alwaysApply: false
|
|
|
2433
2628
|
# shadcn
|
|
2434
2629
|
|
|
2435
2630
|
- Primitives live flat in \`src/components/ui/*\` (CLI-compatible).
|
|
2436
|
-
|
|
2631
|
+
${setLine}
|
|
2632
|
+
- Add more with \`npx shadcn@latest add \u2026\`.
|
|
2437
2633
|
- \`cn()\` from \`@/lib/utils\` for class merging.
|
|
2438
2634
|
- Config: \`components.json\`. Requires Tailwind.
|
|
2439
2635
|
`;
|
|
2636
|
+
}
|
|
2440
2637
|
var shadcnInstaller = {
|
|
2441
2638
|
id: "shadcn",
|
|
2442
2639
|
active: (o) => o.ui === "shadcn" && o.styling === "tailwind",
|
|
2443
2640
|
async run({ projectDir, options }) {
|
|
2444
2641
|
const iconLibrary = options.icons === "tabler" ? "tabler" : "lucide";
|
|
2642
|
+
const set = options.shadcnSet;
|
|
2643
|
+
const uiDir = path21.join(projectDir, "src", "components", "ui");
|
|
2445
2644
|
await fs20.writeFile(
|
|
2446
2645
|
path21.join(projectDir, "components.json"),
|
|
2447
2646
|
componentsJson(iconLibrary),
|
|
2448
2647
|
"utf8"
|
|
2449
2648
|
);
|
|
2450
|
-
await fs20.ensureDir(
|
|
2451
|
-
await fs20.writeFile(
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
"utf8"
|
|
2455
|
-
|
|
2456
|
-
|
|
2649
|
+
await fs20.ensureDir(uiDir);
|
|
2650
|
+
await fs20.writeFile(path21.join(uiDir, "button.tsx"), BUTTON, "utf8");
|
|
2651
|
+
if (set === "starter") {
|
|
2652
|
+
await fs20.writeFile(path21.join(uiDir, "input.tsx"), INPUT, "utf8");
|
|
2653
|
+
await fs20.writeFile(path21.join(uiDir, "card.tsx"), CARD, "utf8");
|
|
2654
|
+
await fs20.writeFile(path21.join(uiDir, "dialog.tsx"), DIALOG, "utf8");
|
|
2655
|
+
}
|
|
2656
|
+
await fs20.remove(path21.join(uiDir, ".gitkeep"));
|
|
2457
2657
|
await fs20.remove(path21.join(projectDir, "src", "components", ".gitkeep"));
|
|
2458
2658
|
await fs20.writeFile(
|
|
2459
2659
|
path21.join(projectDir, ".cursor", "rules", "shadcn.mdc"),
|
|
2460
|
-
|
|
2660
|
+
ruleFor(set),
|
|
2461
2661
|
"utf8"
|
|
2462
2662
|
);
|
|
2663
|
+
await fs20.outputFile(
|
|
2664
|
+
path21.join(projectDir, "docs", "style-guide", "ui", "shadcn.md"),
|
|
2665
|
+
`# shadcn/ui
|
|
2666
|
+
|
|
2667
|
+
Set: **${set}**
|
|
2668
|
+
${set === "starter" ? "- `button` \xB7 `input` \xB7 `card` \xB7 `dialog`\n" : "- `button`\n"}
|
|
2669
|
+
Add more: \`npx shadcn@latest add \u2026\`
|
|
2670
|
+
`
|
|
2671
|
+
);
|
|
2463
2672
|
if (options.icons === "none") {
|
|
2464
2673
|
await addDependencies(projectDir, {
|
|
2465
2674
|
"lucide-react": "^0.469.0"
|
|
2466
2675
|
});
|
|
2467
2676
|
}
|
|
2468
|
-
|
|
2677
|
+
const deps = {
|
|
2469
2678
|
"class-variance-authority": "^0.7.1"
|
|
2470
|
-
}
|
|
2679
|
+
};
|
|
2680
|
+
if (set === "starter") {
|
|
2681
|
+
deps["@radix-ui/react-dialog"] = "^1.1.4";
|
|
2682
|
+
}
|
|
2683
|
+
await addDependencies(projectDir, deps);
|
|
2471
2684
|
}
|
|
2472
2685
|
};
|
|
2473
2686
|
|
|
@@ -2651,9 +2864,10 @@ function stackLines(options) {
|
|
|
2651
2864
|
options.eslint ? "Enhanced ESLint" : "Minimal ESLint",
|
|
2652
2865
|
options.prettier ? "Prettier" : "No Prettier",
|
|
2653
2866
|
options.husky ? "Husky + lint-staged" : "No git hooks",
|
|
2654
|
-
options.
|
|
2867
|
+
options.ui === "shadcn" ? `shadcn set: ${options.shadcnSet}` : null,
|
|
2868
|
+
options.deploy === "docker" ? "Deploy: Docker standalone image" : options.deploy === "vercel" ? "Deploy: Vercel" : "No deploy target",
|
|
2655
2869
|
options.ci ? "GitHub Actions CI" : "No CI workflow"
|
|
2656
|
-
];
|
|
2870
|
+
].filter((line) => line !== null);
|
|
2657
2871
|
}
|
|
2658
2872
|
function welcomeCardSource(options) {
|
|
2659
2873
|
const items = stackLines(options).map((line) => ` <li>${escapeJsx(line)}</li>`).join("\n");
|
|
@@ -2712,6 +2926,7 @@ function docsIndex(options) {
|
|
|
2712
2926
|
"Layers: app / components / lib / utils"
|
|
2713
2927
|
],
|
|
2714
2928
|
["[Project structure](overview/project-structure.md)", "Folder map"],
|
|
2929
|
+
["[Environment](ops/env.md)", "`.env.example` \xB7 staging \xB7 production"],
|
|
2715
2930
|
["[HTTP client](http/client.md)", "`apiFetch` helper"],
|
|
2716
2931
|
[
|
|
2717
2932
|
`[Validation](validation/${options.validation}.md)`,
|
|
@@ -2755,7 +2970,10 @@ function docsIndex(options) {
|
|
|
2755
2970
|
rows.push(["Tailwind", "See `.cursor/rules/tailwind.mdc`"]);
|
|
2756
2971
|
}
|
|
2757
2972
|
if (options.ui === "shadcn") {
|
|
2758
|
-
rows.push([
|
|
2973
|
+
rows.push([
|
|
2974
|
+
"[shadcn/ui](ui/shadcn.md)",
|
|
2975
|
+
`set=${options.shadcnSet}`
|
|
2976
|
+
]);
|
|
2759
2977
|
}
|
|
2760
2978
|
if (options.styling === "mui") {
|
|
2761
2979
|
rows.push(["MUI", "See `.cursor/rules/mui.mdc`"]);
|
|
@@ -2784,9 +3002,12 @@ function docsIndex(options) {
|
|
|
2784
3002
|
if (options.husky) {
|
|
2785
3003
|
rows.push(["[Husky](tooling/husky.md)", "Pre-commit hooks"]);
|
|
2786
3004
|
}
|
|
2787
|
-
if (options.docker) {
|
|
3005
|
+
if (options.deploy === "docker") {
|
|
2788
3006
|
rows.push(["[Docker](ops/docker.md)", "Standalone production image"]);
|
|
2789
3007
|
}
|
|
3008
|
+
if (options.deploy === "vercel") {
|
|
3009
|
+
rows.push(["[Vercel](ops/vercel.md)", "vercel.json + env notes"]);
|
|
3010
|
+
}
|
|
2790
3011
|
if (options.ci) {
|
|
2791
3012
|
rows.push(["[CI](ops/ci.md)", "GitHub Actions"]);
|
|
2792
3013
|
}
|
|
@@ -2977,7 +3198,7 @@ export function cn(...inputs: ClassValue[]) {
|
|
|
2977
3198
|
return twMerge(clsx(inputs));
|
|
2978
3199
|
}
|
|
2979
3200
|
`;
|
|
2980
|
-
var
|
|
3201
|
+
var RULE10 = `---
|
|
2981
3202
|
description: Tailwind CSS v4 conventions
|
|
2982
3203
|
globs: src/app/globals.css,src/**/*.{tsx,css},postcss.config.mjs
|
|
2983
3204
|
alwaysApply: false
|
|
@@ -3010,7 +3231,7 @@ var tailwindInstaller = {
|
|
|
3010
3231
|
);
|
|
3011
3232
|
await fs23.writeFile(
|
|
3012
3233
|
path24.join(projectDir, ".cursor", "rules", "tailwind.mdc"),
|
|
3013
|
-
|
|
3234
|
+
RULE10,
|
|
3014
3235
|
"utf8"
|
|
3015
3236
|
);
|
|
3016
3237
|
await addDependencies(projectDir, {
|
|
@@ -3058,7 +3279,7 @@ export function QueryProvider({ children }: { children: ReactNode }) {
|
|
|
3058
3279
|
return <QueryClientProvider client={client}>{children}</QueryClientProvider>;
|
|
3059
3280
|
}
|
|
3060
3281
|
`;
|
|
3061
|
-
var
|
|
3282
|
+
var RULE11 = `---
|
|
3062
3283
|
description: TanStack Query conventions
|
|
3063
3284
|
globs: src/providers/**,src/hooks/**,src/endpoints/**,src/**/*query*.{ts,tsx},src/**/use-*.{ts,tsx}
|
|
3064
3285
|
alwaysApply: false
|
|
@@ -3091,7 +3312,7 @@ var tanstackQueryInstaller = {
|
|
|
3091
3312
|
await fs24.ensureDir(ruleDir);
|
|
3092
3313
|
await fs24.writeFile(
|
|
3093
3314
|
path25.join(ruleDir, "tanstack-query.mdc"),
|
|
3094
|
-
|
|
3315
|
+
RULE11,
|
|
3095
3316
|
"utf8"
|
|
3096
3317
|
);
|
|
3097
3318
|
}
|
|
@@ -3373,6 +3594,53 @@ Forms: \`@hookform/resolvers/${options.validation}\` when using RHF.
|
|
|
3373
3594
|
}
|
|
3374
3595
|
};
|
|
3375
3596
|
|
|
3597
|
+
// src/installers/vercel.ts
|
|
3598
|
+
import fs27 from "fs-extra";
|
|
3599
|
+
import path28 from "path";
|
|
3600
|
+
var VERCEL_JSON = `{
|
|
3601
|
+
"framework": "nextjs",
|
|
3602
|
+
"regions": ["iad1"]
|
|
3603
|
+
}
|
|
3604
|
+
`;
|
|
3605
|
+
var RULE12 = `---
|
|
3606
|
+
description: Vercel deployment conventions
|
|
3607
|
+
globs: vercel.json
|
|
3608
|
+
alwaysApply: false
|
|
3609
|
+
---
|
|
3610
|
+
|
|
3611
|
+
# Vercel
|
|
3612
|
+
|
|
3613
|
+
- Config: \`vercel.json\` (framework Next.js).
|
|
3614
|
+
- Set \`NEXT_PUBLIC_APP_URL\` / \`NEXT_PUBLIC_API_URL\` (and \`AUTH_SECRET\` if Auth.js) in the Vercel project env.
|
|
3615
|
+
- Prefer Preview env for staging; Production for live.
|
|
3616
|
+
- Do not commit \`.vercel\` or production secrets.
|
|
3617
|
+
`;
|
|
3618
|
+
var vercelInstaller = {
|
|
3619
|
+
id: "vercel",
|
|
3620
|
+
active: (o) => o.deploy === "vercel",
|
|
3621
|
+
async run({ projectDir }) {
|
|
3622
|
+
await fs27.writeFile(
|
|
3623
|
+
path28.join(projectDir, "vercel.json"),
|
|
3624
|
+
VERCEL_JSON,
|
|
3625
|
+
"utf8"
|
|
3626
|
+
);
|
|
3627
|
+
await fs27.writeFile(
|
|
3628
|
+
path28.join(projectDir, ".cursor", "rules", "vercel.mdc"),
|
|
3629
|
+
RULE12,
|
|
3630
|
+
"utf8"
|
|
3631
|
+
);
|
|
3632
|
+
await fs27.outputFile(
|
|
3633
|
+
path28.join(projectDir, "docs", "style-guide", "ops", "vercel.md"),
|
|
3634
|
+
`# Vercel
|
|
3635
|
+
|
|
3636
|
+
- \`vercel.json\` \u2014 Next.js framework hint
|
|
3637
|
+
- Link the repo in the Vercel dashboard (or \`npx vercel\`)
|
|
3638
|
+
- Env: copy from \`.env.production.example\` into Project \u2192 Settings \u2192 Environment Variables
|
|
3639
|
+
`
|
|
3640
|
+
);
|
|
3641
|
+
}
|
|
3642
|
+
};
|
|
3643
|
+
|
|
3376
3644
|
// src/installers/index.ts
|
|
3377
3645
|
var installers = [
|
|
3378
3646
|
packageManagerInstaller,
|
|
@@ -3396,6 +3664,7 @@ var installers = [
|
|
|
3396
3664
|
prettierInstaller,
|
|
3397
3665
|
huskyInstaller,
|
|
3398
3666
|
dockerInstaller,
|
|
3667
|
+
vercelInstaller,
|
|
3399
3668
|
ciInstaller,
|
|
3400
3669
|
appProvidersInstaller,
|
|
3401
3670
|
surfaceInstaller
|
|
@@ -3412,10 +3681,10 @@ async function runInstallers(ctx) {
|
|
|
3412
3681
|
|
|
3413
3682
|
// src/scaffold.ts
|
|
3414
3683
|
async function scaffold(options) {
|
|
3415
|
-
const projectDir =
|
|
3684
|
+
const projectDir = path29.resolve(process.cwd(), options.name);
|
|
3416
3685
|
const pm = getPackageManager(options.packageManager);
|
|
3417
|
-
if (await
|
|
3418
|
-
const entries = await
|
|
3686
|
+
if (await fs28.pathExists(projectDir)) {
|
|
3687
|
+
const entries = await fs28.readdir(projectDir);
|
|
3419
3688
|
if (entries.length > 0) {
|
|
3420
3689
|
throw new Error(
|
|
3421
3690
|
`Target directory already exists and is not empty: ${projectDir}`
|
|
@@ -3424,20 +3693,20 @@ async function scaffold(options) {
|
|
|
3424
3693
|
}
|
|
3425
3694
|
const spin = p2.spinner();
|
|
3426
3695
|
spin.start("Copying template");
|
|
3427
|
-
if (!await
|
|
3696
|
+
if (!await fs28.pathExists(TEMPLATE_DIR)) {
|
|
3428
3697
|
spin.stop("Template missing");
|
|
3429
3698
|
throw new Error(`Template directory not found at ${TEMPLATE_DIR}`);
|
|
3430
3699
|
}
|
|
3431
|
-
await
|
|
3700
|
+
await fs28.copy(TEMPLATE_DIR, projectDir, {
|
|
3432
3701
|
filter: (src) => {
|
|
3433
|
-
const base =
|
|
3702
|
+
const base = path29.basename(src);
|
|
3434
3703
|
return base !== "node_modules" && base !== ".next" && base !== "dist";
|
|
3435
3704
|
}
|
|
3436
3705
|
});
|
|
3437
|
-
const gitignoreSrc =
|
|
3438
|
-
const gitignoreDest =
|
|
3439
|
-
if (await
|
|
3440
|
-
await
|
|
3706
|
+
const gitignoreSrc = path29.join(projectDir, "gitignore");
|
|
3707
|
+
const gitignoreDest = path29.join(projectDir, ".gitignore");
|
|
3708
|
+
if (await fs28.pathExists(gitignoreSrc)) {
|
|
3709
|
+
await fs28.move(gitignoreSrc, gitignoreDest, { overwrite: true });
|
|
3441
3710
|
}
|
|
3442
3711
|
spin.message("Applying project tokens");
|
|
3443
3712
|
await replaceTokensInTree(projectDir, {
|
|
@@ -3473,8 +3742,8 @@ async function scaffold(options) {
|
|
|
3473
3742
|
}
|
|
3474
3743
|
|
|
3475
3744
|
// src/upgrade.ts
|
|
3476
|
-
import
|
|
3477
|
-
import
|
|
3745
|
+
import fs29 from "fs-extra";
|
|
3746
|
+
import path30 from "path";
|
|
3478
3747
|
import * as p3 from "@clack/prompts";
|
|
3479
3748
|
import color3 from "picocolors";
|
|
3480
3749
|
var TRACKED = [
|
|
@@ -3484,17 +3753,17 @@ var TRACKED = [
|
|
|
3484
3753
|
".cursor/rules/forms.mdc"
|
|
3485
3754
|
];
|
|
3486
3755
|
function rel(projectDir, file) {
|
|
3487
|
-
return
|
|
3756
|
+
return path30.join(projectDir, file);
|
|
3488
3757
|
}
|
|
3489
3758
|
function templatePath(file) {
|
|
3490
|
-
return
|
|
3759
|
+
return path30.join(TEMPLATE_DIR, file);
|
|
3491
3760
|
}
|
|
3492
3761
|
async function runUpgrade(options) {
|
|
3493
3762
|
const { projectDir, apply } = options;
|
|
3494
|
-
if (!await
|
|
3763
|
+
if (!await fs29.pathExists(path30.join(projectDir, "package.json"))) {
|
|
3495
3764
|
throw new Error(`Not an app directory (missing package.json): ${projectDir}`);
|
|
3496
3765
|
}
|
|
3497
|
-
if (!await
|
|
3766
|
+
if (!await fs29.pathExists(TEMPLATE_DIR)) {
|
|
3498
3767
|
throw new Error(`Template missing at ${TEMPLATE_DIR}`);
|
|
3499
3768
|
}
|
|
3500
3769
|
p3.intro(color3.bgCyan(color3.black(" next-style-guide upgrade ")));
|
|
@@ -3507,14 +3776,14 @@ async function runUpgrade(options) {
|
|
|
3507
3776
|
for (const file of TRACKED) {
|
|
3508
3777
|
const from = templatePath(file);
|
|
3509
3778
|
const to = rel(projectDir, file);
|
|
3510
|
-
if (!await
|
|
3779
|
+
if (!await fs29.pathExists(from)) {
|
|
3511
3780
|
p3.log.warn(`Template missing ${file}`);
|
|
3512
3781
|
continue;
|
|
3513
3782
|
}
|
|
3514
|
-
const next = await
|
|
3783
|
+
const next = await fs29.readFile(from, "utf8");
|
|
3515
3784
|
let outgoing = next;
|
|
3516
|
-
if (file === "AGENTS.md" && await
|
|
3517
|
-
const current2 = await
|
|
3785
|
+
if (file === "AGENTS.md" && await fs29.pathExists(to)) {
|
|
3786
|
+
const current2 = await fs29.readFile(to, "utf8");
|
|
3518
3787
|
const nameMatch = current2.match(/^# Agents \((.+)\)$/m);
|
|
3519
3788
|
if (nameMatch?.[1]) {
|
|
3520
3789
|
outgoing = outgoing.replace("__PROJECT_NAME__", nameMatch[1]);
|
|
@@ -3527,18 +3796,18 @@ async function runUpgrade(options) {
|
|
|
3527
3796
|
}
|
|
3528
3797
|
}
|
|
3529
3798
|
}
|
|
3530
|
-
outgoing = outgoing.replaceAll("__PROJECT_NAME__",
|
|
3531
|
-
if (!await
|
|
3799
|
+
outgoing = outgoing.replaceAll("__PROJECT_NAME__", path30.basename(projectDir)).replaceAll("__PACKAGE_MANAGER__", "pnpm").replaceAll("__PROJECT_SLUG__", path30.basename(projectDir));
|
|
3800
|
+
if (!await fs29.pathExists(to)) {
|
|
3532
3801
|
missing += 1;
|
|
3533
3802
|
p3.log.warn(`missing ${file}`);
|
|
3534
3803
|
if (apply) {
|
|
3535
|
-
await
|
|
3536
|
-
await
|
|
3804
|
+
await fs29.ensureDir(path30.dirname(to));
|
|
3805
|
+
await fs29.writeFile(to, outgoing, "utf8");
|
|
3537
3806
|
p3.log.success(`wrote ${file}`);
|
|
3538
3807
|
}
|
|
3539
3808
|
continue;
|
|
3540
3809
|
}
|
|
3541
|
-
const current = await
|
|
3810
|
+
const current = await fs29.readFile(to, "utf8");
|
|
3542
3811
|
if (current === outgoing) {
|
|
3543
3812
|
same += 1;
|
|
3544
3813
|
p3.log.step(color3.dim(`same ${file}`));
|
|
@@ -3547,7 +3816,7 @@ async function runUpgrade(options) {
|
|
|
3547
3816
|
changed += 1;
|
|
3548
3817
|
p3.log.warn(`differs ${file}`);
|
|
3549
3818
|
if (apply) {
|
|
3550
|
-
await
|
|
3819
|
+
await fs29.writeFile(to, outgoing, "utf8");
|
|
3551
3820
|
p3.log.success(`updated ${file}`);
|
|
3552
3821
|
}
|
|
3553
3822
|
}
|
|
@@ -3569,6 +3838,8 @@ var VALIDATION_VALUES = /* @__PURE__ */ new Set(["zod", "yup"]);
|
|
|
3569
3838
|
var AUTH_VALUES = /* @__PURE__ */ new Set(["none", "jwt", "authjs"]);
|
|
3570
3839
|
var STORE_VALUES = /* @__PURE__ */ new Set(["none", "zustand", "redux"]);
|
|
3571
3840
|
var PM_VALUES = /* @__PURE__ */ new Set(["pnpm", "npm", "yarn"]);
|
|
3841
|
+
var SHADCN_SET_VALUES = /* @__PURE__ */ new Set(["minimal", "starter"]);
|
|
3842
|
+
var DEPLOY_VALUES = /* @__PURE__ */ new Set(["none", "vercel", "docker"]);
|
|
3572
3843
|
var PRESET_VALUES = /* @__PURE__ */ new Set([
|
|
3573
3844
|
"custom",
|
|
3574
3845
|
"minimal",
|
|
@@ -3604,7 +3875,8 @@ function parseArgs(argv) {
|
|
|
3604
3875
|
noInstall: false,
|
|
3605
3876
|
yes: false,
|
|
3606
3877
|
upgrade: false,
|
|
3607
|
-
apply: false
|
|
3878
|
+
apply: false,
|
|
3879
|
+
verbose: false
|
|
3608
3880
|
};
|
|
3609
3881
|
for (let i = 0; i < args.length; i += 1) {
|
|
3610
3882
|
const arg = args[i];
|
|
@@ -3621,6 +3893,10 @@ function parseArgs(argv) {
|
|
|
3621
3893
|
out.apply = false;
|
|
3622
3894
|
continue;
|
|
3623
3895
|
}
|
|
3896
|
+
if (arg === "--verbose" || arg === "-V") {
|
|
3897
|
+
out.verbose = true;
|
|
3898
|
+
continue;
|
|
3899
|
+
}
|
|
3624
3900
|
if (arg === "--no-install") {
|
|
3625
3901
|
out.noInstall = true;
|
|
3626
3902
|
continue;
|
|
@@ -3645,7 +3921,6 @@ function parseArgs(argv) {
|
|
|
3645
3921
|
["eslint", "--eslint", "--no-eslint"],
|
|
3646
3922
|
["prettier", "--prettier", "--no-prettier"],
|
|
3647
3923
|
["husky", "--husky", "--no-husky"],
|
|
3648
|
-
["docker", "--docker", "--no-docker"],
|
|
3649
3924
|
["ci", "--ci", "--no-ci"],
|
|
3650
3925
|
["shadcn", "--shadcn", "--no-shadcn"]
|
|
3651
3926
|
];
|
|
@@ -3713,6 +3988,29 @@ function parseArgs(argv) {
|
|
|
3713
3988
|
i = icons.nextIndex;
|
|
3714
3989
|
continue;
|
|
3715
3990
|
}
|
|
3991
|
+
const shadcnSet = readChoice(arg, "--shadcn-set", SHADCN_SET_VALUES, args, i);
|
|
3992
|
+
if (shadcnSet) {
|
|
3993
|
+
out.shadcnSet = shadcnSet.value;
|
|
3994
|
+
out.shadcn = true;
|
|
3995
|
+
i = shadcnSet.nextIndex;
|
|
3996
|
+
continue;
|
|
3997
|
+
}
|
|
3998
|
+
const deploy = readChoice(arg, "--deploy", DEPLOY_VALUES, args, i);
|
|
3999
|
+
if (deploy) {
|
|
4000
|
+
out.deploy = deploy.value;
|
|
4001
|
+
i = deploy.nextIndex;
|
|
4002
|
+
continue;
|
|
4003
|
+
}
|
|
4004
|
+
if (arg === "--docker") {
|
|
4005
|
+
out.deploy = "docker";
|
|
4006
|
+
continue;
|
|
4007
|
+
}
|
|
4008
|
+
if (arg === "--no-docker") {
|
|
4009
|
+
if (out.deploy === void 0 || out.deploy === "docker") {
|
|
4010
|
+
out.deploy = "none";
|
|
4011
|
+
}
|
|
4012
|
+
continue;
|
|
4013
|
+
}
|
|
3716
4014
|
if (!arg.startsWith("-") && !out.name) {
|
|
3717
4015
|
out.name = arg;
|
|
3718
4016
|
}
|
|
@@ -3736,6 +4034,7 @@ Options:
|
|
|
3736
4034
|
--store none|zustand|redux
|
|
3737
4035
|
--styling none|tailwind|mui
|
|
3738
4036
|
--shadcn | --no-shadcn
|
|
4037
|
+
--shadcn-set minimal|starter
|
|
3739
4038
|
--dark-mode | --no-dark-mode
|
|
3740
4039
|
--validation zod|yup
|
|
3741
4040
|
--auth none|jwt|authjs
|
|
@@ -3750,8 +4049,10 @@ Options:
|
|
|
3750
4049
|
--eslint | --no-eslint
|
|
3751
4050
|
--prettier | --no-prettier
|
|
3752
4051
|
--husky | --no-husky
|
|
3753
|
-
--
|
|
4052
|
+
--deploy none|vercel|docker
|
|
4053
|
+
--docker | --no-docker (alias for --deploy docker / none)
|
|
3754
4054
|
--ci | --no-ci
|
|
4055
|
+
--verbose, -V advisory tips (e.g. Query vs store)
|
|
3755
4056
|
--help, -h
|
|
3756
4057
|
|
|
3757
4058
|
Upgrade:
|
|
@@ -3767,6 +4068,10 @@ function applyFlagOverrides(options, flags) {
|
|
|
3767
4068
|
if (flags.icons !== void 0) next.icons = flags.icons;
|
|
3768
4069
|
if (flags.styling !== void 0) next.styling = flags.styling;
|
|
3769
4070
|
if (flags.shadcn !== void 0) next.ui = flags.shadcn ? "shadcn" : "none";
|
|
4071
|
+
if (flags.shadcnSet !== void 0) {
|
|
4072
|
+
next.shadcnSet = flags.shadcnSet;
|
|
4073
|
+
next.ui = "shadcn";
|
|
4074
|
+
}
|
|
3770
4075
|
if (flags.validation !== void 0) next.validation = flags.validation;
|
|
3771
4076
|
if (flags.auth !== void 0) next.auth = flags.auth;
|
|
3772
4077
|
if (flags.store !== void 0) next.store = flags.store;
|
|
@@ -3783,14 +4088,14 @@ function applyFlagOverrides(options, flags) {
|
|
|
3783
4088
|
if (flags.eslint !== void 0) next.eslint = flags.eslint;
|
|
3784
4089
|
if (flags.prettier !== void 0) next.prettier = flags.prettier;
|
|
3785
4090
|
if (flags.husky !== void 0) next.husky = flags.husky;
|
|
3786
|
-
if (flags.
|
|
4091
|
+
if (flags.deploy !== void 0) next.deploy = flags.deploy;
|
|
3787
4092
|
if (flags.ci !== void 0) next.ci = flags.ci;
|
|
3788
4093
|
return normalizeOptions(next);
|
|
3789
4094
|
}
|
|
3790
4095
|
async function main() {
|
|
3791
4096
|
const flags = parseArgs(process.argv);
|
|
3792
4097
|
if (flags.upgrade) {
|
|
3793
|
-
const projectDir2 =
|
|
4098
|
+
const projectDir2 = path31.resolve(process.cwd(), flags.name ?? ".");
|
|
3794
4099
|
await runUpgrade({ projectDir: projectDir2, apply: flags.apply });
|
|
3795
4100
|
return;
|
|
3796
4101
|
}
|
|
@@ -3813,8 +4118,8 @@ async function main() {
|
|
|
3813
4118
|
`Non-interactive: ${options.name} (${options.slug})`,
|
|
3814
4119
|
flags.preset ? `preset=${flags.preset}` : null,
|
|
3815
4120
|
`pm=${options.packageManager}`,
|
|
3816
|
-
`styling=${options.styling} ui=${options.ui} auth=${options.auth} store=${options.store}`,
|
|
3817
|
-
`endpoints=${options.endpoints} seo=${options.seo} i18n=${options.i18n} testing=${options.testing}`
|
|
4121
|
+
`styling=${options.styling} ui=${options.ui}${options.ui === "shadcn" ? `:${options.shadcnSet}` : ""} auth=${options.auth} store=${options.store}`,
|
|
4122
|
+
`deploy=${options.deploy} endpoints=${options.endpoints} seo=${options.seo} i18n=${options.i18n} testing=${options.testing}`
|
|
3818
4123
|
].filter(Boolean).join(" \xB7 ")
|
|
3819
4124
|
);
|
|
3820
4125
|
} else {
|
|
@@ -3822,16 +4127,16 @@ async function main() {
|
|
|
3822
4127
|
options.noInstall = flags.noInstall;
|
|
3823
4128
|
options = applyFlagOverrides(options, flags);
|
|
3824
4129
|
}
|
|
3825
|
-
const warnings = collectOptionWarnings(options);
|
|
4130
|
+
const warnings = collectOptionWarnings(options, { verbose: flags.verbose });
|
|
3826
4131
|
for (const warning of warnings) {
|
|
3827
4132
|
p4.log.warn(warning);
|
|
3828
4133
|
}
|
|
3829
4134
|
const projectDir = await scaffold(options);
|
|
3830
4135
|
const pm = getPackageManager(options.packageManager);
|
|
3831
4136
|
const nextSteps = [
|
|
3832
|
-
`cd ${
|
|
4137
|
+
`cd ${path31.relative(process.cwd(), projectDir) || "."}`,
|
|
3833
4138
|
options.noInstall ? `${pm.id} ${pm.installArgs.filter((a) => a !== "--ignore-workspace").join(" ")}`.trim() : null,
|
|
3834
|
-
options.ui === "shadcn" ? "npx shadcn@latest add input #
|
|
4139
|
+
options.ui === "shadcn" && options.shadcnSet === "minimal" ? "npx shadcn@latest add input # or re-scaffold with --shadcn-set starter" : null,
|
|
3835
4140
|
options.endpoints ? `${pm.runScript("endpoints:generate")} # when API schema is up` : null,
|
|
3836
4141
|
options.testing ? pm.runScript("test") : null,
|
|
3837
4142
|
pm.runScript("dev")
|