create-davepi-ui 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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +29 -0
  3. package/bin/index.js +229 -0
  4. package/bin/sync-templates.js +100 -0
  5. package/package.json +40 -0
  6. package/templates/default/.env.example +1 -0
  7. package/templates/default/index.html +13 -0
  8. package/templates/default/package.json +49 -0
  9. package/templates/default/postcss.config.cjs +6 -0
  10. package/templates/default/src/App.tsx +42 -0
  11. package/templates/default/src/components/AppShell.tsx +23 -0
  12. package/templates/default/src/components/BulkActionBar.tsx +47 -0
  13. package/templates/default/src/components/RelatedCreateModal.tsx +91 -0
  14. package/templates/default/src/components/RelatedList.tsx +70 -0
  15. package/templates/default/src/components/ResourceForm.tsx +311 -0
  16. package/templates/default/src/components/ResourceTable.tsx +475 -0
  17. package/templates/default/src/components/RowActions.tsx +54 -0
  18. package/templates/default/src/components/Sidebar.tsx +171 -0
  19. package/templates/default/src/components/ui/button.tsx +43 -0
  20. package/templates/default/src/components/ui/card.tsx +47 -0
  21. package/templates/default/src/components/ui/checkbox.tsx +24 -0
  22. package/templates/default/src/components/ui/command.tsx +117 -0
  23. package/templates/default/src/components/ui/dialog.tsx +95 -0
  24. package/templates/default/src/components/ui/dropdown-menu.tsx +78 -0
  25. package/templates/default/src/components/ui/input.tsx +18 -0
  26. package/templates/default/src/components/ui/label.tsx +17 -0
  27. package/templates/default/src/components/ui/popover.tsx +27 -0
  28. package/templates/default/src/components/ui/select.tsx +83 -0
  29. package/templates/default/src/components/ui/switch.tsx +21 -0
  30. package/templates/default/src/components/ui/table.tsx +66 -0
  31. package/templates/default/src/components/ui/tabs.tsx +53 -0
  32. package/templates/default/src/components/ui/textarea.tsx +17 -0
  33. package/templates/default/src/davepi-ui.config.ts +14 -0
  34. package/templates/default/src/index.css +55 -0
  35. package/templates/default/src/lib/utils.ts +10 -0
  36. package/templates/default/src/main.tsx +34 -0
  37. package/templates/default/src/pages/DashboardPage.tsx +42 -0
  38. package/templates/default/src/pages/LoginScreen.tsx +77 -0
  39. package/templates/default/src/pages/ResourceCreatePage.tsx +58 -0
  40. package/templates/default/src/pages/ResourceDetailPage.tsx +171 -0
  41. package/templates/default/src/pages/ResourceEditPage.tsx +52 -0
  42. package/templates/default/src/pages/ResourceListPage.tsx +8 -0
  43. package/templates/default/src/resourceOverrides.ts +34 -0
  44. package/templates/default/src/resources/account.ts +25 -0
  45. package/templates/default/src/resources/category.ts +7 -0
  46. package/templates/default/src/resources/contact.ts +40 -0
  47. package/templates/default/src/resources/product.ts +7 -0
  48. package/templates/default/src/resources/project.ts +7 -0
  49. package/templates/default/src/resources/quote.ts +12 -0
  50. package/templates/default/src/vite-env.d.ts +9 -0
  51. package/templates/default/src/widgets/CurrencyInput.tsx +44 -0
  52. package/templates/default/src/widgets/DateInput.tsx +36 -0
  53. package/templates/default/src/widgets/EmailInput.tsx +28 -0
  54. package/templates/default/src/widgets/EnumSelect.tsx +35 -0
  55. package/templates/default/src/widgets/FileUploaderStub.tsx +9 -0
  56. package/templates/default/src/widgets/JsonEditor.tsx +64 -0
  57. package/templates/default/src/widgets/NumberInput.tsx +36 -0
  58. package/templates/default/src/widgets/RelationPicker.tsx +349 -0
  59. package/templates/default/src/widgets/SwitchWidget.tsx +20 -0
  60. package/templates/default/src/widgets/TagInput.tsx +83 -0
  61. package/templates/default/src/widgets/TextAreaWidget.tsx +27 -0
  62. package/templates/default/src/widgets/TextInput.tsx +32 -0
  63. package/templates/default/src/widgets/UrlInput.tsx +27 -0
  64. package/templates/default/src/widgets/registry.ts +51 -0
  65. package/templates/default/src/widgets/types.ts +26 -0
  66. package/templates/default/tailwind.config.ts +54 -0
  67. package/templates/default/tsconfig.json +40 -0
  68. package/templates/default/vite.config.ts +16 -0
  69. package/templates/pinned-versions.json +5 -0
