create-vexcms 0.0.3

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 (116) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.js +2409 -0
  3. package/package.json +37 -0
  4. package/templates/base-nextjs/.prettierignore +26 -0
  5. package/templates/base-nextjs/.prettierrc +7 -0
  6. package/templates/base-nextjs/README.md +256 -0
  7. package/templates/base-nextjs/_gitignore +2 -0
  8. package/templates/base-nextjs/components.json +24 -0
  9. package/templates/base-nextjs/convex/_generated/api.d.ts +125 -0
  10. package/templates/base-nextjs/convex/_generated/api.js +23 -0
  11. package/templates/base-nextjs/convex/_generated/dataModel.d.ts +60 -0
  12. package/templates/base-nextjs/convex/_generated/server.d.ts +143 -0
  13. package/templates/base-nextjs/convex/_generated/server.js +93 -0
  14. package/templates/base-nextjs/convex/auth/adapter/index.ts +230 -0
  15. package/templates/base-nextjs/convex/auth/adapter/utils.ts +547 -0
  16. package/templates/base-nextjs/convex/auth/api.ts +8 -0
  17. package/templates/base-nextjs/convex/auth/config.ts +10 -0
  18. package/templates/base-nextjs/convex/auth/db.ts +303 -0
  19. package/templates/base-nextjs/convex/auth/index.ts +14 -0
  20. package/templates/base-nextjs/convex/auth/options.ts +63 -0
  21. package/templates/base-nextjs/convex/auth/plugins/index.ts +20 -0
  22. package/templates/base-nextjs/convex/auth/sessions.ts +60 -0
  23. package/templates/base-nextjs/convex/auth.config.ts +7 -0
  24. package/templates/base-nextjs/convex/convex.config.ts +5 -0
  25. package/templates/base-nextjs/convex/http.ts +28 -0
  26. package/templates/base-nextjs/convex/schema.ts +3 -0
  27. package/templates/base-nextjs/convex/vex/auth.ts +38 -0
  28. package/templates/base-nextjs/convex/vex/collections.ts +321 -0
  29. package/templates/base-nextjs/convex/vex/firstUser.ts +134 -0
  30. package/templates/base-nextjs/convex/vex/helpers.ts +33 -0
  31. package/templates/base-nextjs/convex/vex/impersonation.ts +51 -0
  32. package/templates/base-nextjs/convex/vex/media.ts +246 -0
  33. package/templates/base-nextjs/convex/vex/migrate.ts +74 -0
  34. package/templates/base-nextjs/convex/vex/model/collections.ts +196 -0
  35. package/templates/base-nextjs/convex/vex/model/media.ts +87 -0
  36. package/templates/base-nextjs/convex/vex/model/versions.ts +254 -0
  37. package/templates/base-nextjs/convex/vex/previewSnapshot.ts +53 -0
  38. package/templates/base-nextjs/convex/vex/versions.ts +588 -0
  39. package/templates/base-nextjs/eslint.config.mjs +164 -0
  40. package/templates/base-nextjs/next.config.ts +10 -0
  41. package/templates/base-nextjs/package.json +67 -0
  42. package/templates/base-nextjs/postcss.config.mjs +7 -0
  43. package/templates/base-nextjs/public/favicons/favicon.ico +0 -0
  44. package/templates/base-nextjs/public/file.svg +1 -0
  45. package/templates/base-nextjs/public/globe.svg +1 -0
  46. package/templates/base-nextjs/public/next.svg +1 -0
  47. package/templates/base-nextjs/public/vercel.svg +1 -0
  48. package/templates/base-nextjs/public/window.svg +1 -0
  49. package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/page.tsx +9 -0
  50. package/templates/base-nextjs/src/app/(frontend)/@auth/(...)auth/[pathname]/view.tsx +23 -0
  51. package/templates/base-nextjs/src/app/(frontend)/@auth/default.tsx +3 -0
  52. package/templates/base-nextjs/src/app/(frontend)/@auth/page.tsx +3 -0
  53. package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/page.tsx +9 -0
  54. package/templates/base-nextjs/src/app/(frontend)/auth/[pathname]/view.tsx +11 -0
  55. package/templates/base-nextjs/src/app/(frontend)/layout.tsx +14 -0
  56. package/templates/base-nextjs/src/app/(frontend)/page.tsx +116 -0
  57. package/templates/base-nextjs/src/app/admin/AdminLayoutWrapper.tsx +33 -0
  58. package/templates/base-nextjs/src/app/admin/AdminPageWrapper.tsx +38 -0
  59. package/templates/base-nextjs/src/app/admin/RichTextFieldWithMedia.tsx +101 -0
  60. package/templates/base-nextjs/src/app/admin/[[...path]]/page.tsx +15 -0
  61. package/templates/base-nextjs/src/app/admin/layout.tsx +33 -0
  62. package/templates/base-nextjs/src/app/api/auth/[...all]/route.ts +6 -0
  63. package/templates/base-nextjs/src/app/favicon.ico +0 -0
  64. package/templates/base-nextjs/src/app/globals.css +130 -0
  65. package/templates/base-nextjs/src/app/layout.tsx +30 -0
  66. package/templates/base-nextjs/src/auth/client.tsx +41 -0
  67. package/templates/base-nextjs/src/auth/permissions.ts +102 -0
  68. package/templates/base-nextjs/src/auth/server.ts +16 -0
  69. package/templates/base-nextjs/src/auth/serverUtils.ts +64 -0
  70. package/templates/base-nextjs/src/auth/types.ts +3 -0
  71. package/templates/base-nextjs/src/components/component-example.tsx +474 -0
  72. package/templates/base-nextjs/src/components/example.tsx +52 -0
  73. package/templates/base-nextjs/src/components/providers/client.tsx +9 -0
  74. package/templates/base-nextjs/src/components/providers/convex.tsx +32 -0
  75. package/templates/base-nextjs/src/components/providers/server.tsx +15 -0
  76. package/templates/base-nextjs/src/components/providers/theme.tsx +11 -0
  77. package/templates/base-nextjs/src/components/ui/alert-dialog.tsx +162 -0
  78. package/templates/base-nextjs/src/components/ui/badge.tsx +52 -0
  79. package/templates/base-nextjs/src/components/ui/button.tsx +60 -0
  80. package/templates/base-nextjs/src/components/ui/card.tsx +92 -0
  81. package/templates/base-nextjs/src/components/ui/combobox.tsx +271 -0
  82. package/templates/base-nextjs/src/components/ui/dialog.tsx +135 -0
  83. package/templates/base-nextjs/src/components/ui/dropdown-menu.tsx +246 -0
  84. package/templates/base-nextjs/src/components/ui/field.tsx +224 -0
  85. package/templates/base-nextjs/src/components/ui/input-group.tsx +146 -0
  86. package/templates/base-nextjs/src/components/ui/input.tsx +20 -0
  87. package/templates/base-nextjs/src/components/ui/label.tsx +20 -0
  88. package/templates/base-nextjs/src/components/ui/select.tsx +189 -0
  89. package/templates/base-nextjs/src/components/ui/separator.tsx +21 -0
  90. package/templates/base-nextjs/src/components/ui/textarea.tsx +18 -0
  91. package/templates/base-nextjs/src/components/ui/theme-toggle.tsx +67 -0
  92. package/templates/base-nextjs/src/db/constants/auth.ts +8 -0
  93. package/templates/base-nextjs/src/db/constants/index.ts +44 -0
  94. package/templates/base-nextjs/src/db/types.ts +6 -0
  95. package/templates/base-nextjs/src/env.mjs +48 -0
  96. package/templates/base-nextjs/src/lib/utils.ts +6 -0
  97. package/templates/base-nextjs/src/proxy.ts +23 -0
  98. package/templates/base-nextjs/src/vexcms/access.ts +28 -0
  99. package/templates/base-nextjs/src/vexcms/auth.ts +4 -0
  100. package/templates/base-nextjs/src/vexcms/collections/index.ts +1 -0
  101. package/templates/base-nextjs/src/vexcms/collections/media.ts +15 -0
  102. package/templates/base-nextjs/src/vexcms/collections/users.ts +46 -0
  103. package/templates/base-nextjs/tsconfig.json +60 -0
  104. package/templates/base-nextjs/vex.config.ts +23 -0
  105. package/templates/marketing-site/convex/pages.ts +46 -0
  106. package/templates/marketing-site/src/app/(frontend)/[slug]/page.tsx +58 -0
  107. package/templates/marketing-site/src/app/(frontend)/preview/[slug]/page.tsx +69 -0
  108. package/templates/marketing-site/src/app/admin/AdminLayoutWrapper.tsx +71 -0
  109. package/templates/marketing-site/src/db/constants/index.ts +52 -0
  110. package/templates/marketing-site/src/vexcms/collections/footers.ts +28 -0
  111. package/templates/marketing-site/src/vexcms/collections/headers.ts +35 -0
  112. package/templates/marketing-site/src/vexcms/collections/index.ts +7 -0
  113. package/templates/marketing-site/src/vexcms/collections/pages.ts +40 -0
  114. package/templates/marketing-site/src/vexcms/collections/site_settings.ts +31 -0
  115. package/templates/marketing-site/src/vexcms/collections/themes.ts +37 -0
  116. package/templates/marketing-site/vex.config.ts +32 -0
