@nocobase/portal-template-default 1.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 (123) hide show
  1. package/.env.example +10 -0
  2. package/Dockerfile +36 -0
  3. package/README.MD +50 -0
  4. package/components.json +25 -0
  5. package/eslint.config.js +28 -0
  6. package/index.html +39 -0
  7. package/package.json +84 -0
  8. package/pnpm-workspace.yaml +2 -0
  9. package/public/favicon.ico +0 -0
  10. package/public/logo-dark.png +0 -0
  11. package/public/logo-mark-dark.png +0 -0
  12. package/public/logo-mark.png +0 -0
  13. package/public/logo.png +0 -0
  14. package/src/App.css +158 -0
  15. package/src/App.tsx +151 -0
  16. package/src/components/app-shell/brand.tsx +70 -0
  17. package/src/components/app-shell/breadcrumb.tsx +81 -0
  18. package/src/components/app-shell/document-title-handler.tsx +169 -0
  19. package/src/components/app-shell/error-component.tsx +134 -0
  20. package/src/components/app-shell/header.tsx +127 -0
  21. package/src/components/app-shell/layout.tsx +39 -0
  22. package/src/components/app-shell/loading-overlay.tsx +36 -0
  23. package/src/components/app-shell/sidebar.tsx +351 -0
  24. package/src/components/app-shell/user-avatar.tsx +42 -0
  25. package/src/components/app-shell/user-info.tsx +53 -0
  26. package/src/components/auth/auth-layout.tsx +82 -0
  27. package/src/components/auth/forgot-password-form.tsx +58 -0
  28. package/src/components/auth/input-password.tsx +38 -0
  29. package/src/components/auth/sign-in-form.tsx +111 -0
  30. package/src/components/auth/sign-up-form.tsx +127 -0
  31. package/src/components/data-table/data-table-filter.tsx +994 -0
  32. package/src/components/data-table/data-table-pagination.tsx +146 -0
  33. package/src/components/data-table/data-table-sorter.tsx +47 -0
  34. package/src/components/data-table/data-table.tsx +321 -0
  35. package/src/components/notifications/toaster.tsx +23 -0
  36. package/src/components/notifications/undoable-notification.tsx +84 -0
  37. package/src/components/notifications/use-notification-provider.tsx +62 -0
  38. package/src/components/resources/buttons/clone.tsx +81 -0
  39. package/src/components/resources/buttons/create.tsx +70 -0
  40. package/src/components/resources/buttons/delete.tsx +113 -0
  41. package/src/components/resources/buttons/edit.tsx +81 -0
  42. package/src/components/resources/buttons/list.tsx +70 -0
  43. package/src/components/resources/buttons/refresh.tsx +81 -0
  44. package/src/components/resources/buttons/show.tsx +81 -0
  45. package/src/components/resources/status-badge.tsx +37 -0
  46. package/src/components/resources/views/create-view.tsx +81 -0
  47. package/src/components/resources/views/edit-view.tsx +104 -0
  48. package/src/components/resources/views/list-view.tsx +86 -0
  49. package/src/components/resources/views/show-view.tsx +108 -0
  50. package/src/components/theme/theme-provider.tsx +71 -0
  51. package/src/components/theme/theme-select.tsx +97 -0
  52. package/src/components/theme/theme-toggle.tsx +66 -0
  53. package/src/components/ui/accordion.tsx +72 -0
  54. package/src/components/ui/alert-dialog.tsx +185 -0
  55. package/src/components/ui/alert.tsx +76 -0
  56. package/src/components/ui/aspect-ratio.tsx +22 -0
  57. package/src/components/ui/avatar.tsx +107 -0
  58. package/src/components/ui/badge.tsx +52 -0
  59. package/src/components/ui/breadcrumb.tsx +125 -0
  60. package/src/components/ui/button.tsx +58 -0
  61. package/src/components/ui/calendar.tsx +221 -0
  62. package/src/components/ui/card.tsx +103 -0
  63. package/src/components/ui/carousel.tsx +240 -0
  64. package/src/components/ui/chart.tsx +373 -0
  65. package/src/components/ui/checkbox.tsx +29 -0
  66. package/src/components/ui/collapsible.tsx +19 -0
  67. package/src/components/ui/command.tsx +192 -0
  68. package/src/components/ui/context-menu.tsx +271 -0
  69. package/src/components/ui/dialog.tsx +160 -0
  70. package/src/components/ui/drawer.tsx +226 -0
  71. package/src/components/ui/dropdown-menu.tsx +268 -0
  72. package/src/components/ui/form.tsx +174 -0
  73. package/src/components/ui/hover-card.tsx +49 -0
  74. package/src/components/ui/input-group.tsx +158 -0
  75. package/src/components/ui/input-otp.tsx +87 -0
  76. package/src/components/ui/input.tsx +20 -0
  77. package/src/components/ui/label.tsx +18 -0
  78. package/src/components/ui/menubar.tsx +278 -0
  79. package/src/components/ui/navigation-menu.tsx +168 -0
  80. package/src/components/ui/pagination.tsx +130 -0
  81. package/src/components/ui/popover.tsx +91 -0
  82. package/src/components/ui/progress.tsx +81 -0
  83. package/src/components/ui/radio-group.tsx +38 -0
  84. package/src/components/ui/resizable.tsx +48 -0
  85. package/src/components/ui/scroll-area.tsx +55 -0
  86. package/src/components/ui/select.tsx +199 -0
  87. package/src/components/ui/separator.tsx +25 -0
  88. package/src/components/ui/sheet.tsx +136 -0
  89. package/src/components/ui/sidebar.tsx +723 -0
  90. package/src/components/ui/skeleton.tsx +13 -0
  91. package/src/components/ui/slider.tsx +52 -0
  92. package/src/components/ui/sonner.tsx +47 -0
  93. package/src/components/ui/switch.tsx +32 -0
  94. package/src/components/ui/table.tsx +114 -0
  95. package/src/components/ui/tabs.tsx +82 -0
  96. package/src/components/ui/textarea.tsx +18 -0
  97. package/src/components/ui/toggle-group.tsx +87 -0
  98. package/src/components/ui/toggle.tsx +43 -0
  99. package/src/components/ui/tooltip.tsx +66 -0
  100. package/src/hooks/use-mobile.ts +19 -0
  101. package/src/index.tsx +17 -0
  102. package/src/lib/utils.ts +19 -0
  103. package/src/pages/blog-posts/create.tsx +177 -0
  104. package/src/pages/blog-posts/edit.tsx +197 -0
  105. package/src/pages/blog-posts/index.ts +4 -0
  106. package/src/pages/blog-posts/list.tsx +131 -0
  107. package/src/pages/blog-posts/show.tsx +81 -0
  108. package/src/pages/categories/create.tsx +73 -0
  109. package/src/pages/categories/edit.tsx +73 -0
  110. package/src/pages/categories/index.ts +4 -0
  111. package/src/pages/categories/list.tsx +86 -0
  112. package/src/pages/categories/show.tsx +37 -0
  113. package/src/pages/forgot-password/index.tsx +6 -0
  114. package/src/pages/forgotPassword/index.tsx +5 -0
  115. package/src/pages/login/index.tsx +5 -0
  116. package/src/pages/register/index.tsx +5 -0
  117. package/src/providers/auth.ts +204 -0
  118. package/src/providers/constants.ts +75 -0
  119. package/src/providers/data.ts +232 -0
  120. package/src/vite-env.d.ts +1 -0
  121. package/tsconfig.json +25 -0
  122. package/tsconfig.node.json +21 -0
  123. package/vite.config.ts +74 -0
