@betterstart/cli 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +133 -0
  2. package/dist/cli.d.ts +1 -9
  3. package/dist/cli.js +13484 -354
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.d.ts +24 -260
  6. package/dist/index.js +4 -11373
  7. package/dist/index.js.map +1 -1
  8. package/package.json +29 -42
  9. package/templates/schema.json +959 -0
  10. package/templates/tiptap/hooks/use-composed-ref.ts +43 -0
  11. package/templates/tiptap/hooks/use-cursor-visibility.ts +68 -0
  12. package/templates/tiptap/hooks/use-element-rect.ts +166 -0
  13. package/templates/tiptap/hooks/use-is-breakpoint.ts +32 -0
  14. package/templates/tiptap/hooks/use-menu-navigation.ts +182 -0
  15. package/templates/tiptap/hooks/use-scrolling.ts +64 -0
  16. package/templates/tiptap/hooks/use-throttled-callback.ts +146 -0
  17. package/templates/tiptap/hooks/use-tiptap-editor.ts +46 -0
  18. package/templates/tiptap/hooks/use-unmount.ts +21 -0
  19. package/templates/tiptap/hooks/use-window-size.ts +87 -0
  20. package/templates/tiptap/lib/tiptap-utils.ts +587 -0
  21. package/templates/tiptap/styles/_keyframe-animations.scss +91 -0
  22. package/templates/tiptap/styles/_variables.scss +296 -0
  23. package/templates/tiptap/tiptap-extension/node-background-extension.ts +138 -0
  24. package/templates/tiptap/tiptap-icons/align-center-icon.tsx +38 -0
  25. package/templates/tiptap/tiptap-icons/align-justify-icon.tsx +38 -0
  26. package/templates/tiptap/tiptap-icons/align-left-icon.tsx +38 -0
  27. package/templates/tiptap/tiptap-icons/align-right-icon.tsx +38 -0
  28. package/templates/tiptap/tiptap-icons/arrow-left-icon.tsx +24 -0
  29. package/templates/tiptap/tiptap-icons/ban-icon.tsx +26 -0
  30. package/templates/tiptap/tiptap-icons/blockquote-icon.tsx +44 -0
  31. package/templates/tiptap/tiptap-icons/bold-icon.tsx +26 -0
  32. package/templates/tiptap/tiptap-icons/chevron-down-icon.tsx +26 -0
  33. package/templates/tiptap/tiptap-icons/close-icon.tsx +24 -0
  34. package/templates/tiptap/tiptap-icons/code-block-icon.tsx +38 -0
  35. package/templates/tiptap/tiptap-icons/code2-icon.tsx +32 -0
  36. package/templates/tiptap/tiptap-icons/corner-down-left-icon.tsx +26 -0
  37. package/templates/tiptap/tiptap-icons/external-link-icon.tsx +28 -0
  38. package/templates/tiptap/tiptap-icons/heading-five-icon.tsx +28 -0
  39. package/templates/tiptap/tiptap-icons/heading-four-icon.tsx +28 -0
  40. package/templates/tiptap/tiptap-icons/heading-icon.tsx +24 -0
  41. package/templates/tiptap/tiptap-icons/heading-one-icon.tsx +28 -0
  42. package/templates/tiptap/tiptap-icons/heading-six-icon.tsx +30 -0
  43. package/templates/tiptap/tiptap-icons/heading-three-icon.tsx +36 -0
  44. package/templates/tiptap/tiptap-icons/heading-two-icon.tsx +28 -0
  45. package/templates/tiptap/tiptap-icons/highlighter-icon.tsx +26 -0
  46. package/templates/tiptap/tiptap-icons/image-plus-icon.tsx +26 -0
  47. package/templates/tiptap/tiptap-icons/italic-icon.tsx +24 -0
  48. package/templates/tiptap/tiptap-icons/link-icon.tsx +28 -0
  49. package/templates/tiptap/tiptap-icons/list-icon.tsx +56 -0
  50. package/templates/tiptap/tiptap-icons/list-ordered-icon.tsx +56 -0
  51. package/templates/tiptap/tiptap-icons/list-todo-icon.tsx +50 -0
  52. package/templates/tiptap/tiptap-icons/moon-star-icon.tsx +30 -0
  53. package/templates/tiptap/tiptap-icons/redo2-icon.tsx +26 -0
  54. package/templates/tiptap/tiptap-icons/strike-icon.tsx +28 -0
  55. package/templates/tiptap/tiptap-icons/subscript-icon.tsx +38 -0
  56. package/templates/tiptap/tiptap-icons/sun-icon.tsx +58 -0
  57. package/templates/tiptap/tiptap-icons/superscript-icon.tsx +38 -0
  58. package/templates/tiptap/tiptap-icons/trash-icon.tsx +26 -0
  59. package/templates/tiptap/tiptap-icons/underline-icon.tsx +26 -0
  60. package/templates/tiptap/tiptap-icons/undo2-icon.tsx +26 -0
  61. package/templates/tiptap/tiptap-node/blockquote-node/blockquote-node.scss +37 -0
  62. package/templates/tiptap/tiptap-node/code-block-node/code-block-node.scss +54 -0
  63. package/templates/tiptap/tiptap-node/heading-node/heading-node.scss +45 -0
  64. package/templates/tiptap/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension.ts +10 -0
  65. package/templates/tiptap/tiptap-node/horizontal-rule-node/horizontal-rule-node.scss +25 -0
  66. package/templates/tiptap/tiptap-node/image-node/image-node.scss +35 -0
  67. package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node-extension.ts +154 -0
  68. package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node.scss +249 -0
  69. package/templates/tiptap/tiptap-node/image-upload-node/image-upload-node.tsx +522 -0
  70. package/templates/tiptap/tiptap-node/image-upload-node/index.tsx +1 -0
  71. package/templates/tiptap/tiptap-node/list-node/list-node.scss +208 -0
  72. package/templates/tiptap/tiptap-node/paragraph-node/paragraph-node.scss +273 -0
  73. package/templates/tiptap/tiptap-ui/blockquote-button/blockquote-button.tsx +104 -0
  74. package/templates/tiptap/tiptap-ui/blockquote-button/index.tsx +2 -0
  75. package/templates/tiptap/tiptap-ui/blockquote-button/use-blockquote.ts +252 -0
  76. package/templates/tiptap/tiptap-ui/code-block-button/code-block-button.tsx +106 -0
  77. package/templates/tiptap/tiptap-ui/code-block-button/index.tsx +2 -0
  78. package/templates/tiptap/tiptap-ui/code-block-button/use-code-block.ts +261 -0
  79. package/templates/tiptap/tiptap-ui/color-highlight-button/color-highlight-button.scss +49 -0
  80. package/templates/tiptap/tiptap-ui/color-highlight-button/color-highlight-button.tsx +153 -0
  81. package/templates/tiptap/tiptap-ui/color-highlight-button/index.tsx +2 -0
  82. package/templates/tiptap/tiptap-ui/color-highlight-button/use-color-highlight.ts +345 -0
  83. package/templates/tiptap/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +207 -0
  84. package/templates/tiptap/tiptap-ui/color-highlight-popover/index.tsx +1 -0
  85. package/templates/tiptap/tiptap-ui/heading-button/heading-button.tsx +107 -0
  86. package/templates/tiptap/tiptap-ui/heading-button/index.tsx +2 -0
  87. package/templates/tiptap/tiptap-ui/heading-button/use-heading.ts +314 -0
  88. package/templates/tiptap/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +131 -0
  89. package/templates/tiptap/tiptap-ui/heading-dropdown-menu/index.tsx +2 -0
  90. package/templates/tiptap/tiptap-ui/heading-dropdown-menu/use-heading-dropdown-menu.ts +130 -0
  91. package/templates/tiptap/tiptap-ui/image-upload-button/image-upload-button.tsx +114 -0
  92. package/templates/tiptap/tiptap-ui/image-upload-button/index.tsx +2 -0
  93. package/templates/tiptap/tiptap-ui/image-upload-button/use-image-upload.ts +192 -0
  94. package/templates/tiptap/tiptap-ui/link-popover/index.tsx +2 -0
  95. package/templates/tiptap/tiptap-ui/link-popover/link-popover.tsx +285 -0
  96. package/templates/tiptap/tiptap-ui/link-popover/use-link-popover.ts +286 -0
  97. package/templates/tiptap/tiptap-ui/list-button/index.tsx +2 -0
  98. package/templates/tiptap/tiptap-ui/list-button/list-button.tsx +108 -0
  99. package/templates/tiptap/tiptap-ui/list-button/use-list.ts +329 -0
  100. package/templates/tiptap/tiptap-ui/list-dropdown-menu/index.tsx +1 -0
  101. package/templates/tiptap/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +123 -0
  102. package/templates/tiptap/tiptap-ui/list-dropdown-menu/use-list-dropdown-menu.ts +203 -0
  103. package/templates/tiptap/tiptap-ui/mark-button/index.tsx +2 -0
  104. package/templates/tiptap/tiptap-ui/mark-button/mark-button.tsx +107 -0
  105. package/templates/tiptap/tiptap-ui/mark-button/use-mark.ts +206 -0
  106. package/templates/tiptap/tiptap-ui/text-align-button/index.tsx +2 -0
  107. package/templates/tiptap/tiptap-ui/text-align-button/text-align-button.tsx +118 -0
  108. package/templates/tiptap/tiptap-ui/text-align-button/use-text-align.ts +212 -0
  109. package/templates/tiptap/tiptap-ui/undo-redo-button/index.tsx +2 -0
  110. package/templates/tiptap/tiptap-ui/undo-redo-button/undo-redo-button.tsx +105 -0
  111. package/templates/tiptap/tiptap-ui/undo-redo-button/use-undo-redo.ts +173 -0
  112. package/templates/tiptap/tiptap-ui-primitive/badge/badge-colors.scss +395 -0
  113. package/templates/tiptap/tiptap-ui-primitive/badge/badge-group.scss +16 -0
  114. package/templates/tiptap/tiptap-ui-primitive/badge/badge.scss +99 -0
  115. package/templates/tiptap/tiptap-ui-primitive/badge/badge.tsx +46 -0
  116. package/templates/tiptap/tiptap-ui-primitive/badge/index.tsx +1 -0
  117. package/templates/tiptap/tiptap-ui-primitive/button/button-colors.scss +429 -0
  118. package/templates/tiptap/tiptap-ui-primitive/button/button-group.scss +22 -0
  119. package/templates/tiptap/tiptap-ui-primitive/button/button.scss +314 -0
  120. package/templates/tiptap/tiptap-ui-primitive/button/button.tsx +102 -0
  121. package/templates/tiptap/tiptap-ui-primitive/button/index.tsx +1 -0
  122. package/templates/tiptap/tiptap-ui-primitive/card/card.scss +77 -0
  123. package/templates/tiptap/tiptap-ui-primitive/card/card.tsx +59 -0
  124. package/templates/tiptap/tiptap-ui-primitive/card/index.tsx +1 -0
  125. package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/dropdown-menu.scss +63 -0
  126. package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/dropdown-menu.tsx +95 -0
  127. package/templates/tiptap/tiptap-ui-primitive/dropdown-menu/index.tsx +1 -0
  128. package/templates/tiptap/tiptap-ui-primitive/input/index.tsx +1 -0
  129. package/templates/tiptap/tiptap-ui-primitive/input/input.scss +45 -0
  130. package/templates/tiptap/tiptap-ui-primitive/input/input.tsx +18 -0
  131. package/templates/tiptap/tiptap-ui-primitive/popover/index.tsx +1 -0
  132. package/templates/tiptap/tiptap-ui-primitive/popover/popover.scss +63 -0
  133. package/templates/tiptap/tiptap-ui-primitive/popover/popover.tsx +33 -0
  134. package/templates/tiptap/tiptap-ui-primitive/separator/index.tsx +1 -0
  135. package/templates/tiptap/tiptap-ui-primitive/separator/separator.scss +23 -0
  136. package/templates/tiptap/tiptap-ui-primitive/separator/separator.tsx +33 -0
  137. package/templates/tiptap/tiptap-ui-primitive/spacer/index.tsx +1 -0
  138. package/templates/tiptap/tiptap-ui-primitive/spacer/spacer.tsx +21 -0
  139. package/templates/tiptap/tiptap-ui-primitive/toolbar/index.tsx +1 -0
  140. package/templates/tiptap/tiptap-ui-primitive/toolbar/toolbar.scss +98 -0
  141. package/templates/tiptap/tiptap-ui-primitive/toolbar/toolbar.tsx +113 -0
  142. package/templates/tiptap/tiptap-ui-primitive/tooltip/index.tsx +1 -0
  143. package/templates/tiptap/tiptap-ui-primitive/tooltip/tooltip.scss +43 -0
  144. package/templates/tiptap/tiptap-ui-primitive/tooltip/tooltip.tsx +223 -0
  145. package/templates/ui/accordion.tsx +52 -0
  146. package/templates/ui/alert-dialog.tsx +116 -0
  147. package/templates/ui/alert.tsx +48 -0
  148. package/templates/ui/aspect-ratio.tsx +7 -0
  149. package/templates/ui/avatar.tsx +46 -0
  150. package/templates/ui/badge.tsx +32 -0
  151. package/templates/ui/breadcrumb.tsx +98 -0
  152. package/templates/ui/button-group.tsx +77 -0
  153. package/templates/ui/button.tsx +48 -0
  154. package/templates/ui/calendar.tsx +176 -0
  155. package/templates/ui/card.tsx +54 -0
  156. package/templates/ui/carousel.tsx +234 -0
  157. package/templates/ui/chart.tsx +349 -0
  158. package/templates/ui/checkbox.tsx +27 -0
  159. package/templates/ui/collapsible.tsx +11 -0
  160. package/templates/ui/command.tsx +142 -0
  161. package/templates/ui/context-menu.tsx +188 -0
  162. package/templates/ui/curriculum-editor.tsx +601 -0
  163. package/templates/ui/date-picker.tsx +70 -0
  164. package/templates/ui/dialog.tsx +103 -0
  165. package/templates/ui/drawer.tsx +99 -0
  166. package/templates/ui/dropdown-menu.tsx +185 -0
  167. package/templates/ui/dynamic-list-field.tsx +95 -0
  168. package/templates/ui/empty.tsx +90 -0
  169. package/templates/ui/field.tsx +231 -0
  170. package/templates/ui/file-upload-example.tsx +113 -0
  171. package/templates/ui/form.tsx +172 -0
  172. package/templates/ui/hover-card.tsx +28 -0
  173. package/templates/ui/icon-picker.tsx +435 -0
  174. package/templates/ui/icons-data.ts +6 -0
  175. package/templates/ui/image-upload-field.tsx +360 -0
  176. package/templates/ui/input-group.tsx +160 -0
  177. package/templates/ui/input-otp.tsx +70 -0
  178. package/templates/ui/input.tsx +21 -0
  179. package/templates/ui/item.tsx +171 -0
  180. package/templates/ui/kbd.tsx +28 -0
  181. package/templates/ui/label.tsx +20 -0
  182. package/templates/ui/logo.tsx +113 -0
  183. package/templates/ui/markdown-editor.tsx +303 -0
  184. package/templates/ui/markdown-utils.ts +128 -0
  185. package/templates/ui/media-upload-field.tsx +255 -0
  186. package/templates/ui/menubar.tsx +230 -0
  187. package/templates/ui/navigation-menu.tsx +119 -0
  188. package/templates/ui/pagination.tsx +96 -0
  189. package/templates/ui/placeholder.tsx +25 -0
  190. package/templates/ui/popover.tsx +32 -0
  191. package/templates/ui/progress.tsx +24 -0
  192. package/templates/ui/radio-group.tsx +37 -0
  193. package/templates/ui/resizable.tsx +41 -0
  194. package/templates/ui/rich-text-editor.tsx +374 -0
  195. package/templates/ui/scroll-area.tsx +45 -0
  196. package/templates/ui/select.tsx +151 -0
  197. package/templates/ui/separator.tsx +25 -0
  198. package/templates/ui/sheet.tsx +120 -0
  199. package/templates/ui/sidebar.tsx +684 -0
  200. package/templates/ui/skeleton.tsx +7 -0
  201. package/templates/ui/slider.tsx +24 -0
  202. package/templates/ui/sonner.tsx +29 -0
  203. package/templates/ui/spinner.tsx +15 -0
  204. package/templates/ui/switch.tsx +28 -0
  205. package/templates/ui/table.tsx +93 -0
  206. package/templates/ui/tabs.tsx +54 -0
  207. package/templates/ui/textarea.tsx +20 -0
  208. package/templates/ui/toast.tsx +127 -0
  209. package/templates/ui/toggle-group.tsx +56 -0
  210. package/templates/ui/toggle.tsx +43 -0
  211. package/templates/ui/tooltip.tsx +31 -0
  212. package/templates/ui/use-mobile.tsx +19 -0
  213. package/templates/ui/video-upload-field.tsx +368 -0
  214. package/dist/chunk-G4KI4DVB.js +0 -179
  215. package/dist/chunk-G4KI4DVB.js.map +0 -1
  216. package/dist/chunk-NKRQYAS6.js +0 -260
  217. package/dist/chunk-NKRQYAS6.js.map +0 -1
  218. package/dist/chunk-QLVSHP7X.js +0 -235
  219. package/dist/chunk-QLVSHP7X.js.map +0 -1
  220. package/dist/chunk-WY6BC55D.js +0 -357
  221. package/dist/chunk-WY6BC55D.js.map +0 -1
  222. package/dist/config/index.d.ts +0 -93
  223. package/dist/config/index.js +0 -58
  224. package/dist/config/index.js.map +0 -1
  225. package/dist/core/index.d.ts +0 -415
  226. package/dist/core/index.js +0 -906
  227. package/dist/core/index.js.map +0 -1
  228. package/dist/import-resolver-BaZ-rzkH.d.ts +0 -123
  229. package/dist/logger-awLb347n.d.ts +0 -81
  230. package/dist/plugins/index.d.ts +0 -213
  231. package/dist/plugins/index.js +0 -365
  232. package/dist/plugins/index.js.map +0 -1
  233. package/dist/types-ByX_gl6y.d.ts +0 -232
  234. package/dist/types-eI549DEG.d.ts +0 -331
