@gmickel/gno 0.3.4 → 0.4.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 (57) hide show
  1. package/README.md +194 -53
  2. package/assets/badges/license.svg +12 -0
  3. package/assets/badges/npm.svg +13 -0
  4. package/assets/badges/twitter.svg +22 -0
  5. package/assets/badges/website.svg +22 -0
  6. package/package.json +30 -1
  7. package/src/cli/commands/ask.ts +11 -186
  8. package/src/cli/commands/models/pull.ts +9 -4
  9. package/src/cli/commands/serve.ts +19 -0
  10. package/src/cli/program.ts +28 -0
  11. package/src/llm/registry.ts +3 -1
  12. package/src/pipeline/answer.ts +191 -0
  13. package/src/serve/CLAUDE.md +91 -0
  14. package/src/serve/bunfig.toml +2 -0
  15. package/src/serve/context.ts +181 -0
  16. package/src/serve/index.ts +7 -0
  17. package/src/serve/public/app.tsx +56 -0
  18. package/src/serve/public/components/ai-elements/code-block.tsx +176 -0
  19. package/src/serve/public/components/ai-elements/conversation.tsx +98 -0
  20. package/src/serve/public/components/ai-elements/inline-citation.tsx +285 -0
  21. package/src/serve/public/components/ai-elements/loader.tsx +96 -0
  22. package/src/serve/public/components/ai-elements/message.tsx +443 -0
  23. package/src/serve/public/components/ai-elements/prompt-input.tsx +1421 -0
  24. package/src/serve/public/components/ai-elements/sources.tsx +75 -0
  25. package/src/serve/public/components/ai-elements/suggestion.tsx +51 -0
  26. package/src/serve/public/components/preset-selector.tsx +403 -0
  27. package/src/serve/public/components/ui/badge.tsx +46 -0
  28. package/src/serve/public/components/ui/button-group.tsx +82 -0
  29. package/src/serve/public/components/ui/button.tsx +62 -0
  30. package/src/serve/public/components/ui/card.tsx +92 -0
  31. package/src/serve/public/components/ui/carousel.tsx +244 -0
  32. package/src/serve/public/components/ui/collapsible.tsx +31 -0
  33. package/src/serve/public/components/ui/command.tsx +181 -0
  34. package/src/serve/public/components/ui/dialog.tsx +141 -0
  35. package/src/serve/public/components/ui/dropdown-menu.tsx +255 -0
  36. package/src/serve/public/components/ui/hover-card.tsx +42 -0
  37. package/src/serve/public/components/ui/input-group.tsx +167 -0
  38. package/src/serve/public/components/ui/input.tsx +21 -0
  39. package/src/serve/public/components/ui/progress.tsx +28 -0
  40. package/src/serve/public/components/ui/scroll-area.tsx +56 -0
  41. package/src/serve/public/components/ui/select.tsx +188 -0
  42. package/src/serve/public/components/ui/separator.tsx +26 -0
  43. package/src/serve/public/components/ui/table.tsx +114 -0
  44. package/src/serve/public/components/ui/textarea.tsx +18 -0
  45. package/src/serve/public/components/ui/tooltip.tsx +59 -0
  46. package/src/serve/public/globals.css +226 -0
  47. package/src/serve/public/hooks/use-api.ts +112 -0
  48. package/src/serve/public/index.html +13 -0
  49. package/src/serve/public/pages/Ask.tsx +442 -0
  50. package/src/serve/public/pages/Browse.tsx +270 -0
  51. package/src/serve/public/pages/Dashboard.tsx +202 -0
  52. package/src/serve/public/pages/DocView.tsx +302 -0
  53. package/src/serve/public/pages/Search.tsx +335 -0
  54. package/src/serve/routes/api.ts +763 -0
  55. package/src/serve/server.ts +249 -0
  56. package/src/store/sqlite/adapter.ts +47 -0
  57. package/src/store/types.ts +10 -0
