@beignet/cli 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/choices.d.ts +5 -28
  3. package/dist/choices.d.ts.map +1 -1
  4. package/dist/choices.js +0 -35
  5. package/dist/choices.js.map +1 -1
  6. package/dist/create-prompts.d.ts +5 -6
  7. package/dist/create-prompts.d.ts.map +1 -1
  8. package/dist/create-prompts.js +19 -77
  9. package/dist/create-prompts.js.map +1 -1
  10. package/dist/create.d.ts +6 -4
  11. package/dist/create.d.ts.map +1 -1
  12. package/dist/create.js +15 -24
  13. package/dist/create.js.map +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +32 -39
  16. package/dist/index.js.map +1 -1
  17. package/dist/lib.d.ts +1 -1
  18. package/dist/lib.d.ts.map +1 -1
  19. package/dist/make.d.ts.map +1 -1
  20. package/dist/make.js +153 -1
  21. package/dist/make.js.map +1 -1
  22. package/dist/templates/base.d.ts +13 -0
  23. package/dist/templates/base.d.ts.map +1 -0
  24. package/dist/templates/base.js +300 -0
  25. package/dist/templates/base.js.map +1 -0
  26. package/dist/templates/db.d.ts +15 -0
  27. package/dist/templates/db.d.ts.map +1 -0
  28. package/dist/templates/db.js +1001 -0
  29. package/dist/templates/db.js.map +1 -0
  30. package/dist/templates/index.d.ts +14 -0
  31. package/dist/templates/index.d.ts.map +1 -0
  32. package/dist/templates/index.js +124 -0
  33. package/dist/templates/index.js.map +1 -0
  34. package/dist/templates/server.d.ts +26 -0
  35. package/dist/templates/server.d.ts.map +1 -0
  36. package/dist/templates/server.js +525 -0
  37. package/dist/templates/server.js.map +1 -0
  38. package/dist/templates/shadcn.d.ts +5 -0
  39. package/dist/templates/shadcn.d.ts.map +1 -0
  40. package/dist/templates/shadcn.js +555 -0
  41. package/dist/templates/shadcn.js.map +1 -0
  42. package/dist/templates/shared.d.ts +49 -0
  43. package/dist/templates/shared.d.ts.map +1 -0
  44. package/dist/templates/shared.js +57 -0
  45. package/dist/templates/shared.js.map +1 -0
  46. package/dist/templates/shell.d.ts +5 -0
  47. package/dist/templates/shell.d.ts.map +1 -0
  48. package/dist/templates/shell.js +1198 -0
  49. package/dist/templates/shell.js.map +1 -0
  50. package/dist/templates/todos.d.ts +17 -0
  51. package/dist/templates/todos.d.ts.map +1 -0
  52. package/dist/templates/todos.js +607 -0
  53. package/dist/templates/todos.js.map +1 -0
  54. package/package.json +2 -2
  55. package/src/choices.ts +4 -58
  56. package/src/create-prompts.ts +20 -88
  57. package/src/create.ts +21 -38
  58. package/src/index.ts +39 -45
  59. package/src/lib.ts +1 -1
  60. package/src/make.ts +208 -1
  61. package/src/templates/base.ts +377 -0
  62. package/src/templates/db.ts +1002 -0
  63. package/src/templates/index.ts +149 -0
  64. package/src/templates/server.ts +533 -0
  65. package/src/templates/shadcn.ts +570 -0
  66. package/src/templates/shared.ts +90 -0
  67. package/src/templates/shell.ts +1227 -0
  68. package/src/templates/todos.ts +607 -0
  69. package/dist/templates.d.ts +0 -26
  70. package/dist/templates.d.ts.map +0 -1
  71. package/dist/templates.js +0 -3995
  72. package/dist/templates.js.map +0 -1
  73. package/src/templates.ts +0 -4280