@@ -0,0 +1,474 @@
1
+ "use client"
2
+
3
+ import {
4
+ BellIcon,
5
+ BluetoothIcon,
6
+ CreditCardIcon,
7
+ DownloadIcon,
8
+ EyeIcon,
9
+ FileCodeIcon,
10
+ FileIcon,
11
+ FileTextIcon,
12
+ FolderIcon,
13
+ FolderOpenIcon,
14
+ FolderSearchIcon,
15
+ HelpCircleIcon,
16
+ KeyboardIcon,
17
+ LanguagesIcon,
18
+ LayoutIcon,
19
+ LogOutIcon,
20
+ MailIcon,
21
+ MonitorIcon,
22
+ MoonIcon,
23
+ MoreHorizontalIcon,
24
+ MoreVerticalIcon,
25
+ PaletteIcon,
26
+ PlusIcon,
27
+ SaveIcon,
28
+ SettingsIcon,
29
+ ShieldIcon,
30
+ SunIcon,
31
+ UserIcon,
32
+ } from "lucide-react"
33
+ import * as React from "react"
34
+
35
+ import { Example, ExampleWrapper } from "~/components/example"
36
+ import {
37
+ AlertDialog,
38
+ AlertDialogAction,
39
+ AlertDialogCancel,
40
+ AlertDialogContent,
41
+ AlertDialogDescription,
42
+ AlertDialogFooter,
43
+ AlertDialogHeader,
44
+ AlertDialogMedia,
45
+ AlertDialogTitle,
46
+ AlertDialogTrigger,
47
+ } from "~/components/ui/alert-dialog"
48
+ import { Badge } from "~/components/ui/badge"
49
+ import { Button } from "~/components/ui/button"
50
+ import {
51
+ Card,
52
+ CardAction,
53
+ CardContent,
54
+ CardDescription,
55
+ CardFooter,
56
+ CardHeader,
57
+ CardTitle,
58
+ } from "~/components/ui/card"
59
+ import {
60
+ Combobox,
61
+ ComboboxContent,
62
+ ComboboxEmpty,
63
+ ComboboxInput,
64
+ ComboboxItem,
65
+ ComboboxList,
66
+ } from "~/components/ui/combobox"
67
+ import {
68
+ DropdownMenu,
69
+ DropdownMenuCheckboxItem,
70
+ DropdownMenuContent,
71
+ DropdownMenuGroup,
72
+ DropdownMenuItem,
73
+ DropdownMenuLabel,
74
+ DropdownMenuPortal,
75
+ DropdownMenuRadioGroup,
76
+ DropdownMenuRadioItem,
77
+ DropdownMenuSeparator,
78
+ DropdownMenuShortcut,
79
+ DropdownMenuSub,
80
+ DropdownMenuSubContent,
81
+ DropdownMenuSubTrigger,
82
+ DropdownMenuTrigger,
83
+ } from "~/components/ui/dropdown-menu"
84
+ import { Field, FieldGroup, FieldLabel } from "~/components/ui/field"
85
+ import { Input } from "~/components/ui/input"
86
+ import {
87
+ Select,
88
+ SelectContent,
89
+ SelectGroup,
90
+ SelectItem,
91
+ SelectTrigger,
92
+ SelectValue,
93
+ } from "~/components/ui/select"
94
+ import { Textarea } from "~/components/ui/textarea"
95
+ import { ThemeToggle } from "~/components/ui/theme-toggle"
96
+
97
+ export function ComponentExample() {
98
+ return (
99
+ <ExampleWrapper>
100
+ <ThemeToggle className="absolute w-md:top-10 right-10 top-2" />
101
+ <CardExample />
102
+ <FormExample />
103
+ </ExampleWrapper>
104
+ )
105
+ }
106
+
107
+ function CardExample() {
108
+ return (
109
+ <Example className="items-center justify-center" title="Card">
110
+ <Card className="relative w-full max-w-sm overflow-hidden pt-0">
111
+ <div className="bg-primary absolute inset-0 z-30 aspect-video opacity-50 mix-blend-color" />
112
+ <img
113
+ alt="Photo by mymind on Unsplash"
114
+ className="relative z-20 aspect-video w-full object-cover brightness-60 grayscale"
115
+ src="https://images.unsplash.com/photo-1604076850742-4c7221f3101b?q=80&w=1887&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
116
+ title="Photo by mymind on Unsplash"
117
+ />
118
+ <CardHeader>
119
+ <CardTitle>Observability Plus is replacing Monitoring</CardTitle>
120
+ <CardDescription>
121
+ Switch to the improved way to explore your data, with natural language. Monitoring will
122
+ no longer be available on the Pro plan in November, 2025
123
+ </CardDescription>
124
+ </CardHeader>
125
+ <CardFooter>
126
+ <AlertDialog>
127
+ <AlertDialogTrigger render={<Button />}>
128
+ <PlusIcon data-icon="inline-start" />
129
+ Show Dialog
130
+ </AlertDialogTrigger>
131
+ <AlertDialogContent size="sm">
132
+ <AlertDialogHeader>
133
+ <AlertDialogMedia>
134
+ <BluetoothIcon />
135
+ </AlertDialogMedia>
136
+ <AlertDialogTitle>Allow accessory to connect?</AlertDialogTitle>
137
+ <AlertDialogDescription>
138
+ Do you want to allow the USB accessory to connect to this device?
139
+ </AlertDialogDescription>
140
+ </AlertDialogHeader>
141
+ <AlertDialogFooter>
142
+ <AlertDialogCancel>Don&apos;t allow</AlertDialogCancel>
143
+ <AlertDialogAction>Allow</AlertDialogAction>
144
+ </AlertDialogFooter>
145
+ </AlertDialogContent>
146
+ </AlertDialog>
147
+ <Badge className="ml-auto" variant="secondary">
148
+ Warning
149
+ </Badge>
150
+ </CardFooter>
151
+ </Card>
152
+ </Example>
153
+ )
154
+ }
155
+
156
+ const frameworks = ["Next.js", "SvelteKit", "Nuxt.js", "Remix", "Astro"] as const
157
+
158
+ const roleItems = [
159
+ { label: "Developer", value: "developer" },
160
+ { label: "Designer", value: "designer" },
161
+ { label: "Manager", value: "manager" },
162
+ { label: "Other", value: "other" },
163
+ ]
164
+
165
+ function FormExample() {
166
+ const [notifications, setNotifications] = React.useState({
167
+ email: true,
168
+ push: true,
169
+ sms: false,
170
+ })
171
+ const [theme, setTheme] = React.useState("light")
172
+
173
+ return (
174
+ <Example title="Form">
175
+ <Card className="w-full max-w-md">
176
+ <CardHeader>
177
+ <CardTitle>User Information</CardTitle>
178
+ <CardDescription>Please fill in your details below</CardDescription>
179
+ <CardAction>
180
+ <DropdownMenu>
181
+ <DropdownMenuTrigger render={<Button size="icon" variant="ghost" />}>
182
+ <MoreVerticalIcon />
183
+ <span className="sr-only">More options</span>
184
+ </DropdownMenuTrigger>
185
+ <DropdownMenuContent align="end" className="w-56">
186
+ <DropdownMenuGroup>
187
+ <DropdownMenuLabel>File</DropdownMenuLabel>
188
+ <DropdownMenuItem>
189
+ <FileIcon />
190
+ New File
191
+ <DropdownMenuShortcut>⌘N</DropdownMenuShortcut>
192
+ </DropdownMenuItem>
193
+ <DropdownMenuItem>
194
+ <FolderIcon />
195
+ New Folder
196
+ <DropdownMenuShortcut>⇧⌘N</DropdownMenuShortcut>
197
+ </DropdownMenuItem>
198
+ <DropdownMenuSub>
199
+ <DropdownMenuSubTrigger>
200
+ <FolderOpenIcon />
201
+ Open Recent
202
+ </DropdownMenuSubTrigger>
203
+ <DropdownMenuPortal>
204
+ <DropdownMenuSubContent>
205
+ <DropdownMenuGroup>
206
+ <DropdownMenuLabel>Recent Projects</DropdownMenuLabel>
207
+ <DropdownMenuItem>
208
+ <FileCodeIcon />
209
+ Project Alpha
210
+ </DropdownMenuItem>
211
+ <DropdownMenuItem>
212
+ <FileCodeIcon />
213
+ Project Beta
214
+ </DropdownMenuItem>
215
+ <DropdownMenuSub>
216
+ <DropdownMenuSubTrigger>
217
+ <MoreHorizontalIcon />
218
+ More Projects
219
+ </DropdownMenuSubTrigger>
220
+ <DropdownMenuPortal>
221
+ <DropdownMenuSubContent>
222
+ <DropdownMenuItem>
223
+ <FileCodeIcon />
224
+ Project Gamma
225
+ </DropdownMenuItem>
226
+ <DropdownMenuItem>
227
+ <FileCodeIcon />
228
+ Project Delta
229
+ </DropdownMenuItem>
230
+ </DropdownMenuSubContent>
231
+ </DropdownMenuPortal>
232
+ </DropdownMenuSub>
233
+ </DropdownMenuGroup>
234
+ <DropdownMenuSeparator />
235
+ <DropdownMenuGroup>
236
+ <DropdownMenuItem>
237
+ <FolderSearchIcon />
238
+ Browse...
239
+ </DropdownMenuItem>
240
+ </DropdownMenuGroup>
241
+ </DropdownMenuSubContent>
242
+ </DropdownMenuPortal>
243
+ </DropdownMenuSub>
244
+ <DropdownMenuSeparator />
245
+ <DropdownMenuItem>
246
+ <SaveIcon />
247
+ Save
248
+ <DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
249
+ </DropdownMenuItem>
250
+ <DropdownMenuItem>
251
+ <DownloadIcon />
252
+ Export
253
+ <DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut>
254
+ </DropdownMenuItem>
255
+ </DropdownMenuGroup>
256
+ <DropdownMenuSeparator />
257
+ <DropdownMenuGroup>
258
+ <DropdownMenuLabel>View</DropdownMenuLabel>
259
+ <DropdownMenuCheckboxItem
260
+ checked={notifications.email}
261
+ onCheckedChange={(checked) =>
262
+ setNotifications({
263
+ ...notifications,
264
+ email: checked === true,
265
+ })
266
+ }
267
+ >
268
+ <EyeIcon />
269
+ Show Sidebar
270
+ </DropdownMenuCheckboxItem>
271
+ <DropdownMenuCheckboxItem
272
+ checked={notifications.sms}
273
+ onCheckedChange={(checked) =>
274
+ setNotifications({
275
+ ...notifications,
276
+ sms: checked === true,
277
+ })
278
+ }
279
+ >
280
+ <LayoutIcon />
281
+ Show Status Bar
282
+ </DropdownMenuCheckboxItem>
283
+ <DropdownMenuSub>
284
+ <DropdownMenuSubTrigger>
285
+ <PaletteIcon />
286
+ Theme
287
+ </DropdownMenuSubTrigger>
288
+ <DropdownMenuPortal>
289
+ <DropdownMenuSubContent>
290
+ <DropdownMenuGroup>
291
+ <DropdownMenuLabel>Appearance</DropdownMenuLabel>
292
+ <DropdownMenuRadioGroup onValueChange={setTheme} value={theme}>
293
+ <DropdownMenuRadioItem value="light">
294
+ <SunIcon />
295
+ Light
296
+ </DropdownMenuRadioItem>
297
+ <DropdownMenuRadioItem value="dark">
298
+ <MoonIcon />
299
+ Dark
300
+ </DropdownMenuRadioItem>
301
+ <DropdownMenuRadioItem value="system">
302
+ <MonitorIcon />
303
+ System
304
+ </DropdownMenuRadioItem>
305
+ </DropdownMenuRadioGroup>
306
+ </DropdownMenuGroup>
307
+ </DropdownMenuSubContent>
308
+ </DropdownMenuPortal>
309
+ </DropdownMenuSub>
310
+ </DropdownMenuGroup>
311
+ <DropdownMenuSeparator />
312
+ <DropdownMenuGroup>
313
+ <DropdownMenuLabel>Account</DropdownMenuLabel>
314
+ <DropdownMenuItem>
315
+ <UserIcon />
316
+ Profile
317
+ <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
318
+ </DropdownMenuItem>
319
+ <DropdownMenuItem>
320
+ <CreditCardIcon />
321
+ Billing
322
+ </DropdownMenuItem>
323
+ <DropdownMenuSub>
324
+ <DropdownMenuSubTrigger>
325
+ <SettingsIcon />
326
+ Settings
327
+ </DropdownMenuSubTrigger>
328
+ <DropdownMenuPortal>
329
+ <DropdownMenuSubContent>
330
+ <DropdownMenuGroup>
331
+ <DropdownMenuLabel>Preferences</DropdownMenuLabel>
332
+ <DropdownMenuItem>
333
+ <KeyboardIcon />
334
+ Keyboard Shortcuts
335
+ </DropdownMenuItem>
336
+ <DropdownMenuItem>
337
+ <LanguagesIcon />
338
+ Language
339
+ </DropdownMenuItem>
340
+ <DropdownMenuSub>
341
+ <DropdownMenuSubTrigger>
342
+ <BellIcon />
343
+ Notifications
344
+ </DropdownMenuSubTrigger>
345
+ <DropdownMenuPortal>
346
+ <DropdownMenuSubContent>
347
+ <DropdownMenuGroup>
348
+ <DropdownMenuLabel>Notification Types</DropdownMenuLabel>
349
+ <DropdownMenuCheckboxItem
350
+ checked={notifications.push}
351
+ onCheckedChange={(checked) =>
352
+ setNotifications({
353
+ ...notifications,
354
+ push: checked === true,
355
+ })
356
+ }
357
+ >
358
+ <BellIcon />
359
+ Push Notifications
360
+ </DropdownMenuCheckboxItem>
361
+ <DropdownMenuCheckboxItem
362
+ checked={notifications.email}
363
+ onCheckedChange={(checked) =>
364
+ setNotifications({
365
+ ...notifications,
366
+ email: checked === true,
367
+ })
368
+ }
369
+ >
370
+ <MailIcon />
371
+ Email Notifications
372
+ </DropdownMenuCheckboxItem>
373
+ </DropdownMenuGroup>
374
+ </DropdownMenuSubContent>
375
+ </DropdownMenuPortal>
376
+ </DropdownMenuSub>
377
+ </DropdownMenuGroup>
378
+ <DropdownMenuSeparator />
379
+ <DropdownMenuGroup>
380
+ <DropdownMenuItem>
381
+ <ShieldIcon />
382
+ Privacy & Security
383
+ </DropdownMenuItem>
384
+ </DropdownMenuGroup>
385
+ </DropdownMenuSubContent>
386
+ </DropdownMenuPortal>
387
+ </DropdownMenuSub>
388
+ </DropdownMenuGroup>
389
+ <DropdownMenuSeparator />
390
+ <DropdownMenuGroup>
391
+ <DropdownMenuItem>
392
+ <HelpCircleIcon />
393
+ Help & Support
394
+ </DropdownMenuItem>
395
+ <DropdownMenuItem>
396
+ <FileTextIcon />
397
+ Documentation
398
+ </DropdownMenuItem>
399
+ </DropdownMenuGroup>
400
+ <DropdownMenuSeparator />
401
+ <DropdownMenuGroup>
402
+ <DropdownMenuItem variant="destructive">
403
+ <LogOutIcon />
404
+ Sign Out
405
+ <DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
406
+ </DropdownMenuItem>
407
+ </DropdownMenuGroup>
408
+ </DropdownMenuContent>
409
+ </DropdownMenu>
410
+ </CardAction>
411
+ </CardHeader>
412
+ <CardContent>
413
+ <form>
414
+ <FieldGroup>
415
+ <div className="grid grid-cols-2 gap-4">
416
+ <Field>
417
+ <FieldLabel htmlFor="small-form-name">Name</FieldLabel>
418
+ <Input id="small-form-name" placeholder="Enter your name" required />
419
+ </Field>
420
+ <Field>
421
+ <FieldLabel htmlFor="small-form-role">Role</FieldLabel>
422
+ <Select defaultValue={null} items={roleItems}>
423
+ <SelectTrigger id="small-form-role">
424
+ <SelectValue />
425
+ </SelectTrigger>
426
+ <SelectContent>
427
+ <SelectGroup>
428
+ {roleItems.map((item) => (
429
+ <SelectItem key={item.value} value={item.value}>
430
+ {item.label}
431
+ </SelectItem>
432
+ ))}
433
+ </SelectGroup>
434
+ </SelectContent>
435
+ </Select>
436
+ </Field>
437
+ </div>
438
+ <Field>
439
+ <FieldLabel htmlFor="small-form-framework">Framework</FieldLabel>
440
+ <Combobox items={frameworks}>
441
+ <ComboboxInput
442
+ id="small-form-framework"
443
+ placeholder="Select a framework"
444
+ required
445
+ />
446
+ <ComboboxContent>
447
+ <ComboboxEmpty>No frameworks found.</ComboboxEmpty>
448
+ <ComboboxList>
449
+ {(item) => (
450
+ <ComboboxItem key={item} value={item}>
451
+ {item}
452
+ </ComboboxItem>
453
+ )}
454
+ </ComboboxList>
455
+ </ComboboxContent>
456
+ </Combobox>
457
+ </Field>
458
+ <Field>
459
+ <FieldLabel htmlFor="small-form-comments">Comments</FieldLabel>
460
+ <Textarea id="small-form-comments" placeholder="Add any additional comments" />
461
+ </Field>
462
+ <Field orientation="horizontal">
463
+ <Button type="submit">Submit</Button>
464
+ <Button type="button" variant="outline">
465
+ Cancel
466
+ </Button>
467
+ </Field>
468
+ </FieldGroup>
469
+ </form>
470
+ </CardContent>
471
+ </Card>
472
+ </Example>
473
+ )
474
+ }
@@ -0,0 +1,52 @@
1
+ import { cn } from "~/lib/utils"
2
+
3
+ function Example({
4
+ children,
5
+ className,
6
+ containerClassName,
7
+ title,
8
+ ...props
9
+ }: React.ComponentProps<"div"> & {
10
+ containerClassName?: string
11
+ title: string
12
+ }) {
13
+ return (
14
+ <div
15
+ className={cn(
16
+ "mx-auto flex w-full max-w-lg min-w-0 flex-col gap-1 self-stretch lg:max-w-none",
17
+ containerClassName
18
+ )}
19
+ data-slot="example"
20
+ {...props}
21
+ >
22
+ <div className="text-muted-foreground px-1.5 py-2 text-xs font-medium">{title}</div>
23
+ <div
24
+ className={cn(
25
+ "bg-background text-foreground flex min-w-0 flex-1 flex-col items-start gap-6 border border-dashed p-4 sm:p-6 *:[div:not([class*='w-'])]:w-full",
26
+ className
27
+ )}
28
+ data-slot="example-content"
29
+ >
30
+ {children}
31
+ </div>
32
+ </div>
33
+ )
34
+ }
35
+
36
+ function ExampleWrapper({ className, ...props }: React.ComponentProps<"div">) {
37
+ return (
38
+ <div className="bg-background w-full">
39
+ <div
40
+ className={cn(
41
+ "mx-auto grid min-h-screen w-full max-w-5xl min-w-0 content-center items-start gap-8 p-4 pt-2 sm:gap-12 sm:p-6 md:grid-cols-2 md:gap-8 lg:p-12 2xl:max-w-6xl",
42
+
43
+ className
44
+ )}
45
+ data-slot="example-wrapper"
46
+ {...props}
47
+ />
48
+ </div>
49
+ )
50
+ }
51
+
52
+ export { Example, ExampleWrapper }
@@ -0,0 +1,9 @@
1
+ "use client"
2
+
3
+ import { type PropsWithChildren } from "react"
4
+
5
+ import BetterAuthClientProvider from "~/auth/client"
6
+
7
+ export default function ClientProviders({ children }: PropsWithChildren) {
8
+ return <BetterAuthClientProvider>{children}</BetterAuthClientProvider>
9
+ }
@@ -0,0 +1,32 @@
1
+ "use client"
2
+
3
+ import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react"
4
+ import { ConvexQueryClient } from "@convex-dev/react-query"
5
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
6
+ import { ConvexReactClient } from "convex/react"
7
+ import { type ReactNode } from "react"
8
+
9
+ import { authClient } from "~/auth/client"
10
+ import { env } from "~/env.mjs"
11
+
12
+ const convex = new ConvexReactClient(env.NEXT_PUBLIC_CONVEX_URL, {
13
+ expectAuth: true,
14
+ })
15
+ const convexQueryClient = new ConvexQueryClient(convex)
16
+ const queryClient = new QueryClient({
17
+ defaultOptions: {
18
+ queries: {
19
+ queryFn: convexQueryClient.queryFn(),
20
+ queryKeyHashFn: convexQueryClient.hashFn(),
21
+ },
22
+ },
23
+ })
24
+ convexQueryClient.connect(queryClient)
25
+
26
+ export default function ConvexClientProvider({ children }: { children: ReactNode }) {
27
+ return (
28
+ <ConvexBetterAuthProvider authClient={authClient} client={convex}>
29
+ <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
30
+ </ConvexBetterAuthProvider>
31
+ )
32
+ }
@@ -0,0 +1,15 @@
1
+ import { NuqsAdapter } from "nuqs/adapters/next/app"
2
+ import { type PropsWithChildren } from "react"
3
+
4
+ import ConvexClientProvider from "./convex"
5
+ import { ThemeProvider } from "./theme"
6
+
7
+ export default function ServerProviders({ children }: PropsWithChildren) {
8
+ return (
9
+ <ThemeProvider attribute="class" defaultTheme="system" disableTransitionOnChange enableSystem>
10
+ <ConvexClientProvider>
11
+ <NuqsAdapter>{children}</NuqsAdapter>
12
+ </ConvexClientProvider>
13
+ </ThemeProvider>
14
+ )
15
+ }
@@ -0,0 +1,11 @@
1
+ "use client"
2
+
3
+ import { ThemeProvider as NextThemesProvider } from "next-themes"
4
+ import * as React from "react"
5
+
6
+ export function ThemeProvider({
7
+ children,
8
+ ...props
9
+ }: React.ComponentProps<typeof NextThemesProvider>) {
10
+ return <NextThemesProvider {...props}>{children}</NextThemesProvider>
11
+ }