bsign-customization-full 0.0.1

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 (126) hide show
  1. package/.env +2 -0
  2. package/components.json +21 -0
  3. package/dist/colors/anthracite-gray.webp +0 -0
  4. package/dist/colors/anthracite-gray_50x50.png +0 -0
  5. package/dist/colors/dark-wenge.webp +0 -0
  6. package/dist/colors/dark-wenge_50x50.png +0 -0
  7. package/dist/colors/indian-rosewood.webp +0 -0
  8. package/dist/colors/indian-rosewood_50x50.png +0 -0
  9. package/dist/colors/natural-wood.webp +0 -0
  10. package/dist/colors/natural-wood_50x50.png +0 -0
  11. package/dist/colors/redwood.webp +0 -0
  12. package/dist/colors/redwood_50x50.png +0 -0
  13. package/dist/colors/walnut.webp +0 -0
  14. package/dist/colors/walnut_50x50.png +0 -0
  15. package/dist/html2canvas.esm-BJ_egzt0.js +4802 -0
  16. package/dist/index-Dw5Zc1iD.js +33162 -0
  17. package/dist/index.es-Co1KNpGS.js +6681 -0
  18. package/dist/logo.png +0 -0
  19. package/dist/purify.es-CKpD2xIC.js +552 -0
  20. package/dist/sign-constructor.es.js +4 -0
  21. package/dist/sign-constructor.iife.js +171 -0
  22. package/dist/size-guide.webp +0 -0
  23. package/dist/size.webp +0 -0
  24. package/dist/templates/assets/modern/rectangle-black.webp +0 -0
  25. package/dist/templates/assets/modern/rectangle-white.webp +0 -0
  26. package/dist/templates/assets/modern/square-black.webp +0 -0
  27. package/dist/templates/assets/modern/square-white.webp +0 -0
  28. package/dist/templates/assets/wave.webp +0 -0
  29. package/dist/templates/jure.webp +0 -0
  30. package/dist/templates/modern.webp +0 -0
  31. package/dist/templates/sherwood.webp +0 -0
  32. package/dist/templates/wave.webp +0 -0
  33. package/eslint.config.js +23 -0
  34. package/index.html +13 -0
  35. package/modern-debug.svg +39 -0
  36. package/package.json +62 -0
  37. package/public/colors/anthracite-gray.webp +0 -0
  38. package/public/colors/anthracite-gray_50x50.png +0 -0
  39. package/public/colors/dark-wenge.webp +0 -0
  40. package/public/colors/dark-wenge_50x50.png +0 -0
  41. package/public/colors/indian-rosewood.webp +0 -0
  42. package/public/colors/indian-rosewood_50x50.png +0 -0
  43. package/public/colors/natural-wood.webp +0 -0
  44. package/public/colors/natural-wood_50x50.png +0 -0
  45. package/public/colors/redwood.webp +0 -0
  46. package/public/colors/redwood_50x50.png +0 -0
  47. package/public/colors/walnut.webp +0 -0
  48. package/public/colors/walnut_50x50.png +0 -0
  49. package/public/logo.png +0 -0
  50. package/public/size-guide.webp +0 -0
  51. package/public/size.webp +0 -0
  52. package/public/templates/assets/modern/rectangle-black.webp +0 -0
  53. package/public/templates/assets/modern/rectangle-white.webp +0 -0
  54. package/public/templates/assets/modern/square-black.webp +0 -0
  55. package/public/templates/assets/modern/square-white.webp +0 -0
  56. package/public/templates/assets/wave.webp +0 -0
  57. package/public/templates/jure.webp +0 -0
  58. package/public/templates/modern.webp +0 -0
  59. package/public/templates/sherwood.webp +0 -0
  60. package/public/templates/wave.webp +0 -0
  61. package/src/App.css +43 -0
  62. package/src/AppDemo2.tsx +257 -0
  63. package/src/components/cart-panel.tsx +170 -0
  64. package/src/components/cart-preview.tsx +356 -0
  65. package/src/components/cart-view.tsx +113 -0
  66. package/src/components/constructure-menu.tsx +37 -0
  67. package/src/components/header.tsx +214 -0
  68. package/src/components/heading.tsx +28 -0
  69. package/src/components/icons.tsx +54 -0
  70. package/src/components/import-file-modal.tsx +252 -0
  71. package/src/components/layers/grid-view.tsx +29 -0
  72. package/src/components/layers/image-layer.tsx +128 -0
  73. package/src/components/layers/layer-forms/material-form.tsx +53 -0
  74. package/src/components/layers/layer-forms/size-form.tsx +69 -0
  75. package/src/components/layers/layer-forms/template-form.tsx +39 -0
  76. package/src/components/layers/layer-forms/text-form.tsx +477 -0
  77. package/src/components/layers/layers-container.tsx +259 -0
  78. package/src/components/layers/text-layer.tsx +128 -0
  79. package/src/components/movable-item.tsx +228 -0
  80. package/src/components/preview.tsx +258 -0
  81. package/src/components/resize-button.tsx +83 -0
  82. package/src/components/size-guide-modal.tsx +47 -0
  83. package/src/components/size-guide.tsx +98 -0
  84. package/src/components/ui/button-group.tsx +83 -0
  85. package/src/components/ui/button.tsx +60 -0
  86. package/src/components/ui/checkbox.tsx +30 -0
  87. package/src/components/ui/dialog.tsx +151 -0
  88. package/src/components/ui/input-group.tsx +168 -0
  89. package/src/components/ui/input.tsx +21 -0
  90. package/src/components/ui/label.tsx +22 -0
  91. package/src/components/ui/popover.tsx +54 -0
  92. package/src/components/ui/progress.tsx +28 -0
  93. package/src/components/ui/radio-group.tsx +43 -0
  94. package/src/components/ui/scroll-area.tsx +56 -0
  95. package/src/components/ui/select.tsx +191 -0
  96. package/src/components/ui/separator.tsx +25 -0
  97. package/src/components/ui/sheet.tsx +141 -0
  98. package/src/components/ui/slider.tsx +61 -0
  99. package/src/components/ui/spinner.tsx +15 -0
  100. package/src/components/ui/textarea.tsx +18 -0
  101. package/src/components/ui/toggle-group.tsx +73 -0
  102. package/src/components/ui/toggle.tsx +45 -0
  103. package/src/components/ui/tooltip.tsx +67 -0
  104. package/src/fonts/BEBASNEUE-REGULAR.TTF +0 -0
  105. package/src/fonts/Braille-Regular.ttf +0 -0
  106. package/src/fonts/GOTHICB.TTF +0 -0
  107. package/src/hooks/use-mobile.ts +23 -0
  108. package/src/hooks/use-resize-constraints.ts +62 -0
  109. package/src/index.css +238 -0
  110. package/src/index.tsx +141 -0
  111. package/src/lib/cart-proposal-pdf.ts +350 -0
  112. package/src/lib/config-font.tsx +109 -0
  113. package/src/lib/config.ts +730 -0
  114. package/src/lib/pricing.ts +61 -0
  115. package/src/lib/type-checks.ts +47 -0
  116. package/src/lib/utils.ts +146 -0
  117. package/src/lib/widget-context.tsx +9 -0
  118. package/src/main.tsx +11 -0
  119. package/src/store/cart-store.ts +78 -0
  120. package/src/store/layers-store.ts +337 -0
  121. package/src/vite-env.d.ts +1 -0
  122. package/test/preview.html +37 -0
  123. package/tsconfig.app.json +33 -0
  124. package/tsconfig.json +13 -0
  125. package/tsconfig.node.json +25 -0
  126. package/vite.config.ts +38 -0
