create-ej-app 24.0.0 → 26.0.0

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 (161) hide show
  1. package/cli.js +6 -0
  2. package/cli.ts +8 -0
  3. package/package.json +2 -2
  4. package/template/api/package.json +2 -2
  5. package/template/nextjs/gitignore +1 -0
  6. package/template/nextjs/package.json +20 -20
  7. package/template/nextjs/postcss.config.mjs +3 -1
  8. package/template/saas-starter/.dockerignore +7 -0
  9. package/template/saas-starter/.env.example +25 -0
  10. package/template/saas-starter/.vscode/extensions.json +11 -0
  11. package/template/saas-starter/.vscode/settings.json +3 -0
  12. package/template/saas-starter/Dockerfile +15 -0
  13. package/template/saas-starter/README.md +3 -0
  14. package/template/saas-starter/components.json +25 -0
  15. package/template/saas-starter/drizzle.config.ts +10 -0
  16. package/template/saas-starter/eslint.config.mjs +23 -0
  17. package/template/saas-starter/gitignore +9 -0
  18. package/template/saas-starter/next-env.d.ts +6 -0
  19. package/template/saas-starter/next.config.ts +14 -0
  20. package/template/saas-starter/package.json +92 -0
  21. package/template/saas-starter/postcss.config.mjs +7 -0
  22. package/template/saas-starter/prettier.config.mjs +11 -0
  23. package/template/saas-starter/public/placeholder.svg +1 -0
  24. package/template/saas-starter/src/actions/uploads.ts +28 -0
  25. package/template/saas-starter/src/actions/uploads.validation.ts +14 -0
  26. package/template/saas-starter/src/app/(admin)/actions/users.ts +97 -0
  27. package/template/saas-starter/src/app/(admin)/admin/_components/admin-header.tsx +21 -0
  28. package/template/saas-starter/src/app/(admin)/admin/_components/admin-search.tsx +16 -0
  29. package/template/saas-starter/src/app/(admin)/admin/_components/admin-sidebar.tsx +40 -0
  30. package/template/saas-starter/src/app/(admin)/admin/layout.tsx +57 -0
  31. package/template/saas-starter/src/app/(admin)/admin/page.tsx +3 -0
  32. package/template/saas-starter/src/app/(admin)/admin/settings/users/_components/create-user-dialog.tsx +183 -0
  33. package/template/saas-starter/src/app/(admin)/admin/settings/users/_components/edit-name-dialog.tsx +129 -0
  34. package/template/saas-starter/src/app/(admin)/admin/settings/users/_components/users-table.tsx +415 -0
  35. package/template/saas-starter/src/app/(admin)/admin/settings/users/page.tsx +15 -0
  36. package/template/saas-starter/src/app/(app)/actions/billing.ts +152 -0
  37. package/template/saas-starter/src/app/(app)/actions/members.ts +163 -0
  38. package/template/saas-starter/src/app/(app)/actions/organization.ts +92 -0
  39. package/template/saas-starter/src/app/(app)/app/[orgId]/dashboard/page.tsx +20 -0
  40. package/template/saas-starter/src/app/(app)/app/[orgId]/layout.tsx +34 -0
  41. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/_components/billing-email-form.tsx +100 -0
  42. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/_components/danger-zone.tsx +364 -0
  43. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/_components/general-settings-form.tsx +155 -0
  44. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/_components/plans-section.tsx +232 -0
  45. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/billing/page.tsx +116 -0
  46. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/members/_components/invite-member-dialog.tsx +169 -0
  47. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/members/_components/members-tabs.tsx +571 -0
  48. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/members/page.tsx +40 -0
  49. package/template/saas-starter/src/app/(app)/app/[orgId]/settings/page.tsx +69 -0
  50. package/template/saas-starter/src/app/(app)/app/_components/app-header.tsx +29 -0
  51. package/template/saas-starter/src/app/(app)/app/_components/app-search.tsx +17 -0
  52. package/template/saas-starter/src/app/(app)/app/_components/app-sidebar.tsx +27 -0
  53. package/template/saas-starter/src/app/(app)/app/_components/organization-context.tsx +41 -0
  54. package/template/saas-starter/src/app/(app)/app/_components/organization-switcher.tsx +140 -0
  55. package/template/saas-starter/src/app/(app)/app/layout.tsx +52 -0
  56. package/template/saas-starter/src/app/(app)/app/onboarding/_components/create-organization-form.tsx +129 -0
  57. package/template/saas-starter/src/app/(app)/app/onboarding/page.tsx +42 -0
  58. package/template/saas-starter/src/app/(app)/app/page.tsx +81 -0
  59. package/template/saas-starter/src/app/(auth)/login/email-login-form.tsx +109 -0
  60. package/template/saas-starter/src/app/(auth)/login/page.tsx +87 -0
  61. package/template/saas-starter/src/app/(auth)/login/social-login-buttons.tsx +75 -0
  62. package/template/saas-starter/src/app/(invitation)/accept-invitation/[id]/accept-invitation-form.tsx +88 -0
  63. package/template/saas-starter/src/app/(invitation)/accept-invitation/[id]/page.tsx +167 -0
  64. package/template/saas-starter/src/app/(marketing)/layout.tsx +14 -0
  65. package/template/saas-starter/src/app/(marketing)/page.tsx +3 -0
  66. package/template/saas-starter/src/app/(marketing)/privacy/page.tsx +3 -0
  67. package/template/saas-starter/src/app/(marketing)/terms/page.tsx +3 -0
  68. package/template/saas-starter/src/app/api/auth/[...all]/route.ts +4 -0
  69. package/template/saas-starter/src/app/api/webhooks/stripe/route.ts +94 -0
  70. package/template/saas-starter/src/app/favicon.ico +0 -0
  71. package/template/saas-starter/src/app/globals.css +240 -0
  72. package/template/saas-starter/src/app/layout.tsx +53 -0
  73. package/template/saas-starter/src/app/not-found.tsx +27 -0
  74. package/template/saas-starter/src/app/proxy.ts +28 -0
  75. package/template/saas-starter/src/app/robots.ts +32 -0
  76. package/template/saas-starter/src/app/sitemap.ts +20 -0
  77. package/template/saas-starter/src/components/dashboard-header.tsx +64 -0
  78. package/template/saas-starter/src/components/data-table/enum.ts +5 -0
  79. package/template/saas-starter/src/components/data-table/index.tsx +960 -0
  80. package/template/saas-starter/src/components/data-table/types.ts +75 -0
  81. package/template/saas-starter/src/components/error.tsx +26 -0
  82. package/template/saas-starter/src/components/file-upload.tsx +215 -0
  83. package/template/saas-starter/src/components/impersonation-banner.tsx +44 -0
  84. package/template/saas-starter/src/components/loader.tsx +25 -0
  85. package/template/saas-starter/src/components/navigation-search.tsx +140 -0
  86. package/template/saas-starter/src/components/navigation-sidebar.tsx +241 -0
  87. package/template/saas-starter/src/components/page-heading.tsx +32 -0
  88. package/template/saas-starter/src/components/react-query-provider.tsx +12 -0
  89. package/template/saas-starter/src/components/screen-size.tsx +40 -0
  90. package/template/saas-starter/src/components/site-footer.tsx +23 -0
  91. package/template/saas-starter/src/components/theme-provider.tsx +67 -0
  92. package/template/saas-starter/src/components/theme-toggle.tsx +22 -0
  93. package/template/saas-starter/src/components/ui/avatar.tsx +112 -0
  94. package/template/saas-starter/src/components/ui/badge.tsx +49 -0
  95. package/template/saas-starter/src/components/ui/button.tsx +67 -0
  96. package/template/saas-starter/src/components/ui/card.tsx +103 -0
  97. package/template/saas-starter/src/components/ui/checkbox.tsx +32 -0
  98. package/template/saas-starter/src/components/ui/collapsible.tsx +33 -0
  99. package/template/saas-starter/src/components/ui/command.tsx +192 -0
  100. package/template/saas-starter/src/components/ui/dialog.tsx +164 -0
  101. package/template/saas-starter/src/components/ui/dropdown-menu.tsx +273 -0
  102. package/template/saas-starter/src/components/ui/field.tsx +238 -0
  103. package/template/saas-starter/src/components/ui/input-group.tsx +156 -0
  104. package/template/saas-starter/src/components/ui/input.tsx +19 -0
  105. package/template/saas-starter/src/components/ui/label.tsx +24 -0
  106. package/template/saas-starter/src/components/ui/popover.tsx +89 -0
  107. package/template/saas-starter/src/components/ui/select.tsx +195 -0
  108. package/template/saas-starter/src/components/ui/separator.tsx +28 -0
  109. package/template/saas-starter/src/components/ui/sheet.tsx +143 -0
  110. package/template/saas-starter/src/components/ui/sidebar.tsx +702 -0
  111. package/template/saas-starter/src/components/ui/skeleton.tsx +13 -0
  112. package/template/saas-starter/src/components/ui/sonner.tsx +45 -0
  113. package/template/saas-starter/src/components/ui/switch.tsx +33 -0
  114. package/template/saas-starter/src/components/ui/table.tsx +116 -0
  115. package/template/saas-starter/src/components/ui/tabs.tsx +90 -0
  116. package/template/saas-starter/src/components/ui/textarea.tsx +18 -0
  117. package/template/saas-starter/src/components/ui/tooltip.tsx +57 -0
  118. package/template/saas-starter/src/components/user-menu.tsx +90 -0
  119. package/template/saas-starter/src/db/common.ts +31 -0
  120. package/template/saas-starter/src/db/enums.ts +26 -0
  121. package/template/saas-starter/src/db/index.ts +51 -0
  122. package/template/saas-starter/src/db/relations.ts +75 -0
  123. package/template/saas-starter/src/db/schema.ts +191 -0
  124. package/template/saas-starter/src/emails/components/email-layout.tsx +63 -0
  125. package/template/saas-starter/src/emails/invitation.tsx +56 -0
  126. package/template/saas-starter/src/emails/magic-link.tsx +49 -0
  127. package/template/saas-starter/src/emails/test.tsx +32 -0
  128. package/template/saas-starter/src/emails/welcome.tsx +34 -0
  129. package/template/saas-starter/src/env.ts +66 -0
  130. package/template/saas-starter/src/hooks/use-mobile.ts +19 -0
  131. package/template/saas-starter/src/instrumentation.ts +26 -0
  132. package/template/saas-starter/src/lib/actions.ts +21 -0
  133. package/template/saas-starter/src/lib/admin-navigation.ts +31 -0
  134. package/template/saas-starter/src/lib/app-navigation.ts +59 -0
  135. package/template/saas-starter/src/lib/auth-client.ts +29 -0
  136. package/template/saas-starter/src/lib/auth-permissions.ts +22 -0
  137. package/template/saas-starter/src/lib/auth.ts +211 -0
  138. package/template/saas-starter/src/lib/billing.ts +117 -0
  139. package/template/saas-starter/src/lib/cn.ts +4 -0
  140. package/template/saas-starter/src/lib/constants.ts +22 -0
  141. package/template/saas-starter/src/lib/delay.ts +2 -0
  142. package/template/saas-starter/src/lib/email-service.ts +89 -0
  143. package/template/saas-starter/src/lib/format-currency.ts +27 -0
  144. package/template/saas-starter/src/lib/format-date.ts +12 -0
  145. package/template/saas-starter/src/lib/nodemailer.ts +43 -0
  146. package/template/saas-starter/src/lib/organization-access.ts +93 -0
  147. package/template/saas-starter/src/lib/organization-plan-limits.ts +38 -0
  148. package/template/saas-starter/src/lib/otel.ts +27 -0
  149. package/template/saas-starter/src/lib/plans.ts +63 -0
  150. package/template/saas-starter/src/lib/safe-action-client.ts +75 -0
  151. package/template/saas-starter/src/lib/safe-action.ts +67 -0
  152. package/template/saas-starter/src/lib/siteConfig.ts +4 -0
  153. package/template/saas-starter/src/lib/storage.ts +181 -0
  154. package/template/saas-starter/src/lib/stripe.ts +6 -0
  155. package/template/saas-starter/src/lib/toast-message.ts +15 -0
  156. package/template/saas-starter/src/lib/validations.ts +12 -0
  157. package/template/saas-starter/src/scripts/reset-db.ts +22 -0
  158. package/template/saas-starter/src/scripts/seed.ts +11 -0
  159. package/template/saas-starter/src/scripts/setup-stripe-plans.ts +200 -0
  160. package/template/saas-starter/src/scripts/test-mail.ts +35 -0
  161. package/template/saas-starter/tsconfig.json +51 -0