@@ -0,0 +1,91 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function Popover({ ...props }: PopoverPrimitive.Root.Props) {
9
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
10
+ }
11
+
12
+ function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props) {
13
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
14
+ }
15
+
16
+ function PopoverContent({
17
+ className,
18
+ align = "center",
19
+ alignOffset = 0,
20
+ side = "bottom",
21
+ sideOffset = 4,
22
+ keepMounted,
23
+ ...props
24
+ }: PopoverPrimitive.Popup.Props &
25
+ Pick<
26
+ PopoverPrimitive.Positioner.Props,
27
+ "align" | "alignOffset" | "side" | "sideOffset"
28
+ > & { keepMounted?: boolean }) {
29
+ return (
30
+ <PopoverPrimitive.Portal keepMounted={keepMounted}>
31
+ <PopoverPrimitive.Positioner
32
+ align={align}
33
+ alignOffset={alignOffset}
34
+ side={side}
35
+ sideOffset={sideOffset}
36
+ className="isolate z-50"
37
+ >
38
+ <PopoverPrimitive.Popup
39
+ data-slot="popover-content"
40
+ className={cn(
41
+ "z-50 flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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 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",
42
+ className
43
+ )}
44
+ {...props}
45
+ />
46
+ </PopoverPrimitive.Positioner>
47
+ </PopoverPrimitive.Portal>
48
+ )
49
+ }
50
+
51
+ function PopoverHeader({ className, ...props }: React.ComponentProps<"div">) {
52
+ return (
53
+ <div
54
+ data-slot="popover-header"
55
+ className={cn("flex flex-col gap-0.5 text-sm", className)}
56
+ {...props}
57
+ />
58
+ )
59
+ }
60
+
61
+ function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props) {
62
+ return (
63
+ <PopoverPrimitive.Title
64
+ data-slot="popover-title"
65
+ className={cn("font-medium", className)}
66
+ {...props}
67
+ />
68
+ )
69
+ }
70
+
71
+ function PopoverDescription({
72
+ className,
73
+ ...props
74
+ }: PopoverPrimitive.Description.Props) {
75
+ return (
76
+ <PopoverPrimitive.Description
77
+ data-slot="popover-description"
78
+ className={cn("text-muted-foreground", className)}
79
+ {...props}
80
+ />
81
+ )
82
+ }
83
+
84
+ export {
85
+ Popover,
86
+ PopoverContent,
87
+ PopoverDescription,
88
+ PopoverHeader,
89
+ PopoverTitle,
90
+ PopoverTrigger,
91
+ }
@@ -0,0 +1,81 @@
1
+ import { Progress as ProgressPrimitive } from "@base-ui/react/progress"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function Progress({
6
+ className,
7
+ children,
8
+ value,
9
+ ...props
10
+ }: ProgressPrimitive.Root.Props) {
11
+ return (
12
+ <ProgressPrimitive.Root
13
+ value={value}
14
+ data-slot="progress"
15
+ className={cn("flex flex-wrap gap-3", className)}
16
+ {...props}
17
+ >
18
+ {children}
19
+ <ProgressTrack>
20
+ <ProgressIndicator />
21
+ </ProgressTrack>
22
+ </ProgressPrimitive.Root>
23
+ )
24
+ }
25
+
26
+ function ProgressTrack({ className, ...props }: ProgressPrimitive.Track.Props) {
27
+ return (
28
+ <ProgressPrimitive.Track
29
+ className={cn(
30
+ "relative flex h-1 w-full items-center overflow-x-hidden rounded-full bg-muted",
31
+ className
32
+ )}
33
+ data-slot="progress-track"
34
+ {...props}
35
+ />
36
+ )
37
+ }
38
+
39
+ function ProgressIndicator({
40
+ className,
41
+ ...props
42
+ }: ProgressPrimitive.Indicator.Props) {
43
+ return (
44
+ <ProgressPrimitive.Indicator
45
+ data-slot="progress-indicator"
46
+ className={cn("h-full bg-primary transition-all", className)}
47
+ {...props}
48
+ />
49
+ )
50
+ }
51
+
52
+ function ProgressLabel({ className, ...props }: ProgressPrimitive.Label.Props) {
53
+ return (
54
+ <ProgressPrimitive.Label
55
+ className={cn("text-sm font-medium", className)}
56
+ data-slot="progress-label"
57
+ {...props}
58
+ />
59
+ )
60
+ }
61
+
62
+ function ProgressValue({ className, ...props }: ProgressPrimitive.Value.Props) {
63
+ return (
64
+ <ProgressPrimitive.Value
65
+ className={cn(
66
+ "ml-auto text-sm text-muted-foreground tabular-nums",
67
+ className
68
+ )}
69
+ data-slot="progress-value"
70
+ {...props}
71
+ />
72
+ )
73
+ }
74
+
75
+ export {
76
+ Progress,
77
+ ProgressTrack,
78
+ ProgressIndicator,
79
+ ProgressLabel,
80
+ ProgressValue,
81
+ }
@@ -0,0 +1,38 @@
1
+ "use client"
2
+
3
+ import { Radio as RadioPrimitive } from "@base-ui/react/radio"
4
+ import { RadioGroup as RadioGroupPrimitive } from "@base-ui/react/radio-group"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props) {
9
+ return (
10
+ <RadioGroupPrimitive
11
+ data-slot="radio-group"
12
+ className={cn("grid w-full gap-2", className)}
13
+ {...props}
14
+ />
15
+ )
16
+ }
17
+
18
+ function RadioGroupItem({ className, ...props }: RadioPrimitive.Root.Props) {
19
+ return (
20
+ <RadioPrimitive.Root
21
+ data-slot="radio-group-item"
22
+ className={cn(
23
+ "group/radio-group-item peer relative flex aspect-square size-4 shrink-0 rounded-full border border-input outline-none after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
24
+ className
25
+ )}
26
+ {...props}
27
+ >
28
+ <RadioPrimitive.Indicator
29
+ data-slot="radio-group-indicator"
30
+ className="flex size-4 items-center justify-center"
31
+ >
32
+ <span className="absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2 rounded-full bg-primary-foreground" />
33
+ </RadioPrimitive.Indicator>
34
+ </RadioPrimitive.Root>
35
+ )
36
+ }
37
+
38
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1,48 @@
1
+ import * as ResizablePrimitive from "react-resizable-panels"
2
+
3
+ import { cn } from "@/lib/utils"
4
+
5
+ function ResizablePanelGroup({
6
+ className,
7
+ ...props
8
+ }: ResizablePrimitive.GroupProps) {
9
+ return (
10
+ <ResizablePrimitive.Group
11
+ data-slot="resizable-panel-group"
12
+ className={cn(
13
+ "flex h-full w-full aria-[orientation=vertical]:flex-col",
14
+ className
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ function ResizablePanel({ ...props }: ResizablePrimitive.PanelProps) {
22
+ return <ResizablePrimitive.Panel data-slot="resizable-panel" {...props} />
23
+ }
24
+
25
+ function ResizableHandle({
26
+ withHandle,
27
+ className,
28
+ ...props
29
+ }: ResizablePrimitive.SeparatorProps & {
30
+ withHandle?: boolean
31
+ }) {
32
+ return (
33
+ <ResizablePrimitive.Separator
34
+ data-slot="resizable-handle"
35
+ className={cn(
36
+ "relative flex w-px items-center justify-center bg-border ring-offset-background after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-hidden aria-[orientation=horizontal]:h-px aria-[orientation=horizontal]:w-full aria-[orientation=horizontal]:after:left-0 aria-[orientation=horizontal]:after:h-1 aria-[orientation=horizontal]:after:w-full aria-[orientation=horizontal]:after:translate-x-0 aria-[orientation=horizontal]:after:-translate-y-1/2 [&[aria-orientation=horizontal]>div]:rotate-90",
37
+ className
38
+ )}
39
+ {...props}
40
+ >
41
+ {withHandle && (
42
+ <div className="z-10 flex h-6 w-1 shrink-0 rounded-lg bg-border" />
43
+ )}
44
+ </ResizablePrimitive.Separator>
45
+ )
46
+ }
47
+
48
+ export { ResizableHandle, ResizablePanel, ResizablePanelGroup }
@@ -0,0 +1,55 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area"
5
+
6
+ import { cn } from "@/lib/utils"
7
+
8
+ function ScrollArea({
9
+ className,
10
+ children,
11
+ ...props
12
+ }: ScrollAreaPrimitive.Root.Props) {
13
+ return (
14
+ <ScrollAreaPrimitive.Root
15
+ data-slot="scroll-area"
16
+ className={cn("relative", className)}
17
+ {...props}
18
+ >
19
+ <ScrollAreaPrimitive.Viewport
20
+ data-slot="scroll-area-viewport"
21
+ className="size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1"
22
+ >
23
+ {children}
24
+ </ScrollAreaPrimitive.Viewport>
25
+ <ScrollBar />
26
+ <ScrollAreaPrimitive.Corner />
27
+ </ScrollAreaPrimitive.Root>
28
+ )
29
+ }
30
+
31
+ function ScrollBar({
32
+ className,
33
+ orientation = "vertical",
34
+ ...props
35
+ }: ScrollAreaPrimitive.Scrollbar.Props) {
36
+ return (
37
+ <ScrollAreaPrimitive.Scrollbar
38
+ data-slot="scroll-area-scrollbar"
39
+ data-orientation={orientation}
40
+ orientation={orientation}
41
+ className={cn(
42
+ "flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-l data-vertical:border-l-transparent",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ <ScrollAreaPrimitive.Thumb
48
+ data-slot="scroll-area-thumb"
49
+ className="relative flex-1 rounded-full bg-border"
50
+ />
51
+ </ScrollAreaPrimitive.Scrollbar>
52
+ )
53
+ }
54
+
55
+ export { ScrollArea, ScrollBar }
@@ -0,0 +1,199 @@
1
+ import * as React from "react"
2
+ import { Select as SelectPrimitive } from "@base-ui/react/select"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { ChevronDownIcon, CheckIcon, ChevronUpIcon } from "lucide-react"
6
+
7
+ const Select = SelectPrimitive.Root
8
+
9
+ function SelectGroup({ className, ...props }: SelectPrimitive.Group.Props) {
10
+ return (
11
+ <SelectPrimitive.Group
12
+ data-slot="select-group"
13
+ className={cn("scroll-my-1 p-1", className)}
14
+ {...props}
15
+ />
16
+ )
17
+ }
18
+
19
+ function SelectValue({ className, ...props }: SelectPrimitive.Value.Props) {
20
+ return (
21
+ <SelectPrimitive.Value
22
+ data-slot="select-value"
23
+ className={cn("flex flex-1 text-left", className)}
24
+ {...props}
25
+ />
26
+ )
27
+ }
28
+
29
+ function SelectTrigger({
30
+ className,
31
+ size = "default",
32
+ children,
33
+ ...props
34
+ }: SelectPrimitive.Trigger.Props & {
35
+ size?: "sm" | "default"
36
+ }) {
37
+ return (
38
+ <SelectPrimitive.Trigger
39
+ data-slot="select-trigger"
40
+ data-size={size}
41
+ className={cn(
42
+ "flex w-fit items-center justify-between gap-1.5 rounded-lg border border-input bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ {children}
48
+ <SelectPrimitive.Icon
49
+ render={
50
+ <ChevronDownIcon className="pointer-events-none size-4 text-muted-foreground" />
51
+ }
52
+ />
53
+ </SelectPrimitive.Trigger>
54
+ )
55
+ }
56
+
57
+ function SelectContent({
58
+ className,
59
+ children,
60
+ side = "bottom",
61
+ sideOffset = 4,
62
+ align = "start",
63
+ alignOffset = 0,
64
+ alignItemWithTrigger = false,
65
+ ...props
66
+ }: SelectPrimitive.Popup.Props &
67
+ Pick<
68
+ SelectPrimitive.Positioner.Props,
69
+ "align" | "alignOffset" | "side" | "sideOffset" | "alignItemWithTrigger"
70
+ >) {
71
+ return (
72
+ <SelectPrimitive.Portal>
73
+ <SelectPrimitive.Positioner
74
+ side={side}
75
+ sideOffset={sideOffset}
76
+ align={align}
77
+ alignOffset={alignOffset}
78
+ alignItemWithTrigger={alignItemWithTrigger}
79
+ className="isolate z-50"
80
+ >
81
+ <SelectPrimitive.Popup
82
+ data-slot="select-content"
83
+ data-align-trigger={alignItemWithTrigger}
84
+ className={cn("relative isolate z-50 max-h-(--available-height) w-max min-w-(--anchor-width) max-w-(--available-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 data-[align-trigger=true]:animate-none data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-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 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", className )}
85
+ {...props}
86
+ >
87
+ <SelectScrollUpButton />
88
+ <SelectPrimitive.List>{children}</SelectPrimitive.List>
89
+ <SelectScrollDownButton />
90
+ </SelectPrimitive.Popup>
91
+ </SelectPrimitive.Positioner>
92
+ </SelectPrimitive.Portal>
93
+ )
94
+ }
95
+
96
+ function SelectLabel({
97
+ className,
98
+ ...props
99
+ }: SelectPrimitive.GroupLabel.Props) {
100
+ return (
101
+ <SelectPrimitive.GroupLabel
102
+ data-slot="select-label"
103
+ className={cn("px-1.5 py-1 text-xs text-muted-foreground", className)}
104
+ {...props}
105
+ />
106
+ )
107
+ }
108
+
109
+ function SelectItem({
110
+ className,
111
+ children,
112
+ ...props
113
+ }: SelectPrimitive.Item.Props) {
114
+ return (
115
+ <SelectPrimitive.Item
116
+ data-slot="select-item"
117
+ className={cn(
118
+ "relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
119
+ className
120
+ )}
121
+ {...props}
122
+ >
123
+ <SelectPrimitive.ItemText className="flex min-w-0 flex-1 gap-2 whitespace-normal break-words">
124
+ {children}
125
+ </SelectPrimitive.ItemText>
126
+ <SelectPrimitive.ItemIndicator
127
+ render={
128
+ <span className="pointer-events-none absolute right-2 flex size-4 items-center justify-center" />
129
+ }
130
+ >
131
+ <CheckIcon className="pointer-events-none" />
132
+ </SelectPrimitive.ItemIndicator>
133
+ </SelectPrimitive.Item>
134
+ )
135
+ }
136
+
137
+ function SelectSeparator({
138
+ className,
139
+ ...props
140
+ }: SelectPrimitive.Separator.Props) {
141
+ return (
142
+ <SelectPrimitive.Separator
143
+ data-slot="select-separator"
144
+ className={cn("pointer-events-none -mx-1 my-1 h-px bg-border", className)}
145
+ {...props}
146
+ />
147
+ )
148
+ }
149
+
150
+ function SelectScrollUpButton({
151
+ className,
152
+ ...props
153
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollUpArrow>) {
154
+ return (
155
+ <SelectPrimitive.ScrollUpArrow
156
+ data-slot="select-scroll-up-button"
157
+ className={cn(
158
+ "top-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
159
+ className
160
+ )}
161
+ {...props}
162
+ >
163
+ <ChevronUpIcon
164
+ />
165
+ </SelectPrimitive.ScrollUpArrow>
166
+ )
167
+ }
168
+
169
+ function SelectScrollDownButton({
170
+ className,
171
+ ...props
172
+ }: React.ComponentProps<typeof SelectPrimitive.ScrollDownArrow>) {
173
+ return (
174
+ <SelectPrimitive.ScrollDownArrow
175
+ data-slot="select-scroll-down-button"
176
+ className={cn(
177
+ "bottom-0 z-10 flex w-full cursor-default items-center justify-center bg-popover py-1 [&_svg:not([class*='size-'])]:size-4",
178
+ className
179
+ )}
180
+ {...props}
181
+ >
182
+ <ChevronDownIcon
183
+ />
184
+ </SelectPrimitive.ScrollDownArrow>
185
+ )
186
+ }
187
+
188
+ export {
189
+ Select,
190
+ SelectContent,
191
+ SelectGroup,
192
+ SelectItem,
193
+ SelectLabel,
194
+ SelectScrollDownButton,
195
+ SelectScrollUpButton,
196
+ SelectSeparator,
197
+ SelectTrigger,
198
+ SelectValue,
199
+ }
@@ -0,0 +1,25 @@
1
+ "use client"
2
+
3
+ import { Separator as SeparatorPrimitive } from "@base-ui/react/separator"
4
+
5
+ import { cn } from "@/lib/utils"
6
+
7
+ function Separator({
8
+ className,
9
+ orientation = "horizontal",
10
+ ...props
11
+ }: SeparatorPrimitive.Props) {
12
+ return (
13
+ <SeparatorPrimitive
14
+ data-slot="separator"
15
+ orientation={orientation}
16
+ className={cn(
17
+ "shrink-0 bg-border data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch",
18
+ className
19
+ )}
20
+ {...props}
21
+ />
22
+ )
23
+ }
24
+
25
+ export { Separator }
@@ -0,0 +1,136 @@
1
+ import * as React from "react"
2
+ import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
3
+
4
+ import { cn } from "@/lib/utils"
5
+ import { Button } from "@/components/ui/button"
6
+ import { XIcon } from "lucide-react"
7
+
8
+ function Sheet({ ...props }: SheetPrimitive.Root.Props) {
9
+ return <SheetPrimitive.Root data-slot="sheet" {...props} />
10
+ }
11
+
12
+ function SheetTrigger({ ...props }: SheetPrimitive.Trigger.Props) {
13
+ return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />
14
+ }
15
+
16
+ function SheetClose({ ...props }: SheetPrimitive.Close.Props) {
17
+ return <SheetPrimitive.Close data-slot="sheet-close" {...props} />
18
+ }
19
+
20
+ function SheetPortal({ ...props }: SheetPrimitive.Portal.Props) {
21
+ return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />
22
+ }
23
+
24
+ function SheetOverlay({ className, ...props }: SheetPrimitive.Backdrop.Props) {
25
+ return (
26
+ <SheetPrimitive.Backdrop
27
+ data-slot="sheet-overlay"
28
+ className={cn(
29
+ "fixed inset-0 z-50 bg-black/10 transition-opacity duration-150 data-ending-style:opacity-0 data-starting-style:opacity-0 supports-backdrop-filter:backdrop-blur-xs",
30
+ className
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ function SheetContent({
38
+ className,
39
+ children,
40
+ side = "right",
41
+ showCloseButton = true,
42
+ ...props
43
+ }: SheetPrimitive.Popup.Props & {
44
+ side?: "top" | "right" | "bottom" | "left"
45
+ showCloseButton?: boolean
46
+ }) {
47
+ return (
48
+ <SheetPortal>
49
+ <SheetOverlay />
50
+ <SheetPrimitive.Popup
51
+ data-slot="sheet-content"
52
+ data-side={side}
53
+ className={cn(
54
+ "fixed z-50 flex flex-col gap-4 bg-popover bg-clip-padding text-sm text-popover-foreground shadow-lg transition duration-200 ease-in-out data-ending-style:opacity-0 data-starting-style:opacity-0 data-[side=bottom]:inset-x-0 data-[side=bottom]:bottom-0 data-[side=bottom]:h-auto data-[side=bottom]:border-t data-[side=bottom]:data-ending-style:translate-y-[2.5rem] data-[side=bottom]:data-starting-style:translate-y-[2.5rem] data-[side=left]:inset-y-0 data-[side=left]:left-0 data-[side=left]:h-full data-[side=left]:w-3/4 data-[side=left]:border-r data-[side=left]:data-ending-style:translate-x-[-2.5rem] data-[side=left]:data-starting-style:translate-x-[-2.5rem] data-[side=right]:inset-y-0 data-[side=right]:right-0 data-[side=right]:h-full data-[side=right]:w-3/4 data-[side=right]:border-l data-[side=right]:data-ending-style:translate-x-[2.5rem] data-[side=right]:data-starting-style:translate-x-[2.5rem] data-[side=top]:inset-x-0 data-[side=top]:top-0 data-[side=top]:h-auto data-[side=top]:border-b data-[side=top]:data-ending-style:translate-y-[-2.5rem] data-[side=top]:data-starting-style:translate-y-[-2.5rem] data-[side=left]:sm:max-w-sm data-[side=right]:sm:max-w-sm",
55
+ className
56
+ )}
57
+ {...props}
58
+ >
59
+ {children}
60
+ {showCloseButton && (
61
+ <SheetPrimitive.Close
62
+ data-slot="sheet-close"
63
+ render={
64
+ <Button
65
+ variant="ghost"
66
+ className="absolute top-3 right-3"
67
+ size="icon-sm"
68
+ />
69
+ }
70
+ >
71
+ <XIcon
72
+ />
73
+ <span className="sr-only">Close</span>
74
+ </SheetPrimitive.Close>
75
+ )}
76
+ </SheetPrimitive.Popup>
77
+ </SheetPortal>
78
+ )
79
+ }
80
+
81
+ function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
82
+ return (
83
+ <div
84
+ data-slot="sheet-header"
85
+ className={cn("flex flex-col gap-0.5 p-4", className)}
86
+ {...props}
87
+ />
88
+ )
89
+ }
90
+
91
+ function SheetFooter({ className, ...props }: React.ComponentProps<"div">) {
92
+ return (
93
+ <div
94
+ data-slot="sheet-footer"
95
+ className={cn("mt-auto flex flex-col gap-2 p-4", className)}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ function SheetTitle({ className, ...props }: SheetPrimitive.Title.Props) {
102
+ return (
103
+ <SheetPrimitive.Title
104
+ data-slot="sheet-title"
105
+ className={cn(
106
+ "font-heading text-base font-medium text-foreground",
107
+ className
108
+ )}
109
+ {...props}
110
+ />
111
+ )
112
+ }
113
+
114
+ function SheetDescription({
115
+ className,
116
+ ...props
117
+ }: SheetPrimitive.Description.Props) {
118
+ return (
119
+ <SheetPrimitive.Description
120
+ data-slot="sheet-description"
121
+ className={cn("text-sm text-muted-foreground", className)}
122
+ {...props}
123
+ />
124
+ )
125
+ }
126
+
127
+ export {
128
+ Sheet,
129
+ SheetTrigger,
130
+ SheetClose,
131
+ SheetContent,
132
+ SheetHeader,
133
+ SheetFooter,
134
+ SheetTitle,
135
+ SheetDescription,
136
+ }