@@ -0,0 +1,43 @@
1
+ import { forwardRef, type ButtonHTMLAttributes } from 'react';
2
+ import { Slot } from '@radix-ui/react-slot';
3
+ import { cva, type VariantProps } from 'class-variance-authority';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ const buttonVariants = cva(
7
+ 'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'bg-primary text-primary-foreground hover:bg-primary/90',
12
+ destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
13
+ outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
14
+ secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
15
+ ghost: 'hover:bg-accent hover:text-accent-foreground',
16
+ link: 'text-primary underline-offset-4 hover:underline',
17
+ },
18
+ size: {
19
+ default: 'h-10 px-4 py-2',
20
+ sm: 'h-9 rounded-md px-3',
21
+ lg: 'h-11 rounded-md px-8',
22
+ icon: 'h-10 w-10',
23
+ },
24
+ },
25
+ defaultVariants: { variant: 'default', size: 'default' },
26
+ }
27
+ );
28
+
29
+ export interface ButtonProps
30
+ extends ButtonHTMLAttributes<HTMLButtonElement>,
31
+ VariantProps<typeof buttonVariants> {
32
+ asChild?: boolean;
33
+ }
34
+
35
+ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
36
+ { className, variant, size, asChild = false, ...props },
37
+ ref
38
+ ) {
39
+ const Comp = asChild ? Slot : 'button';
40
+ return <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />;
41
+ });
42
+
43
+ export { buttonVariants };
@@ -0,0 +1,47 @@
1
+ import { forwardRef, type HTMLAttributes } from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ export const Card = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
5
+ function Card({ className, ...props }, ref) {
6
+ return (
7
+ <div
8
+ ref={ref}
9
+ className={cn(
10
+ 'rounded-lg border bg-card text-card-foreground shadow-sm',
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+ );
18
+
19
+ export const CardHeader = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
20
+ function CardHeader({ className, ...props }, ref) {
21
+ return <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />;
22
+ }
23
+ );
24
+
25
+ export const CardTitle = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
26
+ function CardTitle({ className, ...props }, ref) {
27
+ return (
28
+ <h3
29
+ ref={ref}
30
+ className={cn('text-lg font-semibold leading-none tracking-tight', className)}
31
+ {...(props as HTMLAttributes<HTMLHeadingElement>)}
32
+ />
33
+ );
34
+ }
35
+ );
36
+
37
+ export const CardContent = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
38
+ function CardContent({ className, ...props }, ref) {
39
+ return <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />;
40
+ }
41
+ );
42
+
43
+ export const CardFooter = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
44
+ function CardFooter({ className, ...props }, ref) {
45
+ return <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />;
46
+ }
47
+ );
@@ -0,0 +1,24 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import * as CheckboxPrimitive from '@radix-ui/react-checkbox';
3
+ import { Check } from 'lucide-react';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ export const Checkbox = forwardRef<
7
+ ElementRef<typeof CheckboxPrimitive.Root>,
8
+ ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
9
+ >(function Checkbox({ className, ...props }, ref) {
10
+ return (
11
+ <CheckboxPrimitive.Root
12
+ ref={ref}
13
+ className={cn(
14
+ 'peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground',
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <CheckboxPrimitive.Indicator className="flex items-center justify-center text-current">
20
+ <Check className="h-4 w-4" />
21
+ </CheckboxPrimitive.Indicator>
22
+ </CheckboxPrimitive.Root>
23
+ );
24
+ });
@@ -0,0 +1,117 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import { Command as CommandPrimitive } from 'cmdk';
3
+ import { Search } from 'lucide-react';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ export const Command = forwardRef<
7
+ ElementRef<typeof CommandPrimitive>,
8
+ ComponentPropsWithoutRef<typeof CommandPrimitive>
9
+ >(function Command({ className, ...props }, ref) {
10
+ return (
11
+ <CommandPrimitive
12
+ ref={ref}
13
+ className={cn(
14
+ 'flex h-full w-full flex-col overflow-hidden rounded-md bg-popover text-popover-foreground',
15
+ className
16
+ )}
17
+ {...props}
18
+ />
19
+ );
20
+ });
21
+
22
+ export const CommandInput = forwardRef<
23
+ ElementRef<typeof CommandPrimitive.Input>,
24
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
25
+ >(function CommandInput({ className, ...props }, ref) {
26
+ return (
27
+ <div className="flex items-center border-b px-3" cmdk-input-wrapper="">
28
+ <Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
29
+ <CommandPrimitive.Input
30
+ ref={ref}
31
+ className={cn(
32
+ 'flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50',
33
+ className
34
+ )}
35
+ {...props}
36
+ />
37
+ </div>
38
+ );
39
+ });
40
+
41
+ export const CommandList = forwardRef<
42
+ ElementRef<typeof CommandPrimitive.List>,
43
+ ComponentPropsWithoutRef<typeof CommandPrimitive.List>
44
+ >(function CommandList({ className, ...props }, ref) {
45
+ return (
46
+ <CommandPrimitive.List
47
+ ref={ref}
48
+ className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
49
+ {...props}
50
+ />
51
+ );
52
+ });
53
+
54
+ export const CommandEmpty = forwardRef<
55
+ ElementRef<typeof CommandPrimitive.Empty>,
56
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
57
+ >(function CommandEmpty(props, ref) {
58
+ return <CommandPrimitive.Empty ref={ref} className="py-6 text-center text-sm" {...props} />;
59
+ });
60
+
61
+ export const CommandGroup = forwardRef<
62
+ ElementRef<typeof CommandPrimitive.Group>,
63
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
64
+ >(function CommandGroup({ className, ...props }, ref) {
65
+ return (
66
+ <CommandPrimitive.Group
67
+ ref={ref}
68
+ className={cn(
69
+ 'overflow-hidden p-1 text-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground',
70
+ className
71
+ )}
72
+ {...props}
73
+ />
74
+ );
75
+ });
76
+
77
+ export const CommandSeparator = forwardRef<
78
+ ElementRef<typeof CommandPrimitive.Separator>,
79
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
80
+ >(function CommandSeparator({ className, ...props }, ref) {
81
+ return (
82
+ <CommandPrimitive.Separator
83
+ ref={ref}
84
+ className={cn('-mx-1 h-px bg-border', className)}
85
+ {...props}
86
+ />
87
+ );
88
+ });
89
+
90
+ export const CommandItem = forwardRef<
91
+ ElementRef<typeof CommandPrimitive.Item>,
92
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
93
+ >(function CommandItem({ className, ...props }, ref) {
94
+ return (
95
+ <CommandPrimitive.Item
96
+ ref={ref}
97
+ className={cn(
98
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[selected='true']:bg-accent data-[selected=true]:text-accent-foreground data-[disabled=true]:opacity-50",
99
+ className
100
+ )}
101
+ {...props}
102
+ />
103
+ );
104
+ });
105
+
106
+ export const CommandLoading = forwardRef<
107
+ ElementRef<typeof CommandPrimitive.Loading>,
108
+ ComponentPropsWithoutRef<typeof CommandPrimitive.Loading>
109
+ >(function CommandLoading(props, ref) {
110
+ return (
111
+ <CommandPrimitive.Loading
112
+ ref={ref}
113
+ className="py-6 text-center text-sm text-muted-foreground"
114
+ {...props}
115
+ />
116
+ );
117
+ });
@@ -0,0 +1,95 @@
1
+ import {
2
+ forwardRef,
3
+ type ComponentPropsWithoutRef,
4
+ type ElementRef,
5
+ type HTMLAttributes,
6
+ } from 'react';
7
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
8
+ import { X } from 'lucide-react';
9
+ import { cn } from '@/lib/utils';
10
+
11
+ export const Dialog = DialogPrimitive.Root;
12
+ export const DialogTrigger = DialogPrimitive.Trigger;
13
+ export const DialogPortal = DialogPrimitive.Portal;
14
+ export const DialogClose = DialogPrimitive.Close;
15
+
16
+ const DialogOverlay = forwardRef<
17
+ ElementRef<typeof DialogPrimitive.Overlay>,
18
+ ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
19
+ >(function DialogOverlay({ className, ...props }, ref) {
20
+ return (
21
+ <DialogPrimitive.Overlay
22
+ ref={ref}
23
+ className={cn(
24
+ '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',
25
+ className
26
+ )}
27
+ {...props}
28
+ />
29
+ );
30
+ });
31
+
32
+ export const DialogContent = forwardRef<
33
+ ElementRef<typeof DialogPrimitive.Content>,
34
+ ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
35
+ >(function DialogContent({ className, children, ...props }, ref) {
36
+ return (
37
+ <DialogPortal>
38
+ <DialogOverlay />
39
+ <DialogPrimitive.Content
40
+ ref={ref}
41
+ className={cn(
42
+ '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 sm:rounded-lg',
43
+ className
44
+ )}
45
+ {...props}
46
+ >
47
+ {children}
48
+ <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">
49
+ <X className="h-4 w-4" />
50
+ <span className="sr-only">Close</span>
51
+ </DialogPrimitive.Close>
52
+ </DialogPrimitive.Content>
53
+ </DialogPortal>
54
+ );
55
+ });
56
+
57
+ export const DialogHeader = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
58
+ <div
59
+ className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)}
60
+ {...props}
61
+ />
62
+ );
63
+
64
+ export const DialogFooter = ({ className, ...props }: HTMLAttributes<HTMLDivElement>) => (
65
+ <div
66
+ className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
67
+ {...props}
68
+ />
69
+ );
70
+
71
+ export const DialogTitle = forwardRef<
72
+ ElementRef<typeof DialogPrimitive.Title>,
73
+ ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
74
+ >(function DialogTitle({ className, ...props }, ref) {
75
+ return (
76
+ <DialogPrimitive.Title
77
+ ref={ref}
78
+ className={cn('text-lg font-semibold leading-none tracking-tight', className)}
79
+ {...props}
80
+ />
81
+ );
82
+ });
83
+
84
+ export const DialogDescription = forwardRef<
85
+ ElementRef<typeof DialogPrimitive.Description>,
86
+ ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
87
+ >(function DialogDescription({ className, ...props }, ref) {
88
+ return (
89
+ <DialogPrimitive.Description
90
+ ref={ref}
91
+ className={cn('text-sm text-muted-foreground', className)}
92
+ {...props}
93
+ />
94
+ );
95
+ });
@@ -0,0 +1,78 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
3
+ import { Check, ChevronRight } from 'lucide-react';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ export const DropdownMenu = DropdownMenuPrimitive.Root;
7
+ export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
8
+ export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
9
+ export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
10
+
11
+ export const DropdownMenuContent = forwardRef<
12
+ ElementRef<typeof DropdownMenuPrimitive.Content>,
13
+ ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
14
+ >(function DropdownMenuContent({ className, sideOffset = 4, ...props }, ref) {
15
+ return (
16
+ <DropdownMenuPrimitive.Portal>
17
+ <DropdownMenuPrimitive.Content
18
+ ref={ref}
19
+ sideOffset={sideOffset}
20
+ className={cn(
21
+ 'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
22
+ className
23
+ )}
24
+ {...props}
25
+ />
26
+ </DropdownMenuPrimitive.Portal>
27
+ );
28
+ });
29
+
30
+ export const DropdownMenuItem = forwardRef<
31
+ ElementRef<typeof DropdownMenuPrimitive.Item>,
32
+ ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { inset?: boolean }
33
+ >(function DropdownMenuItem({ className, inset, ...props }, ref) {
34
+ return (
35
+ <DropdownMenuPrimitive.Item
36
+ ref={ref}
37
+ className={cn(
38
+ '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',
39
+ inset && 'pl-8',
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ );
45
+ });
46
+
47
+ export const DropdownMenuSeparator = forwardRef<
48
+ ElementRef<typeof DropdownMenuPrimitive.Separator>,
49
+ ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
50
+ >(function DropdownMenuSeparator({ className, ...props }, ref) {
51
+ return (
52
+ <DropdownMenuPrimitive.Separator
53
+ ref={ref}
54
+ className={cn('-mx-1 my-1 h-px bg-muted', className)}
55
+ {...props}
56
+ />
57
+ );
58
+ });
59
+
60
+ export const DropdownMenuLabel = forwardRef<
61
+ ElementRef<typeof DropdownMenuPrimitive.Label>,
62
+ ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }
63
+ >(function DropdownMenuLabel({ className, inset, ...props }, ref) {
64
+ return (
65
+ <DropdownMenuPrimitive.Label
66
+ ref={ref}
67
+ className={cn(
68
+ 'px-2 py-1.5 text-xs font-medium text-muted-foreground',
69
+ inset && 'pl-8',
70
+ className
71
+ )}
72
+ {...props}
73
+ />
74
+ );
75
+ });
76
+
77
+ // Re-export icons used by consumers building menus.
78
+ export { Check, ChevronRight };
@@ -0,0 +1,18 @@
1
+ import { forwardRef, type InputHTMLAttributes } from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ export const Input = forwardRef<HTMLInputElement, InputHTMLAttributes<HTMLInputElement>>(
5
+ function Input({ className, type, ...props }, ref) {
6
+ return (
7
+ <input
8
+ ref={ref}
9
+ type={type}
10
+ className={cn(
11
+ 'flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background 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',
12
+ className
13
+ )}
14
+ {...props}
15
+ />
16
+ );
17
+ }
18
+ );
@@ -0,0 +1,17 @@
1
+ import { forwardRef, type LabelHTMLAttributes } from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ export const Label = forwardRef<HTMLLabelElement, LabelHTMLAttributes<HTMLLabelElement>>(
5
+ function Label({ className, ...props }, ref) {
6
+ return (
7
+ <label
8
+ ref={ref}
9
+ className={cn(
10
+ 'text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70',
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+ );
@@ -0,0 +1,27 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import * as PopoverPrimitive from '@radix-ui/react-popover';
3
+ import { cn } from '@/lib/utils';
4
+
5
+ export const Popover = PopoverPrimitive.Root;
6
+ export const PopoverTrigger = PopoverPrimitive.Trigger;
7
+ export const PopoverAnchor = PopoverPrimitive.Anchor;
8
+
9
+ export const PopoverContent = forwardRef<
10
+ ElementRef<typeof PopoverPrimitive.Content>,
11
+ ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
12
+ >(function PopoverContent({ className, align = 'start', sideOffset = 4, ...props }, ref) {
13
+ return (
14
+ <PopoverPrimitive.Portal>
15
+ <PopoverPrimitive.Content
16
+ ref={ref}
17
+ align={align}
18
+ sideOffset={sideOffset}
19
+ className={cn(
20
+ 'z-50 w-72 rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-none',
21
+ className
22
+ )}
23
+ {...props}
24
+ />
25
+ </PopoverPrimitive.Portal>
26
+ );
27
+ });
@@ -0,0 +1,83 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import * as SelectPrimitive from '@radix-ui/react-select';
3
+ import { Check, ChevronDown } from 'lucide-react';
4
+ import { cn } from '@/lib/utils';
5
+
6
+ export const Select = SelectPrimitive.Root;
7
+ export const SelectGroup = SelectPrimitive.Group;
8
+ export const SelectValue = SelectPrimitive.Value;
9
+
10
+ export const SelectTrigger = forwardRef<
11
+ ElementRef<typeof SelectPrimitive.Trigger>,
12
+ ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
13
+ >(function SelectTrigger({ className, children, ...props }, ref) {
14
+ return (
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
+ });
30
+
31
+ export const SelectContent = forwardRef<
32
+ ElementRef<typeof SelectPrimitive.Content>,
33
+ ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
34
+ >(function SelectContent({ className, children, position = 'popper', ...props }, ref) {
35
+ return (
36
+ <SelectPrimitive.Portal>
37
+ <SelectPrimitive.Content
38
+ ref={ref}
39
+ className={cn(
40
+ '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',
41
+ position === 'popper' &&
42
+ 'data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1',
43
+ className
44
+ )}
45
+ position={position}
46
+ {...props}
47
+ >
48
+ <SelectPrimitive.Viewport
49
+ className={cn(
50
+ 'p-1',
51
+ position === 'popper' &&
52
+ 'h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]'
53
+ )}
54
+ >
55
+ {children}
56
+ </SelectPrimitive.Viewport>
57
+ </SelectPrimitive.Content>
58
+ </SelectPrimitive.Portal>
59
+ );
60
+ });
61
+
62
+ export const SelectItem = forwardRef<
63
+ ElementRef<typeof SelectPrimitive.Item>,
64
+ ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
65
+ >(function SelectItem({ className, children, ...props }, ref) {
66
+ return (
67
+ <SelectPrimitive.Item
68
+ ref={ref}
69
+ className={cn(
70
+ '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',
71
+ className
72
+ )}
73
+ {...props}
74
+ >
75
+ <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
76
+ <SelectPrimitive.ItemIndicator>
77
+ <Check className="h-4 w-4" />
78
+ </SelectPrimitive.ItemIndicator>
79
+ </span>
80
+ <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
81
+ </SelectPrimitive.Item>
82
+ );
83
+ });
@@ -0,0 +1,21 @@
1
+ import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from 'react';
2
+ import * as SwitchPrimitives from '@radix-ui/react-switch';
3
+ import { cn } from '@/lib/utils';
4
+
5
+ export const Switch = forwardRef<
6
+ ElementRef<typeof SwitchPrimitives.Root>,
7
+ ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
8
+ >(function Switch({ className, ...props }, ref) {
9
+ return (
10
+ <SwitchPrimitives.Root
11
+ ref={ref}
12
+ className={cn(
13
+ 'peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input',
14
+ className
15
+ )}
16
+ {...props}
17
+ >
18
+ <SwitchPrimitives.Thumb className="pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-5 data-[state=unchecked]:translate-x-0" />
19
+ </SwitchPrimitives.Root>
20
+ );
21
+ });
@@ -0,0 +1,66 @@
1
+ import { forwardRef, type HTMLAttributes, type TdHTMLAttributes, type ThHTMLAttributes } from 'react';
2
+ import { cn } from '@/lib/utils';
3
+
4
+ export const Table = forwardRef<HTMLTableElement, HTMLAttributes<HTMLTableElement>>(
5
+ function Table({ className, ...props }, ref) {
6
+ return (
7
+ <div className="relative w-full overflow-auto">
8
+ <table ref={ref} className={cn('w-full caption-bottom text-sm', className)} {...props} />
9
+ </div>
10
+ );
11
+ }
12
+ );
13
+
14
+ export const TableHeader = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(
15
+ function TableHeader({ className, ...props }, ref) {
16
+ return <thead ref={ref} className={cn('[&_tr]:border-b', className)} {...props} />;
17
+ }
18
+ );
19
+
20
+ export const TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(
21
+ function TableBody({ className, ...props }, ref) {
22
+ return <tbody ref={ref} className={cn('[&_tr:last-child]:border-0', className)} {...props} />;
23
+ }
24
+ );
25
+
26
+ export const TableRow = forwardRef<HTMLTableRowElement, HTMLAttributes<HTMLTableRowElement>>(
27
+ function TableRow({ className, ...props }, ref) {
28
+ return (
29
+ <tr
30
+ ref={ref}
31
+ className={cn(
32
+ 'border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted',
33
+ className
34
+ )}
35
+ {...props}
36
+ />
37
+ );
38
+ }
39
+ );
40
+
41
+ export const TableHead = forwardRef<HTMLTableCellElement, ThHTMLAttributes<HTMLTableCellElement>>(
42
+ function TableHead({ className, ...props }, ref) {
43
+ return (
44
+ <th
45
+ ref={ref}
46
+ className={cn(
47
+ 'h-10 px-3 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0',
48
+ className
49
+ )}
50
+ {...props}
51
+ />
52
+ );
53
+ }
54
+ );
55
+
56
+ export const TableCell = forwardRef<HTMLTableCellElement, TdHTMLAttributes<HTMLTableCellElement>>(
57
+ function TableCell({ className, ...props }, ref) {
58
+ return (
59
+ <td
60
+ ref={ref}
61
+ className={cn('p-3 align-middle [&:has([role=checkbox])]:pr-0', className)}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+ );