doo-boilerplate 0.1.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 (156) hide show
  1. package/dist/index.js +382 -0
  2. package/package.json +31 -0
  3. package/templates/template-nextjs/Dockerfile +29 -0
  4. package/templates/template-nextjs/README.md +215 -0
  5. package/templates/template-nextjs/_env.example +7 -0
  6. package/templates/template-nextjs/_gitignore +8 -0
  7. package/templates/template-nextjs/_prettierignore +4 -0
  8. package/templates/template-nextjs/_prettierrc +12 -0
  9. package/templates/template-nextjs/components.json +19 -0
  10. package/templates/template-nextjs/docker-compose.yml +12 -0
  11. package/templates/template-nextjs/docs/swagger/api.json +77 -0
  12. package/templates/template-nextjs/eslint.config.ts +25 -0
  13. package/templates/template-nextjs/generate/.gitkeep +0 -0
  14. package/templates/template-nextjs/knip.config.ts +8 -0
  15. package/templates/template-nextjs/messages/en.json +14 -0
  16. package/templates/template-nextjs/messages/vi.json +14 -0
  17. package/templates/template-nextjs/next.config.ts +13 -0
  18. package/templates/template-nextjs/optional/charts/deps.json +7 -0
  19. package/templates/template-nextjs/optional/dark-mode/deps.json +5 -0
  20. package/templates/template-nextjs/optional/dark-mode/files/providers/theme-provider.tsx +17 -0
  21. package/templates/template-nextjs/optional/dnd/deps.json +8 -0
  22. package/templates/template-nextjs/optional/editor/deps.json +10 -0
  23. package/templates/template-nextjs/optional/i18n/deps.json +5 -0
  24. package/templates/template-nextjs/optional/sentry/deps.json +5 -0
  25. package/templates/template-nextjs/package.json +82 -0
  26. package/templates/template-nextjs/postcss.config.js +1 -0
  27. package/templates/template-nextjs/public/images/.gitkeep +0 -0
  28. package/templates/template-nextjs/scripts/build-and-scan.sh +13 -0
  29. package/templates/template-nextjs/scripts/trivy-scan.sh +24 -0
  30. package/templates/template-nextjs/src/app/(auth)/layout.tsx +10 -0
  31. package/templates/template-nextjs/src/app/(auth)/sign-in/page.tsx +9 -0
  32. package/templates/template-nextjs/src/app/(dashboard)/layout.tsx +17 -0
  33. package/templates/template-nextjs/src/app/(dashboard)/page.tsx +27 -0
  34. package/templates/template-nextjs/src/app/(dashboard)/profile/page.tsx +39 -0
  35. package/templates/template-nextjs/src/app/(dashboard)/settings/page.tsx +15 -0
  36. package/templates/template-nextjs/src/app/api/health/route.ts +3 -0
  37. package/templates/template-nextjs/src/app/layout.tsx +22 -0
  38. package/templates/template-nextjs/src/app/not-found.tsx +18 -0
  39. package/templates/template-nextjs/src/app/page.tsx +5 -0
  40. package/templates/template-nextjs/src/components/common/error-boundary.tsx +56 -0
  41. package/templates/template-nextjs/src/components/common/loading-spinner.tsx +28 -0
  42. package/templates/template-nextjs/src/components/common/theme-toggle.tsx +21 -0
  43. package/templates/template-nextjs/src/components/layout/header.tsx +91 -0
  44. package/templates/template-nextjs/src/components/layout/page-layout.tsx +23 -0
  45. package/templates/template-nextjs/src/components/layout/sidebar.tsx +126 -0
  46. package/templates/template-nextjs/src/components/ui/avatar.tsx +45 -0
  47. package/templates/template-nextjs/src/components/ui/badge.tsx +31 -0
  48. package/templates/template-nextjs/src/components/ui/button.tsx +44 -0
  49. package/templates/template-nextjs/src/components/ui/card.tsx +55 -0
  50. package/templates/template-nextjs/src/components/ui/checkbox.tsx +26 -0
  51. package/templates/template-nextjs/src/components/ui/dialog.tsx +99 -0
  52. package/templates/template-nextjs/src/components/ui/dropdown-menu.tsx +180 -0
  53. package/templates/template-nextjs/src/components/ui/form.tsx +158 -0
  54. package/templates/template-nextjs/src/components/ui/input.tsx +24 -0
  55. package/templates/template-nextjs/src/components/ui/label.tsx +19 -0
  56. package/templates/template-nextjs/src/components/ui/scroll-area.tsx +40 -0
  57. package/templates/template-nextjs/src/components/ui/select.tsx +148 -0
  58. package/templates/template-nextjs/src/components/ui/separator.tsx +24 -0
  59. package/templates/template-nextjs/src/components/ui/sheet.tsx +96 -0
  60. package/templates/template-nextjs/src/components/ui/skeleton.tsx +7 -0
  61. package/templates/template-nextjs/src/components/ui/switch.tsx +27 -0
  62. package/templates/template-nextjs/src/components/ui/tabs.tsx +53 -0
  63. package/templates/template-nextjs/src/components/ui/tooltip.tsx +28 -0
  64. package/templates/template-nextjs/src/config/site.ts +5 -0
  65. package/templates/template-nextjs/src/features/auth/components/sign-in-form.tsx +93 -0
  66. package/templates/template-nextjs/src/features/auth/hooks/use-auth.ts +47 -0
  67. package/templates/template-nextjs/src/features/auth/schemas/auth-schema.ts +21 -0
  68. package/templates/template-nextjs/src/features/auth/services/auth-api.ts +30 -0
  69. package/templates/template-nextjs/src/hooks/use-media-query.ts +15 -0
  70. package/templates/template-nextjs/src/i18n/config.ts +3 -0
  71. package/templates/template-nextjs/src/lib/api-client.ts +43 -0
  72. package/templates/template-nextjs/src/lib/query-client.ts +17 -0
  73. package/templates/template-nextjs/src/lib/utils.ts +19 -0
  74. package/templates/template-nextjs/src/middleware.ts +23 -0
  75. package/templates/template-nextjs/src/providers/app-providers.tsx +18 -0
  76. package/templates/template-nextjs/src/providers/query-provider.tsx +16 -0
  77. package/templates/template-nextjs/src/providers/theme-provider.tsx +17 -0
  78. package/templates/template-nextjs/src/stores/auth-store.ts +82 -0
  79. package/templates/template-nextjs/src/styles/globals.css +65 -0
  80. package/templates/template-nextjs/src/types/index.ts +13 -0
  81. package/templates/template-nextjs/tsconfig.json +23 -0
  82. package/templates/template-vite/Dockerfile +20 -0
  83. package/templates/template-vite/README.md +241 -0
  84. package/templates/template-vite/_env.example +8 -0
  85. package/templates/template-vite/_gitignore +7 -0
  86. package/templates/template-vite/_prettierignore +4 -0
  87. package/templates/template-vite/_prettierrc +13 -0
  88. package/templates/template-vite/components.json +19 -0
  89. package/templates/template-vite/docker-compose.yml +11 -0
  90. package/templates/template-vite/docs/swagger/api.json +77 -0
  91. package/templates/template-vite/eslint.config.ts +30 -0
  92. package/templates/template-vite/generate/.gitkeep +0 -0
  93. package/templates/template-vite/index.html +13 -0
  94. package/templates/template-vite/knip.config.ts +8 -0
  95. package/templates/template-vite/nginx.conf +37 -0
  96. package/templates/template-vite/optional/charts/deps.json +7 -0
  97. package/templates/template-vite/optional/dark-mode/deps.json +5 -0
  98. package/templates/template-vite/optional/dnd/deps.json +8 -0
  99. package/templates/template-vite/optional/editor/deps.json +10 -0
  100. package/templates/template-vite/optional/i18n/deps.json +7 -0
  101. package/templates/template-vite/optional/sentry/deps.json +6 -0
  102. package/templates/template-vite/package.json +91 -0
  103. package/templates/template-vite/public/favicon.svg +5 -0
  104. package/templates/template-vite/scripts/build-and-scan.sh +13 -0
  105. package/templates/template-vite/scripts/trivy-scan.sh +24 -0
  106. package/templates/template-vite/src/components/common/error-boundary.tsx +51 -0
  107. package/templates/template-vite/src/components/common/loading-spinner.tsx +38 -0
  108. package/templates/template-vite/src/components/common/theme-toggle.tsx +19 -0
  109. package/templates/template-vite/src/components/layout/header.tsx +58 -0
  110. package/templates/template-vite/src/components/layout/page-layout.tsx +31 -0
  111. package/templates/template-vite/src/components/layout/sidebar.tsx +74 -0
  112. package/templates/template-vite/src/components/ui/avatar.tsx +45 -0
  113. package/templates/template-vite/src/components/ui/badge.tsx +31 -0
  114. package/templates/template-vite/src/components/ui/button.tsx +49 -0
  115. package/templates/template-vite/src/components/ui/card.tsx +56 -0
  116. package/templates/template-vite/src/components/ui/checkbox.tsx +26 -0
  117. package/templates/template-vite/src/components/ui/dialog.tsx +99 -0
  118. package/templates/template-vite/src/components/ui/dropdown-menu.tsx +174 -0
  119. package/templates/template-vite/src/components/ui/form.tsx +161 -0
  120. package/templates/template-vite/src/components/ui/input.tsx +24 -0
  121. package/templates/template-vite/src/components/ui/label.tsx +19 -0
  122. package/templates/template-vite/src/components/ui/scroll-area.tsx +44 -0
  123. package/templates/template-vite/src/components/ui/select.tsx +148 -0
  124. package/templates/template-vite/src/components/ui/separator.tsx +24 -0
  125. package/templates/template-vite/src/components/ui/sheet.tsx +118 -0
  126. package/templates/template-vite/src/components/ui/skeleton.tsx +7 -0
  127. package/templates/template-vite/src/components/ui/switch.tsx +27 -0
  128. package/templates/template-vite/src/components/ui/tabs.tsx +53 -0
  129. package/templates/template-vite/src/components/ui/tooltip.tsx +26 -0
  130. package/templates/template-vite/src/config/site.ts +5 -0
  131. package/templates/template-vite/src/context/theme-provider.tsx +10 -0
  132. package/templates/template-vite/src/features/auth/components/sign-in-form.tsx +86 -0
  133. package/templates/template-vite/src/features/auth/hooks/use-auth.ts +46 -0
  134. package/templates/template-vite/src/features/auth/schemas/auth-schema.ts +8 -0
  135. package/templates/template-vite/src/features/auth/services/auth-api.ts +24 -0
  136. package/templates/template-vite/src/hooks/use-media-query.ts +26 -0
  137. package/templates/template-vite/src/lib/api-client.ts +38 -0
  138. package/templates/template-vite/src/lib/i18n.ts +34 -0
  139. package/templates/template-vite/src/lib/query-client.ts +14 -0
  140. package/templates/template-vite/src/lib/utils.ts +28 -0
  141. package/templates/template-vite/src/main.tsx +37 -0
  142. package/templates/template-vite/src/routeTree.gen.ts +6 -0
  143. package/templates/template-vite/src/routes/(auth)/sign-in.tsx +17 -0
  144. package/templates/template-vite/src/routes/(errors)/404.tsx +19 -0
  145. package/templates/template-vite/src/routes/__root.tsx +17 -0
  146. package/templates/template-vite/src/routes/_authenticated/dashboard.tsx +22 -0
  147. package/templates/template-vite/src/routes/_authenticated/profile.tsx +47 -0
  148. package/templates/template-vite/src/routes/_authenticated/settings.tsx +17 -0
  149. package/templates/template-vite/src/routes/_authenticated.tsx +32 -0
  150. package/templates/template-vite/src/stores/auth-store.ts +56 -0
  151. package/templates/template-vite/src/styles/globals.css +81 -0
  152. package/templates/template-vite/src/types/index.ts +39 -0
  153. package/templates/template-vite/tsconfig.app.json +24 -0
  154. package/templates/template-vite/tsconfig.json +7 -0
  155. package/templates/template-vite/tsconfig.node.json +16 -0
  156. package/templates/template-vite/vite.config.ts +36 -0