@@ -0,0 +1,103 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '~/lib/cn'
4
+
5
+ function Card({
6
+ className,
7
+ size = 'default',
8
+ ...props
9
+ }: React.ComponentProps<'div'> & { size?: 'default' | 'sm' }) {
10
+ return (
11
+ <div
12
+ data-slot="card"
13
+ data-size={size}
14
+ className={cn(
15
+ 'group/card bg-card text-card-foreground ring-foreground/10 flex flex-col gap-(--card-spacing) overflow-hidden rounded-xl py-(--card-spacing) text-sm shadow-xs ring-1 [--card-spacing:--spacing(6)] has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl',
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ )
21
+ }
22
+
23
+ function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
24
+ return (
25
+ <div
26
+ data-slot="card-header"
27
+ className={cn(
28
+ 'group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)',
29
+ className
30
+ )}
31
+ {...props}
32
+ />
33
+ )
34
+ }
35
+
36
+ function CardTitle({ className, ...props }: React.ComponentProps<'div'>) {
37
+ return (
38
+ <div
39
+ data-slot="card-title"
40
+ className={cn(
41
+ 'font-heading text-base leading-normal font-medium group-data-[size=sm]/card:text-sm',
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ )
47
+ }
48
+
49
+ function CardDescription({ className, ...props }: React.ComponentProps<'div'>) {
50
+ return (
51
+ <div
52
+ data-slot="card-description"
53
+ className={cn('text-muted-foreground text-sm', className)}
54
+ {...props}
55
+ />
56
+ )
57
+ }
58
+
59
+ function CardAction({ className, ...props }: React.ComponentProps<'div'>) {
60
+ return (
61
+ <div
62
+ data-slot="card-action"
63
+ className={cn(
64
+ 'col-start-2 row-span-2 row-start-1 self-start justify-self-end',
65
+ className
66
+ )}
67
+ {...props}
68
+ />
69
+ )
70
+ }
71
+
72
+ function CardContent({ className, ...props }: React.ComponentProps<'div'>) {
73
+ return (
74
+ <div
75
+ data-slot="card-content"
76
+ className={cn('px-(--card-spacing)', className)}
77
+ {...props}
78
+ />
79
+ )
80
+ }
81
+
82
+ function CardFooter({ className, ...props }: React.ComponentProps<'div'>) {
83
+ return (
84
+ <div
85
+ data-slot="card-footer"
86
+ className={cn(
87
+ 'flex items-center rounded-b-xl px-(--card-spacing) [.border-t]:pt-(--card-spacing)',
88
+ className
89
+ )}
90
+ {...props}
91
+ />
92
+ )
93
+ }
94
+
95
+ export {
96
+ Card,
97
+ CardAction,
98
+ CardContent,
99
+ CardDescription,
100
+ CardFooter,
101
+ CardHeader,
102
+ CardTitle
103
+ }
@@ -0,0 +1,32 @@
1
+ 'use client'
2
+
3
+ import { Checkbox as CheckboxPrimitive } from 'radix-ui'
4
+ import * as React from 'react'
5
+
6
+ import { CheckIcon } from 'lucide-react'
7
+ import { cn } from '~/lib/cn'
8
+
9
+ function Checkbox({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
+ return (
14
+ <CheckboxPrimitive.Root
15
+ data-slot="checkbox"
16
+ className={cn(
17
+ 'peer border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive 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 relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border shadow-xs transition-shadow outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3',
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ <CheckboxPrimitive.Indicator
23
+ data-slot="checkbox-indicator"
24
+ className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
25
+ >
26
+ <CheckIcon />
27
+ </CheckboxPrimitive.Indicator>
28
+ </CheckboxPrimitive.Root>
29
+ )
30
+ }
31
+
32
+ export { Checkbox }
@@ -0,0 +1,33 @@
1
+ 'use client'
2
+
3
+ import { Collapsible as CollapsiblePrimitive } from 'radix-ui'
4
+
5
+ function Collapsible({
6
+ ...props
7
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
8
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />
9
+ }
10
+
11
+ function CollapsibleTrigger({
12
+ ...props
13
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
14
+ return (
15
+ <CollapsiblePrimitive.CollapsibleTrigger
16
+ data-slot="collapsible-trigger"
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ function CollapsibleContent({
23
+ ...props
24
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
25
+ return (
26
+ <CollapsiblePrimitive.CollapsibleContent
27
+ data-slot="collapsible-content"
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ export { Collapsible, CollapsibleContent, CollapsibleTrigger }
@@ -0,0 +1,192 @@
1
+ 'use client'
2
+
3
+ import { Command as CommandPrimitive } from 'cmdk'
4
+ import * as React from 'react'
5
+
6
+ import { CheckIcon, SearchIcon } from 'lucide-react'
7
+ import {
8
+ Dialog,
9
+ DialogContent,
10
+ DialogDescription,
11
+ DialogHeader,
12
+ DialogTitle
13
+ } from '~/components/ui/dialog'
14
+ import { InputGroup, InputGroupAddon } from '~/components/ui/input-group'
15
+ import { cn } from '~/lib/cn'
16
+
17
+ function Command({
18
+ className,
19
+ ...props
20
+ }: React.ComponentProps<typeof CommandPrimitive>) {
21
+ return (
22
+ <CommandPrimitive
23
+ data-slot="command"
24
+ className={cn(
25
+ 'bg-popover text-popover-foreground flex size-full flex-col overflow-hidden rounded-xl! p-1',
26
+ className
27
+ )}
28
+ {...props}
29
+ />
30
+ )
31
+ }
32
+
33
+ function CommandDialog({
34
+ title = 'Command Palette',
35
+ description = 'Search for a command to run...',
36
+ children,
37
+ className,
38
+ showCloseButton = false,
39
+ ...props
40
+ }: React.ComponentProps<typeof Dialog> & {
41
+ title?: string
42
+ description?: string
43
+ className?: string
44
+ showCloseButton?: boolean
45
+ }) {
46
+ return (
47
+ <Dialog {...props}>
48
+ <DialogHeader className="sr-only">
49
+ <DialogTitle>{title}</DialogTitle>
50
+ <DialogDescription>{description}</DialogDescription>
51
+ </DialogHeader>
52
+ <DialogContent
53
+ className={cn(
54
+ 'top-1/3 translate-y-0 overflow-hidden rounded-xl! p-0',
55
+ className
56
+ )}
57
+ showCloseButton={showCloseButton}
58
+ >
59
+ {children}
60
+ </DialogContent>
61
+ </Dialog>
62
+ )
63
+ }
64
+
65
+ function CommandInput({
66
+ className,
67
+ ...props
68
+ }: React.ComponentProps<typeof CommandPrimitive.Input>) {
69
+ return (
70
+ <div data-slot="command-input-wrapper" className="p-1 pb-0">
71
+ <InputGroup className="border-input/30 bg-input/30 h-8! rounded-lg! shadow-none! *:data-[slot=input-group-addon]:pl-2!">
72
+ <CommandPrimitive.Input
73
+ data-slot="command-input"
74
+ className={cn(
75
+ 'w-full text-sm outline-hidden disabled:cursor-not-allowed disabled:opacity-50',
76
+ className
77
+ )}
78
+ {...props}
79
+ />
80
+ <InputGroupAddon>
81
+ <SearchIcon className="size-4 shrink-0 opacity-50" />
82
+ </InputGroupAddon>
83
+ </InputGroup>
84
+ </div>
85
+ )
86
+ }
87
+
88
+ function CommandList({
89
+ className,
90
+ ...props
91
+ }: React.ComponentProps<typeof CommandPrimitive.List>) {
92
+ return (
93
+ <CommandPrimitive.List
94
+ data-slot="command-list"
95
+ className={cn(
96
+ 'no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none',
97
+ className
98
+ )}
99
+ {...props}
100
+ />
101
+ )
102
+ }
103
+
104
+ function CommandEmpty({
105
+ className,
106
+ ...props
107
+ }: React.ComponentProps<typeof CommandPrimitive.Empty>) {
108
+ return (
109
+ <CommandPrimitive.Empty
110
+ data-slot="command-empty"
111
+ className={cn('py-6 text-center text-sm', className)}
112
+ {...props}
113
+ />
114
+ )
115
+ }
116
+
117
+ function CommandGroup({
118
+ className,
119
+ ...props
120
+ }: React.ComponentProps<typeof CommandPrimitive.Group>) {
121
+ return (
122
+ <CommandPrimitive.Group
123
+ data-slot="command-group"
124
+ className={cn(
125
+ 'text-foreground **:[[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 **:[[cmdk-group-heading]]:px-2 **:[[cmdk-group-heading]]:py-1.5 **:[[cmdk-group-heading]]:text-xs **:[[cmdk-group-heading]]:font-medium',
126
+ className
127
+ )}
128
+ {...props}
129
+ />
130
+ )
131
+ }
132
+
133
+ function CommandSeparator({
134
+ className,
135
+ ...props
136
+ }: React.ComponentProps<typeof CommandPrimitive.Separator>) {
137
+ return (
138
+ <CommandPrimitive.Separator
139
+ data-slot="command-separator"
140
+ className={cn('bg-border -mx-1 h-px w-auto', className)}
141
+ {...props}
142
+ />
143
+ )
144
+ }
145
+
146
+ function CommandItem({
147
+ className,
148
+ children,
149
+ ...props
150
+ }: React.ComponentProps<typeof CommandPrimitive.Item>) {
151
+ return (
152
+ <CommandPrimitive.Item
153
+ data-slot="command-item"
154
+ className={cn(
155
+ "group/command-item data-selected:bg-muted data-selected:text-foreground data-selected:**:[svg]:text-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none in-data-[slot=dialog-content]:rounded-lg! data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
156
+ className
157
+ )}
158
+ {...props}
159
+ >
160
+ {children}
161
+ <CheckIcon className="ml-auto opacity-0 group-has-data-[slot=command-shortcut]/command-item:hidden group-data-[checked=true]/command-item:opacity-100" />
162
+ </CommandPrimitive.Item>
163
+ )
164
+ }
165
+
166
+ function CommandShortcut({
167
+ className,
168
+ ...props
169
+ }: React.ComponentProps<'span'>) {
170
+ return (
171
+ <span
172
+ data-slot="command-shortcut"
173
+ className={cn(
174
+ 'text-muted-foreground group-data-selected/command-item:text-foreground ml-auto text-xs tracking-widest',
175
+ className
176
+ )}
177
+ {...props}
178
+ />
179
+ )
180
+ }
181
+
182
+ export {
183
+ Command,
184
+ CommandDialog,
185
+ CommandEmpty,
186
+ CommandGroup,
187
+ CommandInput,
188
+ CommandItem,
189
+ CommandList,
190
+ CommandSeparator,
191
+ CommandShortcut
192
+ }
@@ -0,0 +1,164 @@
1
+ 'use client'
2
+
3
+ import { Dialog as DialogPrimitive } from 'radix-ui'
4
+ import * as React from 'react'
5
+
6
+ import { XIcon } from 'lucide-react'
7
+ import { Button } from '~/components/ui/button'
8
+ import { cn } from '~/lib/cn'
9
+
10
+ function Dialog({
11
+ ...props
12
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
13
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
14
+ }
15
+
16
+ function DialogTrigger({
17
+ ...props
18
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
19
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
20
+ }
21
+
22
+ function DialogPortal({
23
+ ...props
24
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
25
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />
26
+ }
27
+
28
+ function DialogClose({
29
+ ...props
30
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
31
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
32
+ }
33
+
34
+ function DialogOverlay({
35
+ className,
36
+ ...props
37
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
38
+ return (
39
+ <DialogPrimitive.Overlay
40
+ data-slot="dialog-overlay"
41
+ className={cn(
42
+ 'data-open:animate-in data-open:fade-in-0 data-closed:animate-out data-closed:fade-out-0 fixed inset-0 isolate z-50 bg-black/10 duration-100 supports-backdrop-filter:backdrop-blur-xs',
43
+ className
44
+ )}
45
+ {...props}
46
+ />
47
+ )
48
+ }
49
+
50
+ function DialogContent({
51
+ className,
52
+ children,
53
+ showCloseButton = true,
54
+ ...props
55
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
56
+ showCloseButton?: boolean
57
+ }) {
58
+ return (
59
+ <DialogPortal>
60
+ <DialogOverlay />
61
+ <DialogPrimitive.Content
62
+ data-slot="dialog-content"
63
+ className={cn(
64
+ 'bg-popover text-popover-foreground ring-foreground/10 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-6 rounded-xl p-6 text-sm ring-1 duration-100 outline-none sm:max-w-md',
65
+ className
66
+ )}
67
+ {...props}
68
+ >
69
+ {children}
70
+ {showCloseButton && (
71
+ <DialogPrimitive.Close data-slot="dialog-close" asChild>
72
+ <Button
73
+ variant="ghost"
74
+ className="absolute top-4 right-4"
75
+ size="icon-sm"
76
+ >
77
+ <XIcon />
78
+ <span className="sr-only">Close</span>
79
+ </Button>
80
+ </DialogPrimitive.Close>
81
+ )}
82
+ </DialogPrimitive.Content>
83
+ </DialogPortal>
84
+ )
85
+ }
86
+
87
+ function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
88
+ return (
89
+ <div
90
+ data-slot="dialog-header"
91
+ className={cn('flex flex-col gap-2', className)}
92
+ {...props}
93
+ />
94
+ )
95
+ }
96
+
97
+ function DialogFooter({
98
+ className,
99
+ showCloseButton = false,
100
+ children,
101
+ ...props
102
+ }: React.ComponentProps<'div'> & {
103
+ showCloseButton?: boolean
104
+ }) {
105
+ return (
106
+ <div
107
+ data-slot="dialog-footer"
108
+ className={cn(
109
+ 'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
110
+ className
111
+ )}
112
+ {...props}
113
+ >
114
+ {children}
115
+ {showCloseButton && (
116
+ <DialogPrimitive.Close asChild>
117
+ <Button variant="outline">Close</Button>
118
+ </DialogPrimitive.Close>
119
+ )}
120
+ </div>
121
+ )
122
+ }
123
+
124
+ function DialogTitle({
125
+ className,
126
+ ...props
127
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
128
+ return (
129
+ <DialogPrimitive.Title
130
+ data-slot="dialog-title"
131
+ className={cn('font-heading leading-none font-medium', className)}
132
+ {...props}
133
+ />
134
+ )
135
+ }
136
+
137
+ function DialogDescription({
138
+ className,
139
+ ...props
140
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
141
+ return (
142
+ <DialogPrimitive.Description
143
+ data-slot="dialog-description"
144
+ className={cn(
145
+ 'text-muted-foreground *:[a]:hover:text-foreground text-sm *:[a]:underline *:[a]:underline-offset-3',
146
+ className
147
+ )}
148
+ {...props}
149
+ />
150
+ )
151
+ }
152
+
153
+ export {
154
+ Dialog,
155
+ DialogClose,
156
+ DialogContent,
157
+ DialogDescription,
158
+ DialogFooter,
159
+ DialogHeader,
160
+ DialogOverlay,
161
+ DialogPortal,
162
+ DialogTitle,
163
+ DialogTrigger
164
+ }