@@ -0,0 +1,151 @@
1
+ import * as React from "react"
2
+ import * as DialogPrimitive from "@radix-ui/react-dialog"
3
+ import { XIcon } from "lucide-react"
4
+
5
+ import { cn } from "../../lib/utils"
6
+ import { useWidgetPortalContainer } from "../../lib/widget-context"
7
+
8
+ function Dialog({
9
+ ...props
10
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
11
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />
12
+ }
13
+
14
+ function DialogTrigger({
15
+ ...props
16
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
17
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />
18
+ }
19
+
20
+ function DialogPortal({
21
+ container,
22
+ ...props
23
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
24
+ const portalContainer = useWidgetPortalContainer()
25
+
26
+ return (
27
+ <DialogPrimitive.Portal
28
+ data-slot="dialog-portal"
29
+ container={container ?? portalContainer ?? undefined}
30
+ {...props}
31
+ />
32
+ )
33
+ }
34
+
35
+ function DialogClose({
36
+ ...props
37
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
38
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />
39
+ }
40
+
41
+ function DialogOverlay({
42
+ className,
43
+ ...props
44
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
45
+ return (
46
+ <DialogPrimitive.Overlay
47
+ data-slot="dialog-overlay"
48
+ className={cn(
49
+ "data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50",
50
+ className
51
+ )}
52
+ {...props}
53
+ />
54
+ )
55
+ }
56
+
57
+ function DialogContent({
58
+ className,
59
+ children,
60
+ showCloseButton = true,
61
+ ...props
62
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
63
+ showCloseButton?: boolean
64
+ }) {
65
+ return (
66
+ <DialogPortal data-slot="dialog-portal">
67
+ <DialogOverlay />
68
+ <DialogPrimitive.Content
69
+ data-slot="dialog-content"
70
+ className={cn(
71
+ "bg-background 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 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg",
72
+ className
73
+ )}
74
+ {...props}
75
+ >
76
+ {children}
77
+ {showCloseButton && (
78
+ <DialogPrimitive.Close
79
+ data-slot="dialog-close"
80
+ className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
81
+ >
82
+ <XIcon />
83
+ <span className="sr-only">Close</span>
84
+ </DialogPrimitive.Close>
85
+ )}
86
+ </DialogPrimitive.Content>
87
+ </DialogPortal>
88
+ )
89
+ }
90
+
91
+ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
92
+ return (
93
+ <div
94
+ data-slot="dialog-header"
95
+ className={cn("flex flex-col gap-2 text-center sm:text-left", className)}
96
+ {...props}
97
+ />
98
+ )
99
+ }
100
+
101
+ function DialogFooter({ className, ...props }: React.ComponentProps<"div">) {
102
+ return (
103
+ <div
104
+ data-slot="dialog-footer"
105
+ className={cn(
106
+ "flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",
107
+ className
108
+ )}
109
+ {...props}
110
+ />
111
+ )
112
+ }
113
+
114
+ function DialogTitle({
115
+ className,
116
+ ...props
117
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
118
+ return (
119
+ <DialogPrimitive.Title
120
+ data-slot="dialog-title"
121
+ className={cn("text-lg leading-none font-semibold", className)}
122
+ {...props}
123
+ />
124
+ )
125
+ }
126
+
127
+ function DialogDescription({
128
+ className,
129
+ ...props
130
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
131
+ return (
132
+ <DialogPrimitive.Description
133
+ data-slot="dialog-description"
134
+ className={cn("text-muted-foreground text-sm", className)}
135
+ {...props}
136
+ />
137
+ )
138
+ }
139
+
140
+ export {
141
+ Dialog,
142
+ DialogClose,
143
+ DialogContent,
144
+ DialogDescription,
145
+ DialogFooter,
146
+ DialogHeader,
147
+ DialogOverlay,
148
+ DialogPortal,
149
+ DialogTitle,
150
+ DialogTrigger,
151
+ }
@@ -0,0 +1,168 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+
4
+ import { cn } from "../../lib/utils"
5
+ import { Button } from "./button"
6
+ import { Input } from "./input"
7
+ import { Textarea } from "./textarea"
8
+
9
+ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
10
+ return (
11
+ <div
12
+ data-slot="input-group"
13
+ role="group"
14
+ className={cn(
15
+ "group/input-group border-input dark:bg-input/30 relative flex w-full items-center rounded-md border shadow-xs transition-[color,box-shadow] outline-none",
16
+ "h-9 min-w-0 has-[>textarea]:h-auto",
17
+
18
+ // Variants based on alignment.
19
+ "has-[>[data-align=inline-start]]:[&>input]:pl-2",
20
+ "has-[>[data-align=inline-end]]:[&>input]:pr-2",
21
+ "has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3",
22
+ "has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3",
23
+
24
+ // Focus state.
25
+ "has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot=input-group-control]:focus-visible]:ring-[3px]",
26
+
27
+ // Error state.
28
+ "has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[[data-slot][aria-invalid=true]]:border-destructive dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40",
29
+
30
+ className
31
+ )}
32
+ {...props}
33
+ />
34
+ )
35
+ }
36
+
37
+ const inputGroupAddonVariants = cva(
38
+ "text-muted-foreground flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium select-none [&>svg:not([class*='size-'])]:size-4 [&>kbd]:rounded-[calc(var(--radius)-5px)] group-data-[disabled=true]/input-group:opacity-50",
39
+ {
40
+ variants: {
41
+ align: {
42
+ "inline-start":
43
+ "order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]",
44
+ "inline-end":
45
+ "order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
46
+ "block-start":
47
+ "order-first w-full justify-start px-3 pt-3 [.border-b]:pb-3 group-has-[>input]/input-group:pt-2.5",
48
+ "block-end":
49
+ "order-last w-full justify-start px-3 pb-3 [.border-t]:pt-3 group-has-[>input]/input-group:pb-2.5",
50
+ },
51
+ },
52
+ defaultVariants: {
53
+ align: "inline-start",
54
+ },
55
+ }
56
+ )
57
+
58
+ function InputGroupAddon({
59
+ className,
60
+ align = "inline-start",
61
+ ...props
62
+ }: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
63
+ return (
64
+ <div
65
+ role="group"
66
+ data-slot="input-group-addon"
67
+ data-align={align}
68
+ className={cn(inputGroupAddonVariants({ align }), className)}
69
+ onClick={(e) => {
70
+ if ((e.target as HTMLElement).closest("button")) {
71
+ return
72
+ }
73
+ e.currentTarget.parentElement?.querySelector("input")?.focus()
74
+ }}
75
+ {...props}
76
+ />
77
+ )
78
+ }
79
+
80
+ const inputGroupButtonVariants = cva(
81
+ "text-sm shadow-none flex gap-2 items-center order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]",
82
+ {
83
+ variants: {
84
+ size: {
85
+ xs: "h-6 gap-1 px-2 rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-3.5 has-[>svg]:px-2",
86
+ sm: "h-8 px-2.5 gap-1.5 rounded-md has-[>svg]:px-2.5",
87
+ "icon-xs":
88
+ "size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0",
89
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0",
90
+ },
91
+ },
92
+ defaultVariants: {
93
+ size: "xs",
94
+ },
95
+ }
96
+ )
97
+
98
+ function InputGroupButton({
99
+ className,
100
+ type = "button",
101
+ variant = "ghost",
102
+ size = "xs",
103
+ ...props
104
+ }: Omit<React.ComponentProps<typeof Button>, "size"> &
105
+ VariantProps<typeof inputGroupButtonVariants>) {
106
+ return (
107
+ <Button
108
+ type={type}
109
+ data-size={size}
110
+ variant={variant}
111
+ className={cn(inputGroupButtonVariants({ size }), className)}
112
+ {...props}
113
+ />
114
+ )
115
+ }
116
+
117
+ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
118
+ return (
119
+ <span
120
+ className={cn(
121
+ "text-muted-foreground flex items-center gap-2 text-sm [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
122
+ className
123
+ )}
124
+ {...props}
125
+ />
126
+ )
127
+ }
128
+
129
+ function InputGroupInput({
130
+ className,
131
+ ...props
132
+ }: React.ComponentProps<"input">) {
133
+ return (
134
+ <Input
135
+ data-slot="input-group-control"
136
+ className={cn(
137
+ "flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent",
138
+ className
139
+ )}
140
+ {...props}
141
+ />
142
+ )
143
+ }
144
+
145
+ function InputGroupTextarea({
146
+ className,
147
+ ...props
148
+ }: React.ComponentProps<"textarea">) {
149
+ return (
150
+ <Textarea
151
+ data-slot="input-group-control"
152
+ className={cn(
153
+ "flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent",
154
+ className
155
+ )}
156
+ {...props}
157
+ />
158
+ )
159
+ }
160
+
161
+ export {
162
+ InputGroup,
163
+ InputGroupAddon,
164
+ InputGroupButton,
165
+ InputGroupText,
166
+ InputGroupInput,
167
+ InputGroupTextarea,
168
+ }
@@ -0,0 +1,21 @@
1
+ import * as React from "react"
2
+
3
+ import { cn } from "../../lib/utils"
4
+
5
+ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
6
+ return (
7
+ <input
8
+ type={type}
9
+ data-slot="input"
10
+ className={cn(
11
+ "file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
12
+ "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
13
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
14
+ className
15
+ )}
16
+ {...props}
17
+ />
18
+ )
19
+ }
20
+
21
+ export { Input }
@@ -0,0 +1,22 @@
1
+ import * as React from "react"
2
+ import * as LabelPrimitive from "@radix-ui/react-label"
3
+
4
+ import { cn } from "../../lib/utils"
5
+
6
+ function Label({
7
+ className,
8
+ ...props
9
+ }: React.ComponentProps<typeof LabelPrimitive.Root>) {
10
+ return (
11
+ <LabelPrimitive.Root
12
+ data-slot="label"
13
+ className={cn(
14
+ "flex text-[#8F8F8F] items-center gap-2 text-sm leading-none select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
15
+ className
16
+ )}
17
+ {...props}
18
+ />
19
+ )
20
+ }
21
+
22
+ export { Label }
@@ -0,0 +1,54 @@
1
+ import * as React from "react"
2
+ import * as PopoverPrimitive from "@radix-ui/react-popover"
3
+
4
+ import { cn } from "../../lib/utils"
5
+ import { useWidgetPortalContainer } from "../../lib/widget-context"
6
+
7
+ function Popover({
8
+ ...props
9
+ }: React.ComponentProps<typeof PopoverPrimitive.Root>) {
10
+ return <PopoverPrimitive.Root data-slot="popover" {...props} />
11
+ }
12
+
13
+ function PopoverTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
16
+ return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
17
+ }
18
+
19
+ function PopoverContent({
20
+ className,
21
+ align = "center",
22
+ sideOffset = 4,
23
+ portalContainer,
24
+ ...props
25
+ }: React.ComponentProps<typeof PopoverPrimitive.Content> & {
26
+ portalContainer?: HTMLElement | null
27
+ }) {
28
+ const contextPortalContainer = useWidgetPortalContainer()
29
+ const resolvedPortalContainer =
30
+ portalContainer ?? contextPortalContainer ?? undefined
31
+
32
+ return (
33
+ <PopoverPrimitive.Portal container={resolvedPortalContainer}>
34
+ <PopoverPrimitive.Content
35
+ data-slot="popover-content"
36
+ align={align}
37
+ sideOffset={sideOffset}
38
+ className={cn(
39
+ "bg-popover text-popover-foreground 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 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
40
+ className
41
+ )}
42
+ {...props}
43
+ />
44
+ </PopoverPrimitive.Portal>
45
+ )
46
+ }
47
+
48
+ function PopoverAnchor({
49
+ ...props
50
+ }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
51
+ return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
52
+ }
53
+
54
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
@@ -0,0 +1,28 @@
1
+ import * as React from "react"
2
+ import * as ProgressPrimitive from "@radix-ui/react-progress"
3
+ import { cn } from "../../lib/utils"
4
+
5
+ function Progress({
6
+ className,
7
+ value,
8
+ ...props
9
+ }: React.ComponentProps<typeof ProgressPrimitive.Root>) {
10
+ return (
11
+ <ProgressPrimitive.Root
12
+ data-slot="progress"
13
+ className={cn(
14
+ "bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
15
+ className
16
+ )}
17
+ {...props}
18
+ >
19
+ <ProgressPrimitive.Indicator
20
+ data-slot="progress-indicator"
21
+ className="bg-primary h-full w-full flex-1 transition-all"
22
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
23
+ />
24
+ </ProgressPrimitive.Root>
25
+ )
26
+ }
27
+
28
+ export { Progress }
@@ -0,0 +1,43 @@
1
+ import * as React from "react"
2
+ import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
3
+ import { CircleIcon } from "lucide-react"
4
+
5
+ import { cn } from "../../lib/utils"
6
+
7
+ function RadioGroup({
8
+ className,
9
+ ...props
10
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
11
+ return (
12
+ <RadioGroupPrimitive.Root
13
+ data-slot="radio-group"
14
+ className={cn("grid gap-3", className)}
15
+ {...props}
16
+ />
17
+ )
18
+ }
19
+
20
+ function RadioGroupItem({
21
+ className,
22
+ ...props
23
+ }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
24
+ return (
25
+ <RadioGroupPrimitive.Item
26
+ data-slot="radio-group-item"
27
+ className={cn(
28
+ "border-input text-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 aspect-square size-4 shrink-0 rounded-full border shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
29
+ className
30
+ )}
31
+ {...props}
32
+ >
33
+ <RadioGroupPrimitive.Indicator
34
+ data-slot="radio-group-indicator"
35
+ className="relative flex items-center justify-center"
36
+ >
37
+ <CircleIcon className="fill-primary absolute top-1/2 left-1/2 size-2 -translate-x-1/2 -translate-y-1/2" />
38
+ </RadioGroupPrimitive.Indicator>
39
+ </RadioGroupPrimitive.Item>
40
+ )
41
+ }
42
+
43
+ export { RadioGroup, RadioGroupItem }
@@ -0,0 +1,56 @@
1
+ import * as React from "react"
2
+ import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
3
+
4
+ import { cn } from "../../lib/utils"
5
+
6
+ function ScrollArea({
7
+ className,
8
+ children,
9
+ ...props
10
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
11
+ return (
12
+ <ScrollAreaPrimitive.Root
13
+ data-slot="scroll-area"
14
+ className={cn("relative", className)}
15
+ {...props}
16
+ >
17
+ <ScrollAreaPrimitive.Viewport
18
+ data-slot="scroll-area-viewport"
19
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
20
+ >
21
+ {children}
22
+ </ScrollAreaPrimitive.Viewport>
23
+ <ScrollBar />
24
+ <ScrollAreaPrimitive.Corner />
25
+ </ScrollAreaPrimitive.Root>
26
+ )
27
+ }
28
+
29
+ function ScrollBar({
30
+ className,
31
+ orientation = "vertical",
32
+ ...props
33
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
34
+ return (
35
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
36
+ data-slot="scroll-area-scrollbar"
37
+ orientation={orientation}
38
+ className={cn(
39
+ "flex touch-none p-px transition-colors select-none",
40
+ orientation === "vertical" &&
41
+ "h-full w-2.5 border-l border-l-transparent",
42
+ orientation === "horizontal" &&
43
+ "h-2.5 flex-col border-t border-t-transparent",
44
+ className
45
+ )}
46
+ {...props}
47
+ >
48
+ <ScrollAreaPrimitive.ScrollAreaThumb
49
+ data-slot="scroll-area-thumb"
50
+ className="bg-border relative flex-1 rounded-full"
51
+ />
52
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
53
+ )
54
+ }
55
+
56
+ export { ScrollArea, ScrollBar }