@@ -0,0 +1,103 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@cms/utils/cn'
4
+ import * as DialogPrimitive from '@radix-ui/react-dialog'
5
+ import { X } from 'lucide-react'
6
+ import * as React from 'react'
7
+
8
+ const Dialog = DialogPrimitive.Root
9
+
10
+ const DialogTrigger = DialogPrimitive.Trigger
11
+
12
+ const DialogPortal = DialogPrimitive.Portal
13
+
14
+ const DialogClose = DialogPrimitive.Close
15
+
16
+ const DialogOverlay = React.forwardRef<
17
+ React.ElementRef<typeof DialogPrimitive.Overlay>,
18
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
19
+ >(({ className, ...props }, ref) => (
20
+ <DialogPrimitive.Overlay
21
+ ref={ref}
22
+ className={cn(
23
+ 'fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ ))
29
+ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName
30
+
31
+ const DialogContent = React.forwardRef<
32
+ React.ElementRef<typeof DialogPrimitive.Content>,
33
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
34
+ >(({ className, children, ...props }, ref) => (
35
+ <DialogPortal>
36
+ <DialogOverlay />
37
+ <DialogPrimitive.Content
38
+ ref={ref}
39
+ className={cn(
40
+ 'fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg',
41
+ className
42
+ )}
43
+ {...props}
44
+ >
45
+ {children}
46
+ <DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
47
+ <X className="h-4 w-4" />
48
+ <span className="sr-only">Close</span>
49
+ </DialogPrimitive.Close>
50
+ </DialogPrimitive.Content>
51
+ </DialogPortal>
52
+ ))
53
+ DialogContent.displayName = DialogPrimitive.Content.displayName
54
+
55
+ const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
56
+ <div className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)} {...props} />
57
+ )
58
+ DialogHeader.displayName = 'DialogHeader'
59
+
60
+ const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
61
+ <div
62
+ className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
63
+ {...props}
64
+ />
65
+ )
66
+ DialogFooter.displayName = 'DialogFooter'
67
+
68
+ const DialogTitle = React.forwardRef<
69
+ React.ElementRef<typeof DialogPrimitive.Title>,
70
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
71
+ >(({ className, ...props }, ref) => (
72
+ <DialogPrimitive.Title
73
+ ref={ref}
74
+ className={cn('text-lg font-semibold leading-none tracking-tight', className)}
75
+ {...props}
76
+ />
77
+ ))
78
+ DialogTitle.displayName = DialogPrimitive.Title.displayName
79
+
80
+ const DialogDescription = React.forwardRef<
81
+ React.ElementRef<typeof DialogPrimitive.Description>,
82
+ React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
83
+ >(({ className, ...props }, ref) => (
84
+ <DialogPrimitive.Description
85
+ ref={ref}
86
+ className={cn('text-sm text-muted-foreground', className)}
87
+ {...props}
88
+ />
89
+ ))
90
+ DialogDescription.displayName = DialogPrimitive.Description.displayName
91
+
92
+ export {
93
+ Dialog,
94
+ DialogPortal,
95
+ DialogOverlay,
96
+ DialogTrigger,
97
+ DialogClose,
98
+ DialogContent,
99
+ DialogHeader,
100
+ DialogFooter,
101
+ DialogTitle,
102
+ DialogDescription
103
+ }
@@ -0,0 +1,99 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@cms/utils/cn'
4
+ import * as React from 'react'
5
+ import { Drawer as DrawerPrimitive } from 'vaul'
6
+
7
+ const Drawer = ({
8
+ shouldScaleBackground = true,
9
+ ...props
10
+ }: React.ComponentProps<typeof DrawerPrimitive.Root>) => (
11
+ <DrawerPrimitive.Root shouldScaleBackground={shouldScaleBackground} {...props} />
12
+ )
13
+ Drawer.displayName = 'Drawer'
14
+
15
+ const DrawerTrigger = DrawerPrimitive.Trigger
16
+
17
+ const DrawerPortal = DrawerPrimitive.Portal
18
+
19
+ const DrawerClose = DrawerPrimitive.Close
20
+
21
+ const DrawerOverlay = React.forwardRef<
22
+ React.ElementRef<typeof DrawerPrimitive.Overlay>,
23
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Overlay>
24
+ >(({ className, ...props }, ref) => (
25
+ <DrawerPrimitive.Overlay
26
+ ref={ref}
27
+ className={cn('fixed inset-0 z-50 bg-black/80', className)}
28
+ {...props}
29
+ />
30
+ ))
31
+ DrawerOverlay.displayName = DrawerPrimitive.Overlay.displayName
32
+
33
+ const DrawerContent = React.forwardRef<
34
+ React.ElementRef<typeof DrawerPrimitive.Content>,
35
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Content>
36
+ >(({ className, children, ...props }, ref) => (
37
+ <DrawerPortal>
38
+ <DrawerOverlay />
39
+ <DrawerPrimitive.Content
40
+ ref={ref}
41
+ className={cn(
42
+ 'fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-[10px] border bg-background',
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <div className="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
48
+ {children}
49
+ </DrawerPrimitive.Content>
50
+ </DrawerPortal>
51
+ ))
52
+ DrawerContent.displayName = 'DrawerContent'
53
+
54
+ const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
55
+ <div className={cn('grid gap-1.5 p-4 text-center sm:text-left', className)} {...props} />
56
+ )
57
+ DrawerHeader.displayName = 'DrawerHeader'
58
+
59
+ const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
60
+ <div className={cn('mt-auto flex flex-col gap-2 p-4', className)} {...props} />
61
+ )
62
+ DrawerFooter.displayName = 'DrawerFooter'
63
+
64
+ const DrawerTitle = React.forwardRef<
65
+ React.ElementRef<typeof DrawerPrimitive.Title>,
66
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
67
+ >(({ className, ...props }, ref) => (
68
+ <DrawerPrimitive.Title
69
+ ref={ref}
70
+ className={cn('text-lg font-semibold leading-none tracking-tight', className)}
71
+ {...props}
72
+ />
73
+ ))
74
+ DrawerTitle.displayName = DrawerPrimitive.Title.displayName
75
+
76
+ const DrawerDescription = React.forwardRef<
77
+ React.ElementRef<typeof DrawerPrimitive.Description>,
78
+ React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Description>
79
+ >(({ className, ...props }, ref) => (
80
+ <DrawerPrimitive.Description
81
+ ref={ref}
82
+ className={cn('text-sm text-muted-foreground', className)}
83
+ {...props}
84
+ />
85
+ ))
86
+ DrawerDescription.displayName = DrawerPrimitive.Description.displayName
87
+
88
+ export {
89
+ Drawer,
90
+ DrawerPortal,
91
+ DrawerOverlay,
92
+ DrawerTrigger,
93
+ DrawerClose,
94
+ DrawerContent,
95
+ DrawerHeader,
96
+ DrawerFooter,
97
+ DrawerTitle,
98
+ DrawerDescription
99
+ }
@@ -0,0 +1,185 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@cms/utils/cn'
4
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
5
+ import { Check, ChevronRight, Circle } from 'lucide-react'
6
+ import * as React from 'react'
7
+
8
+ const DropdownMenu = DropdownMenuPrimitive.Root
9
+
10
+ const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
11
+
12
+ const DropdownMenuGroup = DropdownMenuPrimitive.Group
13
+
14
+ const DropdownMenuPortal = DropdownMenuPrimitive.Portal
15
+
16
+ const DropdownMenuSub = DropdownMenuPrimitive.Sub
17
+
18
+ const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
19
+
20
+ const DropdownMenuSubTrigger = React.forwardRef<
21
+ React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
22
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
23
+ inset?: boolean
24
+ }
25
+ >(({ className, inset, children, ...props }, ref) => (
26
+ <DropdownMenuPrimitive.SubTrigger
27
+ ref={ref}
28
+ className={cn(
29
+ 'flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent data-[state=open]:bg-accent [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
30
+ inset && 'pl-8',
31
+ className
32
+ )}
33
+ {...props}
34
+ >
35
+ {children}
36
+ <ChevronRight className="ml-auto" />
37
+ </DropdownMenuPrimitive.SubTrigger>
38
+ ))
39
+ DropdownMenuSubTrigger.displayName = DropdownMenuPrimitive.SubTrigger.displayName
40
+
41
+ const DropdownMenuSubContent = React.forwardRef<
42
+ React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
43
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
44
+ >(({ className, ...props }, ref) => (
45
+ <DropdownMenuPrimitive.SubContent
46
+ ref={ref}
47
+ className={cn(
48
+ '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 origin-[--radix-dropdown-menu-content-transform-origin]',
49
+ className
50
+ )}
51
+ {...props}
52
+ />
53
+ ))
54
+ DropdownMenuSubContent.displayName = DropdownMenuPrimitive.SubContent.displayName
55
+
56
+ const DropdownMenuContent = React.forwardRef<
57
+ React.ElementRef<typeof DropdownMenuPrimitive.Content>,
58
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
59
+ >(({ className, sideOffset = 4, ...props }, ref) => (
60
+ <DropdownMenuPrimitive.Portal>
61
+ <DropdownMenuPrimitive.Content
62
+ ref={ref}
63
+ sideOffset={sideOffset}
64
+ className={cn(
65
+ 'z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
66
+ '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 origin-[--radix-dropdown-menu-content-transform-origin]',
67
+ className
68
+ )}
69
+ {...props}
70
+ />
71
+ </DropdownMenuPrimitive.Portal>
72
+ ))
73
+ DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
74
+
75
+ const DropdownMenuItem = React.forwardRef<
76
+ React.ElementRef<typeof DropdownMenuPrimitive.Item>,
77
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
78
+ inset?: boolean
79
+ }
80
+ >(({ className, inset, ...props }, ref) => (
81
+ <DropdownMenuPrimitive.Item
82
+ ref={ref}
83
+ className={cn(
84
+ 'relative flex cursor-default select-none items-center gap-2 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 [&>svg]:size-4 [&>svg]:shrink-0',
85
+ inset && 'pl-8',
86
+ className
87
+ )}
88
+ {...props}
89
+ />
90
+ ))
91
+ DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
92
+
93
+ const DropdownMenuCheckboxItem = React.forwardRef<
94
+ React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
95
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
96
+ >(({ className, children, checked, ...props }, ref) => (
97
+ <DropdownMenuPrimitive.CheckboxItem
98
+ ref={ref}
99
+ className={cn(
100
+ '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',
101
+ className
102
+ )}
103
+ checked={checked}
104
+ {...props}
105
+ >
106
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
107
+ <DropdownMenuPrimitive.ItemIndicator>
108
+ <Check className="h-4 w-4" />
109
+ </DropdownMenuPrimitive.ItemIndicator>
110
+ </span>
111
+ {children}
112
+ </DropdownMenuPrimitive.CheckboxItem>
113
+ ))
114
+ DropdownMenuCheckboxItem.displayName = DropdownMenuPrimitive.CheckboxItem.displayName
115
+
116
+ const DropdownMenuRadioItem = React.forwardRef<
117
+ React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
118
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
119
+ >(({ className, children, ...props }, ref) => (
120
+ <DropdownMenuPrimitive.RadioItem
121
+ ref={ref}
122
+ className={cn(
123
+ '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',
124
+ className
125
+ )}
126
+ {...props}
127
+ >
128
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
129
+ <DropdownMenuPrimitive.ItemIndicator>
130
+ <Circle className="h-2 w-2 fill-current" />
131
+ </DropdownMenuPrimitive.ItemIndicator>
132
+ </span>
133
+ {children}
134
+ </DropdownMenuPrimitive.RadioItem>
135
+ ))
136
+ DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
137
+
138
+ const DropdownMenuLabel = React.forwardRef<
139
+ React.ElementRef<typeof DropdownMenuPrimitive.Label>,
140
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
141
+ inset?: boolean
142
+ }
143
+ >(({ className, inset, ...props }, ref) => (
144
+ <DropdownMenuPrimitive.Label
145
+ ref={ref}
146
+ className={cn('px-2 py-1.5 text-sm font-semibold', inset && 'pl-8', className)}
147
+ {...props}
148
+ />
149
+ ))
150
+ DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
151
+
152
+ const DropdownMenuSeparator = React.forwardRef<
153
+ React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
154
+ React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
155
+ >(({ className, ...props }, ref) => (
156
+ <DropdownMenuPrimitive.Separator
157
+ ref={ref}
158
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
159
+ {...props}
160
+ />
161
+ ))
162
+ DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
163
+
164
+ const DropdownMenuShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
165
+ return <span className={cn('ml-auto text-xs tracking-widest opacity-60', className)} {...props} />
166
+ }
167
+ DropdownMenuShortcut.displayName = 'DropdownMenuShortcut'
168
+
169
+ export {
170
+ DropdownMenu,
171
+ DropdownMenuTrigger,
172
+ DropdownMenuContent,
173
+ DropdownMenuItem,
174
+ DropdownMenuCheckboxItem,
175
+ DropdownMenuRadioItem,
176
+ DropdownMenuLabel,
177
+ DropdownMenuSeparator,
178
+ DropdownMenuShortcut,
179
+ DropdownMenuGroup,
180
+ DropdownMenuPortal,
181
+ DropdownMenuSub,
182
+ DropdownMenuSubContent,
183
+ DropdownMenuSubTrigger,
184
+ DropdownMenuRadioGroup
185
+ }
@@ -0,0 +1,95 @@
1
+ 'use client'
2
+
3
+ import { cn } from '@cms/utils/cn'
4
+ import { Plus, Trash2 } from 'lucide-react'
5
+ import { useFieldArray, useFormContext } from 'react-hook-form'
6
+ import { Button } from './button'
7
+ import { FormItem, FormLabel, FormMessage } from './form'
8
+ import { Input } from './input'
9
+
10
+ interface DynamicListFieldProps {
11
+ name: string
12
+ label: string
13
+ disabled?: boolean
14
+ maxItems?: number
15
+ placeholder?: string
16
+ className?: string
17
+ }
18
+
19
+ export function DynamicListField({
20
+ name,
21
+ label,
22
+ disabled,
23
+ maxItems,
24
+ placeholder = 'Enter value',
25
+ className
26
+ }: DynamicListFieldProps) {
27
+ const { control } = useFormContext()
28
+ const { fields, append, remove } = useFieldArray({
29
+ control,
30
+ name
31
+ })
32
+
33
+ const canAddMore = !maxItems || fields.length < maxItems
34
+
35
+ const handleAdd = () => {
36
+ if (canAddMore) {
37
+ append('')
38
+ }
39
+ }
40
+
41
+ return (
42
+ <div className={cn('space-y-4', className)}>
43
+ <div className="flex items-center justify-between">
44
+ <FormLabel>{label}</FormLabel>
45
+ <Button
46
+ type="button"
47
+ variant="outline"
48
+ size="sm"
49
+ onClick={handleAdd}
50
+ disabled={disabled || !canAddMore}
51
+ >
52
+ <Plus className="mr-2 h-4 w-4" />
53
+ Add {label}
54
+ </Button>
55
+ </div>
56
+
57
+ {fields.length === 0 && (
58
+ <div className="text-sm text-muted-foreground">
59
+ No items added yet. Click "Add {label}" to get started.
60
+ </div>
61
+ )}
62
+
63
+ <div className="space-y-3">
64
+ {fields.map((field, index) => (
65
+ <div key={field.id} className="flex items-start gap-2">
66
+ <FormItem className="flex-1">
67
+ <Input
68
+ {...control.register(`${name}.${index}`)}
69
+ placeholder={placeholder}
70
+ disabled={disabled}
71
+ />
72
+ <FormMessage />
73
+ </FormItem>
74
+ <Button
75
+ type="button"
76
+ variant="destructive"
77
+ size="icon"
78
+ onClick={() => remove(index)}
79
+ disabled={disabled}
80
+ className="mt-0"
81
+ >
82
+ <Trash2 className="h-4 w-4" />
83
+ </Button>
84
+ </div>
85
+ ))}
86
+ </div>
87
+
88
+ {maxItems && (
89
+ <div className="text-xs text-muted-foreground">
90
+ {fields.length} / {maxItems} items
91
+ </div>
92
+ )}
93
+ </div>
94
+ )
95
+ }
@@ -0,0 +1,90 @@
1
+ import { cn } from '@cms/utils/cn'
2
+ import { cva, type VariantProps } from 'class-variance-authority'
3
+
4
+ function Empty({ className, ...props }: React.ComponentProps<'div'>) {
5
+ return (
6
+ <div
7
+ data-slot="empty"
8
+ className={cn(
9
+ 'flex min-w-0 flex-1 flex-col items-center justify-center gap-6 rounded-lg border-dashed p-6 text-center md:p-12',
10
+ className
11
+ )}
12
+ {...props}
13
+ />
14
+ )
15
+ }
16
+
17
+ function EmptyHeader({ className, ...props }: React.ComponentProps<'div'>) {
18
+ return (
19
+ <div
20
+ data-slot="empty-header"
21
+ className={cn('flex max-w-sm flex-col items-center gap-2 text-center', className)}
22
+ {...props}
23
+ />
24
+ )
25
+ }
26
+
27
+ const emptyMediaVariants = cva(
28
+ 'mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0',
29
+ {
30
+ variants: {
31
+ variant: {
32
+ default: 'bg-transparent',
33
+ icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6"
34
+ }
35
+ },
36
+ defaultVariants: {
37
+ variant: 'default'
38
+ }
39
+ }
40
+ )
41
+
42
+ function EmptyMedia({
43
+ className,
44
+ variant = 'default',
45
+ ...props
46
+ }: React.ComponentProps<'div'> & VariantProps<typeof emptyMediaVariants>) {
47
+ return (
48
+ <div
49
+ data-slot="empty-icon"
50
+ data-variant={variant}
51
+ className={cn(emptyMediaVariants({ variant, className }))}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function EmptyTitle({ className, ...props }: React.ComponentProps<'div'>) {
58
+ return (
59
+ <div
60
+ data-slot="empty-title"
61
+ className={cn('text-lg font-medium tracking-tight', className)}
62
+ {...props}
63
+ />
64
+ )
65
+ }
66
+
67
+ function EmptyDescription({ className, ...props }: React.ComponentProps<'p'>) {
68
+ return (
69
+ <div
70
+ data-slot="empty-description"
71
+ className={cn(
72
+ 'text-muted-foreground [&>a:hover]:text-primary text-sm/relaxed [&>a]:underline [&>a]:underline-offset-4',
73
+ className
74
+ )}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ function EmptyContent({ className, ...props }: React.ComponentProps<'div'>) {
81
+ return (
82
+ <div
83
+ data-slot="empty-content"
84
+ className={cn('flex w-full min-w-0 max-w-sm flex-col items-center gap-4 text-sm', className)}
85
+ {...props}
86
+ />
87
+ )
88
+ }
89
+
90
+ export { Empty, EmptyHeader, EmptyTitle, EmptyDescription, EmptyContent, EmptyMedia }