@@ -0,0 +1,141 @@
1
+ import * as DialogPrimitive from '@radix-ui/react-dialog';
2
+ import { XIcon } from 'lucide-react';
3
+ import type * as React from 'react';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ function Dialog({
8
+ ...props
9
+ }: React.ComponentProps<typeof DialogPrimitive.Root>) {
10
+ return <DialogPrimitive.Root data-slot="dialog" {...props} />;
11
+ }
12
+
13
+ function DialogTrigger({
14
+ ...props
15
+ }: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
16
+ return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
17
+ }
18
+
19
+ function DialogPortal({
20
+ ...props
21
+ }: React.ComponentProps<typeof DialogPrimitive.Portal>) {
22
+ return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
23
+ }
24
+
25
+ function DialogClose({
26
+ ...props
27
+ }: React.ComponentProps<typeof DialogPrimitive.Close>) {
28
+ return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
29
+ }
30
+
31
+ function DialogOverlay({
32
+ className,
33
+ ...props
34
+ }: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
35
+ return (
36
+ <DialogPrimitive.Overlay
37
+ className={cn(
38
+ 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=open]:animate-in',
39
+ className
40
+ )}
41
+ data-slot="dialog-overlay"
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ function DialogContent({
48
+ className,
49
+ children,
50
+ showCloseButton = true,
51
+ ...props
52
+ }: React.ComponentProps<typeof DialogPrimitive.Content> & {
53
+ showCloseButton?: boolean;
54
+ }) {
55
+ return (
56
+ <DialogPortal data-slot="dialog-portal">
57
+ <DialogOverlay />
58
+ <DialogPrimitive.Content
59
+ className={cn(
60
+ '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 bg-background p-6 shadow-lg outline-none duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:max-w-lg',
61
+ className
62
+ )}
63
+ data-slot="dialog-content"
64
+ {...props}
65
+ >
66
+ {children}
67
+ {showCloseButton && (
68
+ <DialogPrimitive.Close
69
+ className="absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden 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 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0"
70
+ data-slot="dialog-close"
71
+ >
72
+ <XIcon />
73
+ <span className="sr-only">Close</span>
74
+ </DialogPrimitive.Close>
75
+ )}
76
+ </DialogPrimitive.Content>
77
+ </DialogPortal>
78
+ );
79
+ }
80
+
81
+ function DialogHeader({ className, ...props }: React.ComponentProps<'div'>) {
82
+ return (
83
+ <div
84
+ className={cn('flex flex-col gap-2 text-center sm:text-left', className)}
85
+ data-slot="dialog-header"
86
+ {...props}
87
+ />
88
+ );
89
+ }
90
+
91
+ function DialogFooter({ className, ...props }: React.ComponentProps<'div'>) {
92
+ return (
93
+ <div
94
+ className={cn(
95
+ 'flex flex-col-reverse gap-2 sm:flex-row sm:justify-end',
96
+ className
97
+ )}
98
+ data-slot="dialog-footer"
99
+ {...props}
100
+ />
101
+ );
102
+ }
103
+
104
+ function DialogTitle({
105
+ className,
106
+ ...props
107
+ }: React.ComponentProps<typeof DialogPrimitive.Title>) {
108
+ return (
109
+ <DialogPrimitive.Title
110
+ className={cn('font-semibold text-lg leading-none', className)}
111
+ data-slot="dialog-title"
112
+ {...props}
113
+ />
114
+ );
115
+ }
116
+
117
+ function DialogDescription({
118
+ className,
119
+ ...props
120
+ }: React.ComponentProps<typeof DialogPrimitive.Description>) {
121
+ return (
122
+ <DialogPrimitive.Description
123
+ className={cn('text-muted-foreground text-sm', className)}
124
+ data-slot="dialog-description"
125
+ {...props}
126
+ />
127
+ );
128
+ }
129
+
130
+ export {
131
+ Dialog,
132
+ DialogClose,
133
+ DialogContent,
134
+ DialogDescription,
135
+ DialogFooter,
136
+ DialogHeader,
137
+ DialogOverlay,
138
+ DialogPortal,
139
+ DialogTitle,
140
+ DialogTrigger,
141
+ };
@@ -0,0 +1,255 @@
1
+ import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
2
+ import { CheckIcon, ChevronRightIcon, CircleIcon } from 'lucide-react';
3
+ import type * as React from 'react';
4
+
5
+ import { cn } from '../../lib/utils';
6
+
7
+ function DropdownMenu({
8
+ ...props
9
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {
10
+ return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />;
11
+ }
12
+
13
+ function DropdownMenuPortal({
14
+ ...props
15
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {
16
+ return (
17
+ <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
18
+ );
19
+ }
20
+
21
+ function DropdownMenuTrigger({
22
+ ...props
23
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
24
+ return (
25
+ <DropdownMenuPrimitive.Trigger
26
+ data-slot="dropdown-menu-trigger"
27
+ {...props}
28
+ />
29
+ );
30
+ }
31
+
32
+ function DropdownMenuContent({
33
+ className,
34
+ sideOffset = 4,
35
+ ...props
36
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
37
+ return (
38
+ <DropdownMenuPrimitive.Portal>
39
+ <DropdownMenuPrimitive.Content
40
+ className={cn(
41
+ '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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[state=closed]:animate-out data-[state=open]:animate-in',
42
+ className
43
+ )}
44
+ data-slot="dropdown-menu-content"
45
+ sideOffset={sideOffset}
46
+ {...props}
47
+ />
48
+ </DropdownMenuPrimitive.Portal>
49
+ );
50
+ }
51
+
52
+ function DropdownMenuGroup({
53
+ ...props
54
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {
55
+ return (
56
+ <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
57
+ );
58
+ }
59
+
60
+ function DropdownMenuItem({
61
+ className,
62
+ inset,
63
+ variant = 'default',
64
+ ...props
65
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
66
+ inset?: boolean;
67
+ variant?: 'default' | 'destructive';
68
+ }) {
69
+ return (
70
+ <DropdownMenuPrimitive.Item
71
+ className={cn(
72
+ "data-[variant=destructive]:*:[svg]:!text-destructive relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[disabled]:opacity-50 data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
73
+ className
74
+ )}
75
+ data-inset={inset}
76
+ data-slot="dropdown-menu-item"
77
+ data-variant={variant}
78
+ {...props}
79
+ />
80
+ );
81
+ }
82
+
83
+ function DropdownMenuCheckboxItem({
84
+ className,
85
+ children,
86
+ checked,
87
+ ...props
88
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>) {
89
+ return (
90
+ <DropdownMenuPrimitive.CheckboxItem
91
+ checked={checked}
92
+ className={cn(
93
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
94
+ className
95
+ )}
96
+ data-slot="dropdown-menu-checkbox-item"
97
+ {...props}
98
+ >
99
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
100
+ <DropdownMenuPrimitive.ItemIndicator>
101
+ <CheckIcon className="size-4" />
102
+ </DropdownMenuPrimitive.ItemIndicator>
103
+ </span>
104
+ {children}
105
+ </DropdownMenuPrimitive.CheckboxItem>
106
+ );
107
+ }
108
+
109
+ function DropdownMenuRadioGroup({
110
+ ...props
111
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {
112
+ return (
113
+ <DropdownMenuPrimitive.RadioGroup
114
+ data-slot="dropdown-menu-radio-group"
115
+ {...props}
116
+ />
117
+ );
118
+ }
119
+
120
+ function DropdownMenuRadioItem({
121
+ className,
122
+ children,
123
+ ...props
124
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>) {
125
+ return (
126
+ <DropdownMenuPrimitive.RadioItem
127
+ className={cn(
128
+ "relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
129
+ className
130
+ )}
131
+ data-slot="dropdown-menu-radio-item"
132
+ {...props}
133
+ >
134
+ <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
135
+ <DropdownMenuPrimitive.ItemIndicator>
136
+ <CircleIcon className="size-2 fill-current" />
137
+ </DropdownMenuPrimitive.ItemIndicator>
138
+ </span>
139
+ {children}
140
+ </DropdownMenuPrimitive.RadioItem>
141
+ );
142
+ }
143
+
144
+ function DropdownMenuLabel({
145
+ className,
146
+ inset,
147
+ ...props
148
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
149
+ inset?: boolean;
150
+ }) {
151
+ return (
152
+ <DropdownMenuPrimitive.Label
153
+ className={cn(
154
+ 'px-2 py-1.5 font-medium text-sm data-[inset]:pl-8',
155
+ className
156
+ )}
157
+ data-inset={inset}
158
+ data-slot="dropdown-menu-label"
159
+ {...props}
160
+ />
161
+ );
162
+ }
163
+
164
+ function DropdownMenuSeparator({
165
+ className,
166
+ ...props
167
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {
168
+ return (
169
+ <DropdownMenuPrimitive.Separator
170
+ className={cn('-mx-1 my-1 h-px bg-border', className)}
171
+ data-slot="dropdown-menu-separator"
172
+ {...props}
173
+ />
174
+ );
175
+ }
176
+
177
+ function DropdownMenuShortcut({
178
+ className,
179
+ ...props
180
+ }: React.ComponentProps<'span'>) {
181
+ return (
182
+ <span
183
+ className={cn(
184
+ 'ml-auto text-muted-foreground text-xs tracking-widest',
185
+ className
186
+ )}
187
+ data-slot="dropdown-menu-shortcut"
188
+ {...props}
189
+ />
190
+ );
191
+ }
192
+
193
+ function DropdownMenuSub({
194
+ ...props
195
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {
196
+ return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
197
+ }
198
+
199
+ function DropdownMenuSubTrigger({
200
+ className,
201
+ inset,
202
+ children,
203
+ ...props
204
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
205
+ inset?: boolean;
206
+ }) {
207
+ return (
208
+ <DropdownMenuPrimitive.SubTrigger
209
+ className={cn(
210
+ "flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[inset]:pl-8 data-[state=open]:text-accent-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0",
211
+ className
212
+ )}
213
+ data-inset={inset}
214
+ data-slot="dropdown-menu-sub-trigger"
215
+ {...props}
216
+ >
217
+ {children}
218
+ <ChevronRightIcon className="ml-auto size-4" />
219
+ </DropdownMenuPrimitive.SubTrigger>
220
+ );
221
+ }
222
+
223
+ function DropdownMenuSubContent({
224
+ className,
225
+ ...props
226
+ }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
227
+ return (
228
+ <DropdownMenuPrimitive.SubContent
229
+ className={cn(
230
+ '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 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=closed]:animate-out data-[state=open]:animate-in',
231
+ className
232
+ )}
233
+ data-slot="dropdown-menu-sub-content"
234
+ {...props}
235
+ />
236
+ );
237
+ }
238
+
239
+ export {
240
+ DropdownMenu,
241
+ DropdownMenuPortal,
242
+ DropdownMenuTrigger,
243
+ DropdownMenuContent,
244
+ DropdownMenuGroup,
245
+ DropdownMenuLabel,
246
+ DropdownMenuItem,
247
+ DropdownMenuCheckboxItem,
248
+ DropdownMenuRadioGroup,
249
+ DropdownMenuRadioItem,
250
+ DropdownMenuSeparator,
251
+ DropdownMenuShortcut,
252
+ DropdownMenuSub,
253
+ DropdownMenuSubTrigger,
254
+ DropdownMenuSubContent,
255
+ };
@@ -0,0 +1,42 @@
1
+ import * as HoverCardPrimitive from '@radix-ui/react-hover-card';
2
+ import type * as React from 'react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ function HoverCard({
7
+ ...props
8
+ }: React.ComponentProps<typeof HoverCardPrimitive.Root>) {
9
+ return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
10
+ }
11
+
12
+ function HoverCardTrigger({
13
+ ...props
14
+ }: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
15
+ return (
16
+ <HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
17
+ );
18
+ }
19
+
20
+ function HoverCardContent({
21
+ className,
22
+ align = 'center',
23
+ sideOffset = 4,
24
+ ...props
25
+ }: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
26
+ return (
27
+ <HoverCardPrimitive.Portal data-slot="hover-card-portal">
28
+ <HoverCardPrimitive.Content
29
+ align={align}
30
+ className={cn(
31
+ '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-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden data-[state=closed]:animate-out data-[state=open]:animate-in',
32
+ className
33
+ )}
34
+ data-slot="hover-card-content"
35
+ sideOffset={sideOffset}
36
+ {...props}
37
+ />
38
+ </HoverCardPrimitive.Portal>
39
+ );
40
+ }
41
+
42
+ export { HoverCard, HoverCardTrigger, HoverCardContent };
@@ -0,0 +1,167 @@
1
+ import { cva, type VariantProps } from 'class-variance-authority';
2
+ import type * as React from 'react';
3
+ import { cn } from '../../lib/utils';
4
+ import { Button } from './button';
5
+ import { Input } from './input';
6
+ import { Textarea } from './textarea';
7
+
8
+ function InputGroup({ className, ...props }: React.ComponentProps<'div'>) {
9
+ return (
10
+ <div
11
+ className={cn(
12
+ 'group/input-group relative flex w-full items-center rounded-md border border-input shadow-xs outline-none transition-[color,box-shadow] dark:bg-input/30',
13
+ 'h-9 min-w-0 has-[>textarea]:h-auto',
14
+
15
+ // Variants based on alignment.
16
+ 'has-[>[data-align=inline-start]]:[&>input]:pl-2',
17
+ 'has-[>[data-align=inline-end]]:[&>input]:pr-2',
18
+ 'has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-start]]:[&>input]:pb-3',
19
+ 'has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3',
20
+
21
+ // Focus state.
22
+ 'has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-[3px] has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50',
23
+
24
+ // Error state.
25
+ 'has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-destructive/20 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40',
26
+
27
+ className
28
+ )}
29
+ data-slot="input-group"
30
+ role="group"
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ const inputGroupAddonVariants = cva(
37
+ "flex h-auto cursor-text select-none items-center justify-center gap-2 py-1.5 font-medium text-muted-foreground text-sm group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
38
+ {
39
+ variants: {
40
+ align: {
41
+ 'inline-start':
42
+ 'order-first pl-3 has-[>button]:ml-[-0.45rem] has-[>kbd]:ml-[-0.35rem]',
43
+ 'inline-end':
44
+ 'order-last pr-3 has-[>button]:mr-[-0.45rem] has-[>kbd]:mr-[-0.35rem]',
45
+ 'block-start':
46
+ 'order-first w-full justify-start px-3 pt-3 group-has-[>input]/input-group:pt-2.5 [.border-b]:pb-3',
47
+ 'block-end':
48
+ 'order-last w-full justify-start px-3 pb-3 group-has-[>input]/input-group:pb-2.5 [.border-t]:pt-3',
49
+ },
50
+ },
51
+ defaultVariants: {
52
+ align: 'inline-start',
53
+ },
54
+ }
55
+ );
56
+
57
+ function InputGroupAddon({
58
+ className,
59
+ align = 'inline-start',
60
+ ...props
61
+ }: React.ComponentProps<'div'> & VariantProps<typeof inputGroupAddonVariants>) {
62
+ return (
63
+ <div
64
+ className={cn(inputGroupAddonVariants({ align }), className)}
65
+ data-align={align}
66
+ data-slot="input-group-addon"
67
+ onClick={(e) => {
68
+ if ((e.target as HTMLElement).closest('button')) {
69
+ return;
70
+ }
71
+ e.currentTarget.parentElement?.querySelector('input')?.focus();
72
+ }}
73
+ role="group"
74
+ {...props}
75
+ />
76
+ );
77
+ }
78
+
79
+ const inputGroupButtonVariants = cva(
80
+ 'flex items-center gap-2 text-sm shadow-none',
81
+ {
82
+ variants: {
83
+ size: {
84
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-5px)] px-2 has-[>svg]:px-2 [&>svg:not([class*='size-'])]:size-3.5",
85
+ sm: 'h-8 gap-1.5 rounded-md px-2.5 has-[>svg]:px-2.5',
86
+ 'icon-xs':
87
+ 'size-6 rounded-[calc(var(--radius)-5px)] p-0 has-[>svg]:p-0',
88
+ 'icon-sm': 'size-8 p-0 has-[>svg]:p-0',
89
+ },
90
+ },
91
+ defaultVariants: {
92
+ size: 'xs',
93
+ },
94
+ }
95
+ );
96
+
97
+ function InputGroupButton({
98
+ className,
99
+ type = 'button',
100
+ variant = 'ghost',
101
+ size = 'xs',
102
+ ...props
103
+ }: Omit<React.ComponentProps<typeof Button>, 'size'> &
104
+ VariantProps<typeof inputGroupButtonVariants>) {
105
+ return (
106
+ <Button
107
+ className={cn(inputGroupButtonVariants({ size }), className)}
108
+ data-size={size}
109
+ type={type}
110
+ variant={variant}
111
+ {...props}
112
+ />
113
+ );
114
+ }
115
+
116
+ function InputGroupText({ className, ...props }: React.ComponentProps<'span'>) {
117
+ return (
118
+ <span
119
+ className={cn(
120
+ "flex items-center gap-2 text-muted-foreground text-sm [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none",
121
+ className
122
+ )}
123
+ {...props}
124
+ />
125
+ );
126
+ }
127
+
128
+ function InputGroupInput({
129
+ className,
130
+ ...props
131
+ }: React.ComponentProps<'input'>) {
132
+ return (
133
+ <Input
134
+ className={cn(
135
+ 'flex-1 rounded-none border-0 bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent',
136
+ className
137
+ )}
138
+ data-slot="input-group-control"
139
+ {...props}
140
+ />
141
+ );
142
+ }
143
+
144
+ function InputGroupTextarea({
145
+ className,
146
+ ...props
147
+ }: React.ComponentProps<'textarea'>) {
148
+ return (
149
+ <Textarea
150
+ className={cn(
151
+ 'flex-1 resize-none rounded-none border-0 bg-transparent py-3 shadow-none focus-visible:ring-0 dark:bg-transparent',
152
+ className
153
+ )}
154
+ data-slot="input-group-control"
155
+ {...props}
156
+ />
157
+ );
158
+ }
159
+
160
+ export {
161
+ InputGroup,
162
+ InputGroupAddon,
163
+ InputGroupButton,
164
+ InputGroupText,
165
+ InputGroupInput,
166
+ InputGroupTextarea,
167
+ };
@@ -0,0 +1,21 @@
1
+ import type * 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
+ className={cn(
9
+ 'h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-xs outline-none transition-[color,box-shadow] selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:font-medium file:text-foreground file:text-sm placeholder:text-muted-foreground disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm dark:bg-input/30',
10
+ 'focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50',
11
+ 'aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40',
12
+ className
13
+ )}
14
+ data-slot="input"
15
+ type={type}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ export { Input };
@@ -0,0 +1,28 @@
1
+ import { Indicator, Root } from '@radix-ui/react-progress';
2
+ import type * as React from 'react';
3
+
4
+ import { cn } from '../../lib/utils';
5
+
6
+ function Progress({
7
+ className,
8
+ value,
9
+ ...props
10
+ }: React.ComponentProps<typeof Root>) {
11
+ return (
12
+ <Root
13
+ className={cn(
14
+ 'relative h-2 w-full overflow-hidden rounded-full bg-primary/20',
15
+ className
16
+ )}
17
+ data-slot="progress"
18
+ {...props}
19
+ >
20
+ <Indicator
21
+ className="h-full w-full flex-1 bg-primary transition-all"
22
+ style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
23
+ />
24
+ </Root>
25
+ );
26
+ }
27
+
28
+ export { Progress };