@@ -0,0 +1,570 @@
1
+ import type { TemplateFile } from "./shared.js";
2
+
3
+ /**
4
+ * shadcn UI stack for generated apps: Tailwind v4 wiring, the radix-nova
5
+ * design tokens, the `cn` helper, and the ui primitives the starter shell
6
+ * uses.
7
+ *
8
+ * The config, tokens, and most primitives are vendored byte-identically from
9
+ * `apps/example-twitter-clone` (shadcn style "radix-nova"), which is the
10
+ * repo's source of truth for this stack. `checkbox` and `label` are ported
11
+ * from the radix-nova registry following the same conventions.
12
+ */
13
+
14
+ const postcssConfig = `const config = {
15
+ plugins: {
16
+ "@tailwindcss/postcss": {},
17
+ },
18
+ };
19
+
20
+ export default config;
21
+ `;
22
+
23
+ const componentsJson = `{
24
+ "$schema": "https://ui.shadcn.com/schema.json",
25
+ "style": "radix-nova",
26
+ "rsc": true,
27
+ "tsx": true,
28
+ "tailwind": {
29
+ "config": "",
30
+ "css": "app/globals.css",
31
+ "baseColor": "neutral",
32
+ "cssVariables": true,
33
+ "prefix": ""
34
+ },
35
+ "iconLibrary": "lucide",
36
+ "rtl": false,
37
+ "aliases": {
38
+ "components": "@/components",
39
+ "utils": "@/lib/utils",
40
+ "ui": "@/components/ui",
41
+ "lib": "@/lib",
42
+ "hooks": "@/hooks"
43
+ },
44
+ "menuColor": "default",
45
+ "menuAccent": "subtle",
46
+ "registries": {}
47
+ }
48
+ `;
49
+
50
+ const libUtils = `import { type ClassValue, clsx } from "clsx";
51
+ import { twMerge } from "tailwind-merge";
52
+
53
+ export function cn(...inputs: ClassValue[]) {
54
+ return twMerge(clsx(inputs));
55
+ }
56
+ `;
57
+
58
+ const appGlobalsCss = `@import "tailwindcss";
59
+ @import "tw-animate-css";
60
+ @import "shadcn/tailwind.css";
61
+
62
+ @custom-variant dark (&:is(.dark *));
63
+
64
+ :root {
65
+ --background: oklch(1 0 0);
66
+ --foreground: oklch(0.145 0 0);
67
+ --card: oklch(1 0 0);
68
+ --card-foreground: oklch(0.145 0 0);
69
+ --popover: oklch(1 0 0);
70
+ --popover-foreground: oklch(0.145 0 0);
71
+ --primary: oklch(0.145 0 0);
72
+ --primary-foreground: oklch(1 0 0);
73
+ --secondary: oklch(0.967 0.001 286.375);
74
+ --secondary-foreground: oklch(0.21 0.006 285.885);
75
+ --muted: oklch(0.97 0 0);
76
+ --muted-foreground: oklch(0.556 0 0);
77
+ --accent: oklch(0.97 0 0);
78
+ --accent-foreground: oklch(0.205 0 0);
79
+ --destructive: oklch(0.577 0.245 27.325);
80
+ --border: oklch(0.922 0 0);
81
+ --input: oklch(0.922 0 0);
82
+ --ring: oklch(0.708 0 0);
83
+ --chart-1: oklch(0.87 0 0);
84
+ --chart-2: oklch(0.556 0 0);
85
+ --chart-3: oklch(0.439 0 0);
86
+ --chart-4: oklch(0.371 0 0);
87
+ --chart-5: oklch(0.269 0 0);
88
+ --radius: 0.625rem;
89
+ --sidebar: oklch(0.985 0 0);
90
+ --sidebar-foreground: oklch(0.145 0 0);
91
+ --sidebar-primary: oklch(0.145 0 0);
92
+ --sidebar-primary-foreground: oklch(1 0 0);
93
+ --sidebar-accent: oklch(0.97 0 0);
94
+ --sidebar-accent-foreground: oklch(0.205 0 0);
95
+ --sidebar-border: oklch(0.922 0 0);
96
+ --sidebar-ring: oklch(0.708 0 0);
97
+ }
98
+
99
+ @theme inline {
100
+ --font-heading: var(--font-sans);
101
+ --font-sans: var(--font-sans);
102
+ --color-sidebar-ring: var(--sidebar-ring);
103
+ --color-sidebar-border: var(--sidebar-border);
104
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
105
+ --color-sidebar-accent: var(--sidebar-accent);
106
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
107
+ --color-sidebar-primary: var(--sidebar-primary);
108
+ --color-sidebar-foreground: var(--sidebar-foreground);
109
+ --color-sidebar: var(--sidebar);
110
+ --color-chart-5: var(--chart-5);
111
+ --color-chart-4: var(--chart-4);
112
+ --color-chart-3: var(--chart-3);
113
+ --color-chart-2: var(--chart-2);
114
+ --color-chart-1: var(--chart-1);
115
+ --color-ring: var(--ring);
116
+ --color-input: var(--input);
117
+ --color-border: var(--border);
118
+ --color-destructive: var(--destructive);
119
+ --color-accent-foreground: var(--accent-foreground);
120
+ --color-accent: var(--accent);
121
+ --color-muted-foreground: var(--muted-foreground);
122
+ --color-muted: var(--muted);
123
+ --color-secondary-foreground: var(--secondary-foreground);
124
+ --color-secondary: var(--secondary);
125
+ --color-primary-foreground: var(--primary-foreground);
126
+ --color-primary: var(--primary);
127
+ --color-popover-foreground: var(--popover-foreground);
128
+ --color-popover: var(--popover);
129
+ --color-card-foreground: var(--card-foreground);
130
+ --color-card: var(--card);
131
+ --color-foreground: var(--foreground);
132
+ --color-background: var(--background);
133
+ --radius-sm: calc(var(--radius) * 0.6);
134
+ --radius-md: calc(var(--radius) * 0.8);
135
+ --radius-lg: var(--radius);
136
+ --radius-xl: calc(var(--radius) * 1.4);
137
+ --radius-2xl: calc(var(--radius) * 1.8);
138
+ --radius-3xl: calc(var(--radius) * 2.2);
139
+ --radius-4xl: calc(var(--radius) * 2.6);
140
+ }
141
+
142
+ .dark {
143
+ --background: oklch(0.145 0 0);
144
+ --foreground: oklch(0.985 0 0);
145
+ --card: oklch(0.205 0 0);
146
+ --card-foreground: oklch(0.985 0 0);
147
+ --popover: oklch(0.205 0 0);
148
+ --popover-foreground: oklch(0.985 0 0);
149
+ --primary: oklch(0.985 0 0);
150
+ --primary-foreground: oklch(0.145 0 0);
151
+ --secondary: oklch(0.274 0.006 286.033);
152
+ --secondary-foreground: oklch(0.985 0 0);
153
+ --muted: oklch(0.269 0 0);
154
+ --muted-foreground: oklch(0.708 0 0);
155
+ --accent: oklch(0.269 0 0);
156
+ --accent-foreground: oklch(0.985 0 0);
157
+ --destructive: oklch(0.704 0.191 22.216);
158
+ --border: oklch(1 0 0 / 10%);
159
+ --input: oklch(1 0 0 / 15%);
160
+ --ring: oklch(0.556 0 0);
161
+ --chart-1: oklch(0.87 0 0);
162
+ --chart-2: oklch(0.556 0 0);
163
+ --chart-3: oklch(0.439 0 0);
164
+ --chart-4: oklch(0.371 0 0);
165
+ --chart-5: oklch(0.269 0 0);
166
+ --sidebar: oklch(0.205 0 0);
167
+ --sidebar-foreground: oklch(0.985 0 0);
168
+ --sidebar-primary: oklch(0.985 0 0);
169
+ --sidebar-primary-foreground: oklch(0.145 0 0);
170
+ --sidebar-accent: oklch(0.269 0 0);
171
+ --sidebar-accent-foreground: oklch(0.985 0 0);
172
+ --sidebar-border: oklch(1 0 0 / 10%);
173
+ --sidebar-ring: oklch(0.556 0 0);
174
+ }
175
+
176
+ @layer base {
177
+ * {
178
+ @apply border-border outline-ring/50;
179
+ }
180
+ body {
181
+ @apply bg-background text-foreground;
182
+ }
183
+ html {
184
+ @apply font-sans;
185
+ }
186
+ }
187
+ `;
188
+
189
+ const uiButton = `import { cva, type VariantProps } from "class-variance-authority";
190
+ import { Slot } from "radix-ui";
191
+ import type * as React from "react";
192
+
193
+ import { cn } from "@/lib/utils";
194
+
195
+ const buttonVariants = cva(
196
+ "group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
197
+ {
198
+ variants: {
199
+ variant: {
200
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
201
+ outline:
202
+ "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
203
+ secondary:
204
+ "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
205
+ ghost:
206
+ "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
207
+ destructive:
208
+ "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
209
+ link: "text-primary underline-offset-4 hover:underline",
210
+ },
211
+ size: {
212
+ default:
213
+ "h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
214
+ xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
215
+ sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
216
+ lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
217
+ icon: "size-8",
218
+ "icon-xs":
219
+ "size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
220
+ "icon-sm":
221
+ "size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
222
+ "icon-lg": "size-9",
223
+ },
224
+ },
225
+ defaultVariants: {
226
+ variant: "default",
227
+ size: "default",
228
+ },
229
+ },
230
+ );
231
+
232
+ function Button({
233
+ className,
234
+ variant = "default",
235
+ size = "default",
236
+ asChild = false,
237
+ ...props
238
+ }: React.ComponentProps<"button"> &
239
+ VariantProps<typeof buttonVariants> & {
240
+ asChild?: boolean;
241
+ }) {
242
+ const Comp = asChild ? Slot.Root : "button";
243
+
244
+ return (
245
+ <Comp
246
+ data-slot="button"
247
+ data-variant={variant}
248
+ data-size={size}
249
+ className={cn(buttonVariants({ variant, size, className }))}
250
+ {...props}
251
+ />
252
+ );
253
+ }
254
+
255
+ export { Button, buttonVariants };
256
+ `;
257
+
258
+ const uiCard = `import type * as React from "react";
259
+
260
+ import { cn } from "@/lib/utils";
261
+
262
+ function Card({
263
+ className,
264
+ size = "default",
265
+ ...props
266
+ }: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
267
+ return (
268
+ <div
269
+ data-slot="card"
270
+ data-size={size}
271
+ className={cn(
272
+ "group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
273
+ className,
274
+ )}
275
+ {...props}
276
+ />
277
+ );
278
+ }
279
+
280
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
281
+ return (
282
+ <div
283
+ data-slot="card-header"
284
+ className={cn(
285
+ "group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
286
+ className,
287
+ )}
288
+ {...props}
289
+ />
290
+ );
291
+ }
292
+
293
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
294
+ return (
295
+ <div
296
+ data-slot="card-title"
297
+ className={cn(
298
+ "font-heading text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
299
+ className,
300
+ )}
301
+ {...props}
302
+ />
303
+ );
304
+ }
305
+
306
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
307
+ return (
308
+ <div
309
+ data-slot="card-description"
310
+ className={cn("text-sm text-muted-foreground", className)}
311
+ {...props}
312
+ />
313
+ );
314
+ }
315
+
316
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
317
+ return (
318
+ <div
319
+ data-slot="card-action"
320
+ className={cn(
321
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
322
+ className,
323
+ )}
324
+ {...props}
325
+ />
326
+ );
327
+ }
328
+
329
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
330
+ return (
331
+ <div
332
+ data-slot="card-content"
333
+ className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
334
+ {...props}
335
+ />
336
+ );
337
+ }
338
+
339
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
340
+ return (
341
+ <div
342
+ data-slot="card-footer"
343
+ className={cn(
344
+ "flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
345
+ className,
346
+ )}
347
+ {...props}
348
+ />
349
+ );
350
+ }
351
+
352
+ export {
353
+ Card,
354
+ CardAction,
355
+ CardContent,
356
+ CardDescription,
357
+ CardFooter,
358
+ CardHeader,
359
+ CardTitle,
360
+ };
361
+ `;
362
+
363
+ const uiCheckbox = `"use client";
364
+
365
+ import { CheckIcon } from "lucide-react";
366
+ import { Checkbox as CheckboxPrimitive } from "radix-ui";
367
+ import type * as React from "react";
368
+
369
+ import { cn } from "@/lib/utils";
370
+
371
+ function Checkbox({
372
+ className,
373
+ ...props
374
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
375
+ return (
376
+ <CheckboxPrimitive.Root
377
+ data-slot="checkbox"
378
+ className={cn(
379
+ "peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
380
+ className,
381
+ )}
382
+ {...props}
383
+ >
384
+ <CheckboxPrimitive.Indicator
385
+ data-slot="checkbox-indicator"
386
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
387
+ >
388
+ <CheckIcon />
389
+ </CheckboxPrimitive.Indicator>
390
+ </CheckboxPrimitive.Root>
391
+ );
392
+ }
393
+
394
+ export { Checkbox };
395
+ `;
396
+
397
+ const uiDropdownMenu = `"use client";
398
+
399
+ import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui";
400
+ import type * as React from "react";
401
+ import { cn } from "@/lib/utils";
402
+
403
+ function DropdownMenu({
404
+ ...props
405
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
406
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
407
+ }
408
+
409
+ function DropdownMenuTrigger({
410
+ ...props
411
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
412
+ return (
413
+ <DropdownMenuPrimitive.Trigger
414
+ data-slot="dropdown-menu-trigger"
415
+ {...props}
416
+ />
417
+ );
418
+ }
419
+
420
+ function DropdownMenuContent({
421
+ className,
422
+ sideOffset = 6,
423
+ ...props
424
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
425
+ return (
426
+ <DropdownMenuPrimitive.Portal>
427
+ <DropdownMenuPrimitive.Content
428
+ data-slot="dropdown-menu-content"
429
+ sideOffset={sideOffset}
430
+ className={cn(
431
+ "z-50 min-w-40 rounded-xl border border-border bg-popover p-1 text-popover-foreground text-sm shadow-lg outline-none data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95",
432
+ className,
433
+ )}
434
+ {...props}
435
+ />
436
+ </DropdownMenuPrimitive.Portal>
437
+ );
438
+ }
439
+
440
+ function DropdownMenuItem({
441
+ className,
442
+ ...props
443
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item>) {
444
+ return (
445
+ <DropdownMenuPrimitive.Item
446
+ data-slot="dropdown-menu-item"
447
+ className={cn(
448
+ "relative flex cursor-default select-none items-center gap-2 rounded-lg px-2 py-2 outline-none focus:bg-muted disabled:pointer-events-none disabled:opacity-50",
449
+ className,
450
+ )}
451
+ {...props}
452
+ />
453
+ );
454
+ }
455
+
456
+ export {
457
+ DropdownMenu,
458
+ DropdownMenuContent,
459
+ DropdownMenuItem,
460
+ DropdownMenuTrigger,
461
+ };
462
+ `;
463
+
464
+ const uiInput = `import type * as React from "react";
465
+
466
+ import { cn } from "@/lib/utils";
467
+
468
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
469
+ return (
470
+ <input
471
+ type={type}
472
+ data-slot="input"
473
+ className={cn(
474
+ "h-8 w-full min-w-0 rounded-lg border border-input bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:bg-input/50 disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 md:text-sm dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40",
475
+ className,
476
+ )}
477
+ {...props}
478
+ />
479
+ );
480
+ }
481
+
482
+ export { Input };
483
+ `;
484
+
485
+ const uiLabel = `"use client";
486
+
487
+ import { Label as LabelPrimitive } from "radix-ui";
488
+ import type * as React from "react";
489
+
490
+ import { cn } from "@/lib/utils";
491
+
492
+ function Label({
493
+ className,
494
+ ...props
495
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
496
+ return (
497
+ <LabelPrimitive.Root
498
+ data-slot="label"
499
+ className={cn(
500
+ "flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
501
+ className,
502
+ )}
503
+ {...props}
504
+ />
505
+ );
506
+ }
507
+
508
+ export { Label };
509
+ `;
510
+
511
+ const uiSeparator = `"use client";
512
+
513
+ import { Separator as SeparatorPrimitive } from "radix-ui";
514
+ import type * as React from "react";
515
+
516
+ import { cn } from "@/lib/utils";
517
+
518
+ function Separator({
519
+ className,
520
+ orientation = "horizontal",
521
+ decorative = true,
522
+ ...props
523
+ }: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
524
+ return (
525
+ <SeparatorPrimitive.Root
526
+ data-slot="separator"
527
+ decorative={decorative}
528
+ orientation={orientation}
529
+ className={cn(
530
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
531
+ className,
532
+ )}
533
+ {...props}
534
+ />
535
+ );
536
+ }
537
+
538
+ export { Separator };
539
+ `;
540
+
541
+ export function shadcnTemplateFiles(): TemplateFile[] {
542
+ return [
543
+ { path: "postcss.config.mjs", content: postcssConfig },
544
+ { path: "components.json", content: componentsJson },
545
+ { path: "lib/utils.ts", content: libUtils },
546
+ { path: "app/globals.css", content: appGlobalsCss },
547
+ { path: "components/ui/button.tsx", content: uiButton },
548
+ { path: "components/ui/card.tsx", content: uiCard },
549
+ { path: "components/ui/checkbox.tsx", content: uiCheckbox },
550
+ { path: "components/ui/dropdown-menu.tsx", content: uiDropdownMenu },
551
+ { path: "components/ui/input.tsx", content: uiInput },
552
+ { path: "components/ui/label.tsx", content: uiLabel },
553
+ { path: "components/ui/separator.tsx", content: uiSeparator },
554
+ ];
555
+ }
556
+
557
+ export const shadcnDependencies: Record<string, string> = {
558
+ "class-variance-authority": "^0.7.1",
559
+ clsx: "^2.1.1",
560
+ "lucide-react": "^1.16.0",
561
+ "radix-ui": "^1.4.3",
562
+ shadcn: "^4.7.0",
563
+ "tailwind-merge": "^3.6.0",
564
+ "tw-animate-css": "^1.4.0",
565
+ };
566
+
567
+ export const shadcnDevDependencies: Record<string, string> = {
568
+ "@tailwindcss/postcss": "^4.3.0",
569
+ tailwindcss: "^4.3.0",
570
+ };
@@ -0,0 +1,90 @@
1
+ import type { IntegrationName, PackageManager } from "../choices.js";
2
+
3
+ /**
4
+ * One generated file emitted by the template generator.
5
+ */
6
+ export type TemplateFile = {
7
+ path: string;
8
+ content: string;
9
+ };
10
+
11
+ /**
12
+ * Inputs used to render app template files.
13
+ */
14
+ export type TemplateContext = {
15
+ name: string;
16
+ packageManager: PackageManager;
17
+ beignetVersion: string;
18
+ /**
19
+ * When true, scaffold an API-only app without the UI shell.
20
+ */
21
+ api: boolean;
22
+ integrations: IntegrationName[];
23
+ };
24
+
25
+ export const externalVersions = {
26
+ next: "^16.2.4",
27
+ react: "^19.2.5",
28
+ reactDom: "^19.2.5",
29
+ typescript: "^5.3.0",
30
+ typesBun: "^1.3.13",
31
+ typesNode: "^20.10.0",
32
+ typesReact: "^19.0.0",
33
+ typesReactDom: "^19.0.0",
34
+ zod: "^4.0.0",
35
+ tanstackReactQuery: "^5.100.7",
36
+ hookformResolvers: "^5.0.0",
37
+ reactHookForm: "^7.74.0",
38
+ betterAuth: "1.6.11",
39
+ drizzleKit: "^0.31.10",
40
+ drizzleOrm: "^0.45.2",
41
+ inngest: "^3.0.0",
42
+ libsqlClient: "^0.14.0",
43
+ pino: "^9.7.0",
44
+ resend: "^4.0.1",
45
+ upstashRateLimit: "^2.0.0",
46
+ upstashRedis: "^1.0.0",
47
+ };
48
+
49
+ export function packageRunner(ctx: TemplateContext): string {
50
+ switch (ctx.packageManager) {
51
+ case "npm":
52
+ return "npm run beignet --";
53
+ case "pnpm":
54
+ return "pnpm beignet";
55
+ case "yarn":
56
+ return "yarn beignet";
57
+ default:
58
+ return "bun beignet";
59
+ }
60
+ }
61
+
62
+ export const integrationDeps: Record<
63
+ IntegrationName,
64
+ Record<string, string>
65
+ > = {
66
+ inngest: {
67
+ "@beignet/provider-inngest": "",
68
+ inngest: externalVersions.inngest,
69
+ },
70
+ resend: {
71
+ "@beignet/provider-mail-resend": "",
72
+ resend: externalVersions.resend,
73
+ },
74
+ "upstash-rate-limit": {
75
+ "@beignet/provider-rate-limit-upstash": "",
76
+ "@upstash/ratelimit": externalVersions.upstashRateLimit,
77
+ "@upstash/redis": externalVersions.upstashRedis,
78
+ },
79
+ };
80
+
81
+ export function hasIntegration(
82
+ ctx: TemplateContext,
83
+ integration: IntegrationName,
84
+ ): boolean {
85
+ return ctx.integrations.includes(integration);
86
+ }
87
+
88
+ export function json(value: unknown): string {
89
+ return `${JSON.stringify(value, null, "\t")}\n`;
90
+ }