@@ -0,0 +1,174 @@
1
+ import * as React from 'react'
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
3
+ import { Check, ChevronRight, Circle } from 'lucide-react'
4
+
5
+ import { cn } from '@/lib/utils'
6
+
7
+ const DropdownMenu = DropdownMenuPrimitive.Root
8
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
9
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
10
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
11
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
12
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
13
+
14
+ const DropdownMenuSubTrigger = React.forwardRef<
15
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
16
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }
17
+ >(({ className, inset, children, ...props }, ref) => (
18
+ <DropdownMenuPrimitive.SubTrigger
19
+ ref={ref}
20
+ className={cn(
21
+ 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent',
22
+ inset && 'pl-8',
23
+ className
24
+ )}
25
+ {...props}
26
+ >
27
+ {children}
28
+ <ChevronRight className='ml-auto h-4 w-4' />
29
+ </DropdownMenuPrimitive.SubTrigger>
30
+ ))
31
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName
32
+
33
+ const DropdownMenuSubContent = React.forwardRef<
34
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
35
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
36
+ >(({ className, ...props }, ref) => (
37
+ <DropdownMenuPrimitive.SubContent
38
+ ref={ref}
39
+ className={cn(
40
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
41
+ className
42
+ )}
43
+ {...props}
44
+ />
45
+ ))
46
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName
47
+
48
+ const DropdownMenuContent = React.forwardRef<
49
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
50
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
51
+ >(({ className, sideOffset = 4, ...props }, ref) => (
52
+ <DropdownMenuPrimitive.Portal>
53
+ <DropdownMenuPrimitive.Content
54
+ ref={ref}
55
+ sideOffset={sideOffset}
56
+ className={cn(
57
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
58
+ className
59
+ )}
60
+ {...props}
61
+ />
62
+ </DropdownMenuPrimitive.Portal>
63
+ ))
64
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
65
+
66
+ const DropdownMenuItem = React.forwardRef<
67
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
68
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }
69
+ >(({ className, inset, ...props }, ref) => (
70
+ <DropdownMenuPrimitive.Item
71
+ ref={ref}
72
+ className={cn(
73
+ 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
74
+ inset && 'pl-8',
75
+ className
76
+ )}
77
+ {...props}
78
+ />
79
+ ))
80
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
81
+
82
+ const DropdownMenuCheckboxItem = React.forwardRef<
83
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
84
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
85
+ >(({ className, children, checked, ...props }, ref) => (
86
+ <DropdownMenuPrimitive.CheckboxItem
87
+ ref={ref}
88
+ className={cn(
89
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
90
+ className
91
+ )}
92
+ checked={checked}
93
+ {...props}
94
+ >
95
+ <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
96
+ <DropdownMenuPrimitive.ItemIndicator>
97
+ <Check className='h-4 w-4' />
98
+ </DropdownMenuPrimitive.ItemIndicator>
99
+ </span>
100
+ {children}
101
+ </DropdownMenuPrimitive.CheckboxItem>
102
+ ))
103
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName
104
+
105
+ const DropdownMenuRadioItem = React.forwardRef<
106
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
107
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
108
+ >(({ className, children, ...props }, ref) => (
109
+ <DropdownMenuPrimitive.RadioItem
110
+ ref={ref}
111
+ className={cn(
112
+ 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
113
+ className
114
+ )}
115
+ {...props}
116
+ >
117
+ <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
118
+ <DropdownMenuPrimitive.ItemIndicator>
119
+ <Circle className='h-2 w-2 fill-current' />
120
+ </DropdownMenuPrimitive.ItemIndicator>
121
+ </span>
122
+ {children}
123
+ </DropdownMenuPrimitive.RadioItem>
124
+ ))
125
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
126
+
127
+ const DropdownMenuLabel = React.forwardRef<
128
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
129
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }
130
+ >(({ className, inset, ...props }, ref) => (
131
+ <DropdownMenuPrimitive.Label
132
+ ref={ref}
133
+ className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
134
+ {...props}
135
+ />
136
+ ))
137
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
138
+
139
+ const DropdownMenuSeparator = React.forwardRef<
140
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
141
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
142
+ >(({ className, ...props }, ref) => (
143
+ <DropdownMenuPrimitive.Separator
144
+ ref={ref}
145
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
146
+ {...props}
147
+ />
148
+ ))
149
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
150
+
151
+ const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
152
+ return (
153
+ <span className={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...props} />
154
+ )
155
+ }
156
+ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
157
+
158
+ export {
159
+ DropdownMenu,
160
+ DropdownMenuTrigger,
161
+ DropdownMenuContent,
162
+ DropdownMenuItem,
163
+ DropdownMenuCheckboxItem,
164
+ DropdownMenuRadioItem,
165
+ DropdownMenuLabel,
166
+ DropdownMenuSeparator,
167
+ DropdownMenuShortcut,
168
+ DropdownMenuGroup,
169
+ DropdownMenuPortal,
170
+ DropdownMenuSub,
171
+ DropdownMenuSubContent,
172
+ DropdownMenuSubTrigger,
173
+ DropdownMenuRadioGroup,
174
+ }
@@ -0,0 +1,161 @@
1
+ import * as React from 'react'
2
+ import * as LabelPrimitive from '@radix-ui/react-label'
3
+ import { Slot } from '@radix-ui/react-slot'
4
+ import {
5
+ Controller,
6
+ FormProvider,
7
+ useFormContext,
8
+ type ControllerProps,
9
+ type FieldPath,
10
+ type FieldValues,
11
+ } from 'react-hook-form'
12
+
13
+ import { cn } from '@/lib/utils'
14
+ import { Label } from '@/components/ui/label'
15
+
16
+ const Form = FormProvider
17
+
18
+ type FormFieldContextValue<
19
+ TFieldValues extends FieldValues = FieldValues,
20
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
21
+ > = { name: TName }
22
+
23
+ const FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue)
24
+
25
+ const FormField = <
26
+ TFieldValues extends FieldValues = FieldValues,
27
+ TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,
28
+ >({
29
+ ...props
30
+ }: ControllerProps<TFieldValues, TName>) => {
31
+ return (
32
+ <FormFieldContext.Provider value={{ name: props.name }}>
33
+ <Controller {...props} />
34
+ </FormFieldContext.Provider>
35
+ )
36
+ }
37
+
38
+ const useFormField = () => {
39
+ const fieldContext = React.useContext(FormFieldContext)
40
+ const itemContext = React.useContext(FormItemContext)
41
+ const { getFieldState, formState } = useFormContext()
42
+
43
+ const fieldState = getFieldState(fieldContext.name, formState)
44
+
45
+ if (!fieldContext) {
46
+ throw new Error('useFormField should be used within <FormField>')
47
+ }
48
+
49
+ const { id } = itemContext
50
+
51
+ return {
52
+ id,
53
+ name: fieldContext.name,
54
+ formItemId: `${id}-form-item`,
55
+ formDescriptionId: `${id}-form-item-description`,
56
+ formMessageId: `${id}-form-item-message`,
57
+ ...fieldState,
58
+ }
59
+ }
60
+
61
+ type FormItemContextValue = { id: string }
62
+
63
+ const FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue)
64
+
65
+ const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
66
+ ({ className, ...props }, ref) => {
67
+ const id = React.useId()
68
+
69
+ return (
70
+ <FormItemContext.Provider value={{ id }}>
71
+ <div ref={ref} className={cn('space-y-2', className)} {...props} />
72
+ </FormItemContext.Provider>
73
+ )
74
+ }
75
+ )
76
+ FormItem.displayName = 'FormItem'
77
+
78
+ const FormLabel = React.forwardRef<
79
+ React.ElementRef<typeof LabelPrimitive.Root>,
80
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root>
81
+ >(({ className, ...props }, ref) => {
82
+ const { error, formItemId } = useFormField()
83
+
84
+ return (
85
+ <Label
86
+ ref={ref}
87
+ className={cn(error && 'text-destructive', className)}
88
+ htmlFor={formItemId}
89
+ {...props}
90
+ />
91
+ )
92
+ })
93
+ FormLabel.displayName = 'FormLabel'
94
+
95
+ const FormControl = React.forwardRef<
96
+ React.ElementRef<typeof Slot>,
97
+ React.ComponentPropsWithoutRef<typeof Slot>
98
+ >(({ ...props }, ref) => {
99
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField()
100
+
101
+ return (
102
+ <Slot
103
+ ref={ref}
104
+ id={formItemId}
105
+ aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
106
+ aria-invalid={!!error}
107
+ {...props}
108
+ />
109
+ )
110
+ })
111
+ FormControl.displayName = 'FormControl'
112
+
113
+ const FormDescription = React.forwardRef<
114
+ HTMLParagraphElement,
115
+ React.HTMLAttributes<HTMLParagraphElement>
116
+ >(({ className, ...props }, ref) => {
117
+ const { formDescriptionId } = useFormField()
118
+
119
+ return (
120
+ <p
121
+ ref={ref}
122
+ id={formDescriptionId}
123
+ className={cn('text-sm text-muted-foreground', className)}
124
+ {...props}
125
+ />
126
+ )
127
+ })
128
+ FormDescription.displayName = 'FormDescription'
129
+
130
+ const FormMessage = React.forwardRef<
131
+ HTMLParagraphElement,
132
+ React.HTMLAttributes<HTMLParagraphElement>
133
+ >(({ className, children, ...props }, ref) => {
134
+ const { error, formMessageId } = useFormField()
135
+ const body = error ? String(error?.message) : children
136
+
137
+ if (!body) return null
138
+
139
+ return (
140
+ <p
141
+ ref={ref}
142
+ id={formMessageId}
143
+ className={cn('text-sm font-medium text-destructive', className)}
144
+ {...props}
145
+ >
146
+ {body}
147
+ </p>
148
+ )
149
+ })
150
+ FormMessage.displayName = 'FormMessage'
151
+
152
+ export {
153
+ useFormField,
154
+ Form,
155
+ FormItem,
156
+ FormLabel,
157
+ FormControl,
158
+ FormDescription,
159
+ FormMessage,
160
+ FormField,
161
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from 'react'
2
+
3
+ import { cn } from '@/lib/utils'
4
+
5
+ export type InputProps = React.InputHTMLAttributes<HTMLInputElement>
6
+
7
+ const Input = React.forwardRef<HTMLInputElement, InputProps>(
8
+ ({ className, type, ...props }, ref) => {
9
+ return (
10
+ <input
11
+ type={type}
12
+ className={cn(
13
+ 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
14
+ className
15
+ )}
16
+ ref={ref}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+ )
22
+ Input.displayName = 'Input'
23
+
24
+ export { Input }
@@ -0,0 +1,19 @@
1
+ import * as React from 'react'
2
+ import * as LabelPrimitive from '@radix-ui/react-label'
3
+ import { cva, type VariantProps } from 'class-variance-authority'
4
+
5
+ import { cn } from '@/lib/utils'
6
+
7
+ const labelVariants = cva(
8
+ 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
9
+ )
10
+
11
+ const Label = React.forwardRef<
12
+ React.ElementRef<typeof LabelPrimitive.Root>,
13
+ React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & VariantProps<typeof labelVariants>
14
+ >(({ className, ...props }, ref) => (
15
+ <LabelPrimitive.Root ref={ref} className={cn(labelVariants(), className)} {...props} />
16
+ ))
17
+ Label.displayName = LabelPrimitive.Root.displayName
18
+
19
+ export { Label }
@@ -0,0 +1,44 @@
1
+ import * as React from 'react'
2
+ import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
3
+
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const ScrollArea = React.forwardRef<
7
+ React.ElementRef<typeof ScrollAreaPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
9
+ >(({ className, children, ...props }, ref) => (
10
+ <ScrollAreaPrimitive.Root
11
+ ref={ref}
12
+ className={cn('relative overflow-hidden', className)}
13
+ {...props}
14
+ >
15
+ <ScrollAreaPrimitive.Viewport className='h-full w-full rounded-[inherit]'>
16
+ {children}
17
+ </ScrollAreaPrimitive.Viewport>
18
+ <ScrollBar />
19
+ <ScrollAreaPrimitive.Corner />
20
+ </ScrollAreaPrimitive.Root>
21
+ ))
22
+ ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
23
+
24
+ const ScrollBar = React.forwardRef<
25
+ React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
26
+ React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
27
+ >(({ className, orientation = 'vertical', ...props }, ref) => (
28
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
29
+ ref={ref}
30
+ orientation={orientation}
31
+ className={cn(
32
+ 'flex touch-none select-none transition-colors',
33
+ orientation === 'vertical' && 'h-full w-2.5 border-l border-l-transparent p-[1px]',
34
+ orientation === 'horizontal' && 'h-2.5 flex-col border-t border-t-transparent p-[1px]',
35
+ className
36
+ )}
37
+ {...props}
38
+ >
39
+ <ScrollAreaPrimitive.ScrollAreaThumb className='relative flex-1 rounded-full bg-border' />
40
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
41
+ ))
42
+ ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
43
+
44
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,148 @@
1
+ import * as React from 'react'
2
+ import * as SelectPrimitive from '@radix-ui/react-select'
3
+ import { Check, ChevronDown, ChevronUp } from 'lucide-react'
4
+
5
+ import { cn } from '@/lib/utils'
6
+
7
+ const Select = SelectPrimitive.Root
8
+ const SelectGroup = SelectPrimitive.Group
9
+ const SelectValue = SelectPrimitive.Value
10
+
11
+ const SelectTrigger = React.forwardRef<
12
+ React.ElementRef<typeof SelectPrimitive.Trigger>,
13
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
14
+ >(({ className, children, ...props }, ref) => (
15
+ <SelectPrimitive.Trigger
16
+ ref={ref}
17
+ className={cn(
18
+ 'flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
19
+ className
20
+ )}
21
+ {...props}
22
+ >
23
+ {children}
24
+ <SelectPrimitive.Icon asChild>
25
+ <ChevronDown className='h-4 w-4 opacity-50' />
26
+ </SelectPrimitive.Icon>
27
+ </SelectPrimitive.Trigger>
28
+ ))
29
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
30
+
31
+ const SelectScrollUpButton = React.forwardRef<
32
+ React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
33
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
34
+ >(({ className, ...props }, ref) => (
35
+ <SelectPrimitive.ScrollUpButton
36
+ ref={ref}
37
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
38
+ {...props}
39
+ >
40
+ <ChevronUp className='h-4 w-4' />
41
+ </SelectPrimitive.ScrollUpButton>
42
+ ))
43
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
44
+
45
+ const SelectScrollDownButton = React.forwardRef<
46
+ React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
47
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
48
+ >(({ className, ...props }, ref) => (
49
+ <SelectPrimitive.ScrollDownButton
50
+ ref={ref}
51
+ className={cn('flex cursor-default items-center justify-center py-1', className)}
52
+ {...props}
53
+ >
54
+ <ChevronDown className='h-4 w-4' />
55
+ </SelectPrimitive.ScrollDownButton>
56
+ ))
57
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName
58
+
59
+ const SelectContent = React.forwardRef<
60
+ React.ElementRef<typeof SelectPrimitive.Content>,
61
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
62
+ >(({ className, children, position = 'popper', ...props }, ref) => (
63
+ <SelectPrimitive.Portal>
64
+ <SelectPrimitive.Content
65
+ ref={ref}
66
+ className={cn(
67
+ 'relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
68
+ position === 'popper' &&
69
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
70
+ className
71
+ )}
72
+ position={position}
73
+ {...props}
74
+ >
75
+ <SelectScrollUpButton />
76
+ <SelectPrimitive.Viewport
77
+ className={cn(
78
+ 'p-1',
79
+ position === 'popper' &&
80
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
81
+ )}
82
+ >
83
+ {children}
84
+ </SelectPrimitive.Viewport>
85
+ <SelectScrollDownButton />
86
+ </SelectPrimitive.Content>
87
+ </SelectPrimitive.Portal>
88
+ ))
89
+ SelectContent.displayName = SelectPrimitive.Content.displayName
90
+
91
+ const SelectLabel = React.forwardRef<
92
+ React.ElementRef<typeof SelectPrimitive.Label>,
93
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
94
+ >(({ className, ...props }, ref) => (
95
+ <SelectPrimitive.Label
96
+ ref={ref}
97
+ className={cn('py-1.5 pl-8 pr-2 text-sm font-semibold', className)}
98
+ {...props}
99
+ />
100
+ ))
101
+ SelectLabel.displayName = SelectPrimitive.Label.displayName
102
+
103
+ const SelectItem = React.forwardRef<
104
+ React.ElementRef<typeof SelectPrimitive.Item>,
105
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
106
+ >(({ className, children, ...props }, ref) => (
107
+ <SelectPrimitive.Item
108
+ ref={ref}
109
+ className={cn(
110
+ 'relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
111
+ className
112
+ )}
113
+ {...props}
114
+ >
115
+ <span className='absolute left-2 flex h-3.5 w-3.5 items-center justify-center'>
116
+ <SelectPrimitive.ItemIndicator>
117
+ <Check className='h-4 w-4' />
118
+ </SelectPrimitive.ItemIndicator>
119
+ </span>
120
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
121
+ </SelectPrimitive.Item>
122
+ ))
123
+ SelectItem.displayName = SelectPrimitive.Item.displayName
124
+
125
+ const SelectSeparator = React.forwardRef<
126
+ React.ElementRef<typeof SelectPrimitive.Separator>,
127
+ React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
128
+ >(({ className, ...props }, ref) => (
129
+ <SelectPrimitive.Separator
130
+ ref={ref}
131
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
132
+ {...props}
133
+ />
134
+ ))
135
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName
136
+
137
+ export {
138
+ Select,
139
+ SelectGroup,
140
+ SelectValue,
141
+ SelectTrigger,
142
+ SelectContent,
143
+ SelectLabel,
144
+ SelectItem,
145
+ SelectSeparator,
146
+ SelectScrollUpButton,
147
+ SelectScrollDownButton,
148
+ }
@@ -0,0 +1,24 @@
1
+ import * as React from 'react'
2
+ import * as SeparatorPrimitive from '@radix-ui/react-separator'
3
+
4
+ import { cn } from '@/lib/utils'
5
+
6
+ const Separator = React.forwardRef<
7
+ React.ElementRef<typeof SeparatorPrimitive.Root>,
8
+ React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>
9
+ >(({ className, orientation = 'horizontal', decorative = true, ...props }, ref) => (
10
+ <SeparatorPrimitive.Root
11
+ ref={ref}
12
+ decorative={decorative}
13
+ orientation={orientation}
14
+ className={cn(
15
+ 'shrink-0 bg-border',
16
+ orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]',
17
+ className
18
+ )}
19
+ {...props}
20
+ />
21
+ ))
22
+ Separator.displayName = SeparatorPrimitive.Root.displayName
23
+
24
+ export { Separator }