@vercel/agent-eval-playground 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.
- package/README.md +50 -0
- package/app/compare/page.tsx +40 -0
- package/app/evals/[name]/page.tsx +22 -0
- package/app/evals/page.tsx +18 -0
- package/app/experiments/[name]/[timestamp]/page.tsx +23 -0
- package/app/experiments/page.tsx +28 -0
- package/app/globals.css +126 -0
- package/app/layout.tsx +102 -0
- package/app/page.tsx +179 -0
- package/app/transcript/[experiment]/[timestamp]/[evalName]/[run]/page.tsx +43 -0
- package/bin.mjs +86 -0
- package/components/ComparePage.tsx +312 -0
- package/components/EvalDetail.tsx +114 -0
- package/components/EvalsPage.tsx +80 -0
- package/components/ExperimentDetail.tsx +162 -0
- package/components/ExperimentList.tsx +103 -0
- package/components/O11ySummary.tsx +114 -0
- package/components/RunResultCard.tsx +72 -0
- package/components/ShowMore.tsx +60 -0
- package/components/TranscriptPage.tsx +46 -0
- package/components/TranscriptViewer.tsx +201 -0
- package/components/ui/alert-dialog.tsx +184 -0
- package/components/ui/badge.tsx +45 -0
- package/components/ui/button.tsx +60 -0
- package/components/ui/card.tsx +94 -0
- package/components/ui/collapsible.tsx +34 -0
- package/components/ui/combobox.tsx +297 -0
- package/components/ui/dropdown-menu.tsx +269 -0
- package/components/ui/field.tsx +227 -0
- package/components/ui/input-group.tsx +147 -0
- package/components/ui/input.tsx +19 -0
- package/components/ui/label.tsx +24 -0
- package/components/ui/progress.tsx +31 -0
- package/components/ui/scroll-area.tsx +58 -0
- package/components/ui/select.tsx +191 -0
- package/components/ui/separator.tsx +28 -0
- package/components/ui/table.tsx +116 -0
- package/components/ui/tabs.tsx +91 -0
- package/components/ui/textarea.tsx +18 -0
- package/components/ui/tooltip.tsx +57 -0
- package/components.json +25 -0
- package/lib/data.ts +297 -0
- package/lib/types.ts +113 -0
- package/lib/utils.ts +6 -0
- package/next.config.ts +5 -0
- package/package.json +51 -0
- package/postcss.config.mjs +7 -0
- package/public/vercel.svg +1 -0
- package/tsconfig.json +42 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useMemo } from "react"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Label } from "@/components/ui/label"
|
|
8
|
+
import { Separator } from "@/components/ui/separator"
|
|
9
|
+
|
|
10
|
+
function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
|
|
11
|
+
return (
|
|
12
|
+
<fieldset
|
|
13
|
+
data-slot="field-set"
|
|
14
|
+
className={cn("gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3 flex flex-col", className)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function FieldLegend({
|
|
21
|
+
className,
|
|
22
|
+
variant = "legend",
|
|
23
|
+
...props
|
|
24
|
+
}: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
|
|
25
|
+
return (
|
|
26
|
+
<legend
|
|
27
|
+
data-slot="field-legend"
|
|
28
|
+
data-variant={variant}
|
|
29
|
+
className={cn("mb-2 font-medium data-[variant=label]:text-xs/relaxed data-[variant=legend]:text-sm", className)}
|
|
30
|
+
{...props}
|
|
31
|
+
/>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
36
|
+
return (
|
|
37
|
+
<div
|
|
38
|
+
data-slot="field-group"
|
|
39
|
+
className={cn(
|
|
40
|
+
"gap-4 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4 group/field-group @container/field-group flex w-full flex-col",
|
|
41
|
+
className
|
|
42
|
+
)}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const fieldVariants = cva("data-[invalid=true]:text-destructive gap-2 group/field flex w-full", {
|
|
49
|
+
variants: {
|
|
50
|
+
orientation: {
|
|
51
|
+
vertical:
|
|
52
|
+
"flex-col *:w-full [&>.sr-only]:w-auto",
|
|
53
|
+
horizontal:
|
|
54
|
+
"flex-row items-center *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:items-start has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
55
|
+
responsive:
|
|
56
|
+
"flex-col *:w-full [&>.sr-only]:w-auto @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:*:data-[slot=field-label]:flex-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
defaultVariants: {
|
|
60
|
+
orientation: "vertical",
|
|
61
|
+
},
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
function Field({
|
|
65
|
+
className,
|
|
66
|
+
orientation = "vertical",
|
|
67
|
+
...props
|
|
68
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
|
|
69
|
+
return (
|
|
70
|
+
<div
|
|
71
|
+
role="group"
|
|
72
|
+
data-slot="field"
|
|
73
|
+
data-orientation={orientation}
|
|
74
|
+
className={cn(fieldVariants({ orientation }), className)}
|
|
75
|
+
{...props}
|
|
76
|
+
/>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
81
|
+
return (
|
|
82
|
+
<div
|
|
83
|
+
data-slot="field-content"
|
|
84
|
+
className={cn(
|
|
85
|
+
"gap-0.5 group/field-content flex flex-1 flex-col leading-snug",
|
|
86
|
+
className
|
|
87
|
+
)}
|
|
88
|
+
{...props}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function FieldLabel({
|
|
94
|
+
className,
|
|
95
|
+
...props
|
|
96
|
+
}: React.ComponentProps<typeof Label>) {
|
|
97
|
+
return (
|
|
98
|
+
<Label
|
|
99
|
+
data-slot="field-label"
|
|
100
|
+
className={cn(
|
|
101
|
+
"has-data-checked:bg-primary/5 dark:has-data-checked:bg-primary/10 gap-2 group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border *:data-[slot=field]:p-2 group/field-label peer/field-label flex w-fit leading-snug",
|
|
102
|
+
"has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
|
|
103
|
+
className
|
|
104
|
+
)}
|
|
105
|
+
{...props}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
111
|
+
return (
|
|
112
|
+
<div
|
|
113
|
+
data-slot="field-label"
|
|
114
|
+
className={cn(
|
|
115
|
+
"gap-2 text-xs/relaxed font-medium group-data-[disabled=true]/field:opacity-50 flex w-fit items-center leading-snug",
|
|
116
|
+
className
|
|
117
|
+
)}
|
|
118
|
+
{...props}
|
|
119
|
+
/>
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
|
|
124
|
+
return (
|
|
125
|
+
<p
|
|
126
|
+
data-slot="field-description"
|
|
127
|
+
className={cn(
|
|
128
|
+
"text-muted-foreground text-left text-xs/relaxed [[data-variant=legend]+&]:-mt-1.5 leading-normal font-normal group-has-data-horizontal/field:text-balance",
|
|
129
|
+
"last:mt-0 nth-last-2:-mt-1",
|
|
130
|
+
"[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4",
|
|
131
|
+
className
|
|
132
|
+
)}
|
|
133
|
+
{...props}
|
|
134
|
+
/>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function FieldSeparator({
|
|
139
|
+
children,
|
|
140
|
+
className,
|
|
141
|
+
...props
|
|
142
|
+
}: React.ComponentProps<"div"> & {
|
|
143
|
+
children?: React.ReactNode
|
|
144
|
+
}) {
|
|
145
|
+
return (
|
|
146
|
+
<div
|
|
147
|
+
data-slot="field-separator"
|
|
148
|
+
data-content={!!children}
|
|
149
|
+
className={cn("-my-2 h-5 text-xs/relaxed group-data-[variant=outline]/field-group:-mb-2 relative", className)}
|
|
150
|
+
{...props}
|
|
151
|
+
>
|
|
152
|
+
<Separator className="absolute inset-0 top-1/2" />
|
|
153
|
+
{children && (
|
|
154
|
+
<span
|
|
155
|
+
className="text-muted-foreground px-2 bg-background relative mx-auto block w-fit"
|
|
156
|
+
data-slot="field-separator-content"
|
|
157
|
+
>
|
|
158
|
+
{children}
|
|
159
|
+
</span>
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
function FieldError({
|
|
166
|
+
className,
|
|
167
|
+
children,
|
|
168
|
+
errors,
|
|
169
|
+
...props
|
|
170
|
+
}: React.ComponentProps<"div"> & {
|
|
171
|
+
errors?: Array<{ message?: string } | undefined>
|
|
172
|
+
}) {
|
|
173
|
+
const content = useMemo(() => {
|
|
174
|
+
if (children) {
|
|
175
|
+
return children
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!errors?.length) {
|
|
179
|
+
return null
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const uniqueErrors = [
|
|
183
|
+
...new Map(errors.map((error) => [error?.message, error])).values(),
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
if (uniqueErrors?.length == 1) {
|
|
187
|
+
return uniqueErrors[0]?.message
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<ul className="ml-4 flex list-disc flex-col gap-1">
|
|
192
|
+
{uniqueErrors.map(
|
|
193
|
+
(error, index) =>
|
|
194
|
+
error?.message && <li key={index}>{error.message}</li>
|
|
195
|
+
)}
|
|
196
|
+
</ul>
|
|
197
|
+
)
|
|
198
|
+
}, [children, errors])
|
|
199
|
+
|
|
200
|
+
if (!content) {
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return (
|
|
205
|
+
<div
|
|
206
|
+
role="alert"
|
|
207
|
+
data-slot="field-error"
|
|
208
|
+
className={cn("text-destructive text-xs/relaxed font-normal", className)}
|
|
209
|
+
{...props}
|
|
210
|
+
>
|
|
211
|
+
{content}
|
|
212
|
+
</div>
|
|
213
|
+
)
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export {
|
|
217
|
+
Field,
|
|
218
|
+
FieldLabel,
|
|
219
|
+
FieldDescription,
|
|
220
|
+
FieldError,
|
|
221
|
+
FieldGroup,
|
|
222
|
+
FieldLegend,
|
|
223
|
+
FieldSeparator,
|
|
224
|
+
FieldSet,
|
|
225
|
+
FieldContent,
|
|
226
|
+
FieldTitle,
|
|
227
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { Button } from "@/components/ui/button"
|
|
8
|
+
import { Input } from "@/components/ui/input"
|
|
9
|
+
import { Textarea } from "@/components/ui/textarea"
|
|
10
|
+
|
|
11
|
+
function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|
12
|
+
return (
|
|
13
|
+
<div
|
|
14
|
+
data-slot="input-group"
|
|
15
|
+
role="group"
|
|
16
|
+
className={cn(
|
|
17
|
+
"border-input bg-input/20 dark:bg-input/30 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-ring/30 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 h-7 rounded-md border transition-colors in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-data-[align=block-end]:rounded-md has-data-[align=block-start]:rounded-md has-[[data-slot=input-group-control]:focus-visible]:ring-2 has-[[data-slot][aria-invalid=true]]:ring-2 has-[textarea]:rounded-md has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5 group/input-group relative flex w-full min-w-0 items-center outline-none has-[>textarea]:h-auto",
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
/>
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const inputGroupAddonVariants = cva(
|
|
26
|
+
"text-muted-foreground **:data-[slot=kbd]:bg-muted-foreground/10 h-auto gap-1 py-2 text-xs/relaxed font-medium group-data-[disabled=true]/input-group:opacity-50 **:data-[slot=kbd]:rounded-[calc(var(--radius-sm)-2px)] **:data-[slot=kbd]:px-1 **:data-[slot=kbd]:text-[0.625rem] [&>svg:not([class*='size-'])]:size-3.5 flex cursor-text items-center justify-center select-none",
|
|
27
|
+
{
|
|
28
|
+
variants: {
|
|
29
|
+
align: {
|
|
30
|
+
"inline-start": "pl-2 has-[>button]:ml-[-0.275rem] has-[>kbd]:ml-[-0.275rem] order-first",
|
|
31
|
+
"inline-end": "pr-2 has-[>button]:mr-[-0.275rem] has-[>kbd]:mr-[-0.275rem] order-last",
|
|
32
|
+
"block-start":
|
|
33
|
+
"px-2 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2 order-first w-full justify-start",
|
|
34
|
+
"block-end":
|
|
35
|
+
"px-2 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2 order-last w-full justify-start",
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultVariants: {
|
|
39
|
+
align: "inline-start",
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
function InputGroupAddon({
|
|
45
|
+
className,
|
|
46
|
+
align = "inline-start",
|
|
47
|
+
...props
|
|
48
|
+
}: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
|
|
49
|
+
return (
|
|
50
|
+
<div
|
|
51
|
+
role="group"
|
|
52
|
+
data-slot="input-group-addon"
|
|
53
|
+
data-align={align}
|
|
54
|
+
className={cn(inputGroupAddonVariants({ align }), className)}
|
|
55
|
+
onClick={(e) => {
|
|
56
|
+
if ((e.target as HTMLElement).closest("button")) {
|
|
57
|
+
return
|
|
58
|
+
}
|
|
59
|
+
e.currentTarget.parentElement?.querySelector("input")?.focus()
|
|
60
|
+
}}
|
|
61
|
+
{...props}
|
|
62
|
+
/>
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const inputGroupButtonVariants = cva(
|
|
67
|
+
"gap-2 rounded-md text-xs/relaxed shadow-none flex items-center",
|
|
68
|
+
{
|
|
69
|
+
variants: {
|
|
70
|
+
size: {
|
|
71
|
+
xs: "h-5 gap-1 rounded-[calc(var(--radius-sm)-2px)] px-1 [&>svg:not([class*='size-'])]:size-3",
|
|
72
|
+
sm: "",
|
|
73
|
+
"icon-xs": "size-6 p-0 has-[>svg]:p-0",
|
|
74
|
+
"icon-sm": "size-8 p-0 has-[>svg]:p-0",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
defaultVariants: {
|
|
78
|
+
size: "xs",
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
function InputGroupButton({
|
|
84
|
+
className,
|
|
85
|
+
type = "button",
|
|
86
|
+
variant = "ghost",
|
|
87
|
+
size = "xs",
|
|
88
|
+
...props
|
|
89
|
+
}: Omit<React.ComponentProps<typeof Button>, "size"> &
|
|
90
|
+
VariantProps<typeof inputGroupButtonVariants>) {
|
|
91
|
+
return (
|
|
92
|
+
<Button
|
|
93
|
+
type={type}
|
|
94
|
+
data-size={size}
|
|
95
|
+
variant={variant}
|
|
96
|
+
className={cn(inputGroupButtonVariants({ size }), className)}
|
|
97
|
+
{...props}
|
|
98
|
+
/>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
|
|
103
|
+
return (
|
|
104
|
+
<span
|
|
105
|
+
className={cn(
|
|
106
|
+
"text-muted-foreground gap-2 text-xs/relaxed [&_svg:not([class*='size-'])]:size-4 flex items-center [&_svg]:pointer-events-none",
|
|
107
|
+
className
|
|
108
|
+
)}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function InputGroupInput({
|
|
115
|
+
className,
|
|
116
|
+
...props
|
|
117
|
+
}: React.ComponentProps<"input">) {
|
|
118
|
+
return (
|
|
119
|
+
<Input
|
|
120
|
+
data-slot="input-group-control"
|
|
121
|
+
className={cn("rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent flex-1", className)}
|
|
122
|
+
{...props}
|
|
123
|
+
/>
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function InputGroupTextarea({
|
|
128
|
+
className,
|
|
129
|
+
...props
|
|
130
|
+
}: React.ComponentProps<"textarea">) {
|
|
131
|
+
return (
|
|
132
|
+
<Textarea
|
|
133
|
+
data-slot="input-group-control"
|
|
134
|
+
className={cn("rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 aria-invalid:ring-0 dark:bg-transparent flex-1 resize-none", className)}
|
|
135
|
+
{...props}
|
|
136
|
+
/>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export {
|
|
141
|
+
InputGroup,
|
|
142
|
+
InputGroupAddon,
|
|
143
|
+
InputGroupButton,
|
|
144
|
+
InputGroupText,
|
|
145
|
+
InputGroupInput,
|
|
146
|
+
InputGroupTextarea,
|
|
147
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
"bg-input/20 dark:bg-input/30 border-input focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 h-7 rounded-md border px-2 py-0.5 text-sm transition-colors file:h-6 file:text-xs/relaxed file:font-medium focus-visible:ring-2 aria-invalid:ring-2 md:text-xs/relaxed file:text-foreground placeholder:text-muted-foreground w-full min-w-0 outline-none file:inline-flex file:border-0 file:bg-transparent disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export { Input }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Label as LabelPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Label({
|
|
9
|
+
className,
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof LabelPrimitive.Root>) {
|
|
12
|
+
return (
|
|
13
|
+
<LabelPrimitive.Root
|
|
14
|
+
data-slot="label"
|
|
15
|
+
className={cn(
|
|
16
|
+
"gap-2 text-xs/relaxed leading-none font-medium group-data-[disabled=true]:opacity-50 peer-disabled:opacity-50 flex items-center select-none group-data-[disabled=true]:pointer-events-none peer-disabled:cursor-not-allowed",
|
|
17
|
+
className
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { Label }
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Progress as ProgressPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function Progress({
|
|
9
|
+
className,
|
|
10
|
+
value,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
|
|
13
|
+
return (
|
|
14
|
+
<ProgressPrimitive.Root
|
|
15
|
+
data-slot="progress"
|
|
16
|
+
className={cn(
|
|
17
|
+
"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
|
|
18
|
+
className
|
|
19
|
+
)}
|
|
20
|
+
{...props}
|
|
21
|
+
>
|
|
22
|
+
<ProgressPrimitive.Indicator
|
|
23
|
+
data-slot="progress-indicator"
|
|
24
|
+
className="bg-primary h-full w-full flex-1 transition-all"
|
|
25
|
+
style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
|
|
26
|
+
/>
|
|
27
|
+
</ProgressPrimitive.Root>
|
|
28
|
+
)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { Progress }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ScrollArea as ScrollAreaPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
|
|
8
|
+
function ScrollArea({
|
|
9
|
+
className,
|
|
10
|
+
children,
|
|
11
|
+
...props
|
|
12
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.Root>) {
|
|
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="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] 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
|
+
}: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>) {
|
|
36
|
+
return (
|
|
37
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
38
|
+
data-slot="scroll-area-scrollbar"
|
|
39
|
+
orientation={orientation}
|
|
40
|
+
className={cn(
|
|
41
|
+
"flex touch-none p-px transition-colors select-none",
|
|
42
|
+
orientation === "vertical" &&
|
|
43
|
+
"h-full w-2.5 border-l border-l-transparent",
|
|
44
|
+
orientation === "horizontal" &&
|
|
45
|
+
"h-2.5 flex-col border-t border-t-transparent",
|
|
46
|
+
className
|
|
47
|
+
)}
|
|
48
|
+
{...props}
|
|
49
|
+
>
|
|
50
|
+
<ScrollAreaPrimitive.ScrollAreaThumb
|
|
51
|
+
data-slot="scroll-area-thumb"
|
|
52
|
+
className="bg-border relative flex-1 rounded-full"
|
|
53
|
+
/>
|
|
54
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { ScrollArea, ScrollBar }
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { Select as SelectPrimitive } from "radix-ui"
|
|
5
|
+
|
|
6
|
+
import { cn } from "@/lib/utils"
|
|
7
|
+
import { RiArrowDownSLine, RiCheckLine, RiArrowUpSLine } from "@remixicon/react"
|
|
8
|
+
|
|
9
|
+
function Select({
|
|
10
|
+
...props
|
|
11
|
+
}: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
|
12
|
+
return <SelectPrimitive.Root data-slot="select" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function SelectGroup({
|
|
16
|
+
className,
|
|
17
|
+
...props
|
|
18
|
+
}: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
|
19
|
+
return (
|
|
20
|
+
<SelectPrimitive.Group
|
|
21
|
+
data-slot="select-group"
|
|
22
|
+
className={cn("scroll-my-1 p-1", className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function SelectValue({
|
|
29
|
+
...props
|
|
30
|
+
}: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
|
31
|
+
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function SelectTrigger({
|
|
35
|
+
className,
|
|
36
|
+
size = "default",
|
|
37
|
+
children,
|
|
38
|
+
...props
|
|
39
|
+
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
|
40
|
+
size?: "sm" | "default"
|
|
41
|
+
}) {
|
|
42
|
+
return (
|
|
43
|
+
<SelectPrimitive.Trigger
|
|
44
|
+
data-slot="select-trigger"
|
|
45
|
+
data-size={size}
|
|
46
|
+
className={cn(
|
|
47
|
+
"cursor-pointer border-input data-placeholder:text-muted-foreground bg-input/20 dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/30 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 gap-1.5 rounded-md border px-2 py-1.5 text-xs/relaxed transition-colors focus-visible:ring-2 aria-invalid:ring-2 data-[size=default]:h-7 data-[size=sm]:h-6 *:data-[slot=select-value]:gap-1.5 [&_svg:not([class*='size-'])]:size-3.5 flex w-fit items-center justify-between whitespace-nowrap outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
48
|
+
className
|
|
49
|
+
)}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
{children}
|
|
53
|
+
<SelectPrimitive.Icon asChild>
|
|
54
|
+
<RiArrowDownSLine className="text-muted-foreground size-3.5 pointer-events-none" />
|
|
55
|
+
</SelectPrimitive.Icon>
|
|
56
|
+
</SelectPrimitive.Trigger>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function SelectContent({
|
|
61
|
+
className,
|
|
62
|
+
children,
|
|
63
|
+
position = "item-aligned",
|
|
64
|
+
align = "center",
|
|
65
|
+
...props
|
|
66
|
+
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
|
67
|
+
return (
|
|
68
|
+
<SelectPrimitive.Portal>
|
|
69
|
+
<SelectPrimitive.Content
|
|
70
|
+
data-slot="select-content"
|
|
71
|
+
data-align-trigger={position === "item-aligned"}
|
|
72
|
+
className={cn(
|
|
73
|
+
"bg-popover text-popover-foreground data-open:animate-in data-closed:animate-out data-closed:fade-out-0 data-open:fade-in-0 data-closed:zoom-out-95 data-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 ring-foreground/10 min-w-32 rounded-lg shadow-md ring-1 duration-100 dark relative z-50 max-h-(--radix-select-content-available-height) origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto data-[align-trigger=true]:animate-none",
|
|
74
|
+
position === "popper" &&
|
|
75
|
+
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
76
|
+
className
|
|
77
|
+
)}
|
|
78
|
+
position={position}
|
|
79
|
+
align={align}
|
|
80
|
+
{...props}
|
|
81
|
+
>
|
|
82
|
+
<SelectScrollUpButton />
|
|
83
|
+
<SelectPrimitive.Viewport
|
|
84
|
+
data-position={position}
|
|
85
|
+
className={cn(
|
|
86
|
+
"data-[position=popper]:h-(--radix-select-trigger-height) data-[position=popper]:w-full data-[position=popper]:min-w-(--radix-select-trigger-width)",
|
|
87
|
+
position === "popper" && ""
|
|
88
|
+
)}
|
|
89
|
+
>
|
|
90
|
+
{children}
|
|
91
|
+
</SelectPrimitive.Viewport>
|
|
92
|
+
<SelectScrollDownButton />
|
|
93
|
+
</SelectPrimitive.Content>
|
|
94
|
+
</SelectPrimitive.Portal>
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function SelectLabel({
|
|
99
|
+
className,
|
|
100
|
+
...props
|
|
101
|
+
}: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
|
102
|
+
return (
|
|
103
|
+
<SelectPrimitive.Label
|
|
104
|
+
data-slot="select-label"
|
|
105
|
+
className={cn("text-muted-foreground px-2 py-1.5 text-xs", className)}
|
|
106
|
+
{...props}
|
|
107
|
+
/>
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function SelectItem({
|
|
112
|
+
className,
|
|
113
|
+
children,
|
|
114
|
+
...props
|
|
115
|
+
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
|
116
|
+
return (
|
|
117
|
+
<SelectPrimitive.Item
|
|
118
|
+
data-slot="select-item"
|
|
119
|
+
className={cn(
|
|
120
|
+
"focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground min-h-7 gap-2 rounded-md px-2 py-1 text-xs/relaxed [&_svg:not([class*='size-'])]:size-3.5 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 relative flex w-full cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
121
|
+
className
|
|
122
|
+
)}
|
|
123
|
+
{...props}
|
|
124
|
+
>
|
|
125
|
+
<span className="pointer-events-none absolute right-2 flex items-center justify-center">
|
|
126
|
+
<SelectPrimitive.ItemIndicator>
|
|
127
|
+
<RiCheckLine className="pointer-events-none" />
|
|
128
|
+
</SelectPrimitive.ItemIndicator>
|
|
129
|
+
</span>
|
|
130
|
+
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
|
131
|
+
</SelectPrimitive.Item>
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function SelectSeparator({
|
|
136
|
+
className,
|
|
137
|
+
...props
|
|
138
|
+
}: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
|
139
|
+
return (
|
|
140
|
+
<SelectPrimitive.Separator
|
|
141
|
+
data-slot="select-separator"
|
|
142
|
+
className={cn("bg-border/50 -mx-1 my-1 h-px pointer-events-none", className)}
|
|
143
|
+
{...props}
|
|
144
|
+
/>
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function SelectScrollUpButton({
|
|
149
|
+
className,
|
|
150
|
+
...props
|
|
151
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
|
152
|
+
return (
|
|
153
|
+
<SelectPrimitive.ScrollUpButton
|
|
154
|
+
data-slot="select-scroll-up-button"
|
|
155
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
|
|
156
|
+
{...props}
|
|
157
|
+
>
|
|
158
|
+
<RiArrowUpSLine
|
|
159
|
+
/>
|
|
160
|
+
</SelectPrimitive.ScrollUpButton>
|
|
161
|
+
)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function SelectScrollDownButton({
|
|
165
|
+
className,
|
|
166
|
+
...props
|
|
167
|
+
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
|
168
|
+
return (
|
|
169
|
+
<SelectPrimitive.ScrollDownButton
|
|
170
|
+
data-slot="select-scroll-down-button"
|
|
171
|
+
className={cn("bg-popover z-10 flex cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-3.5", className)}
|
|
172
|
+
{...props}
|
|
173
|
+
>
|
|
174
|
+
<RiArrowDownSLine
|
|
175
|
+
/>
|
|
176
|
+
</SelectPrimitive.ScrollDownButton>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
Select,
|
|
182
|
+
SelectContent,
|
|
183
|
+
SelectGroup,
|
|
184
|
+
SelectItem,
|
|
185
|
+
SelectLabel,
|
|
186
|
+
SelectScrollDownButton,
|
|
187
|
+
SelectScrollUpButton,
|
|
188
|
+
SelectSeparator,
|
|
189
|
+
SelectTrigger,
|
|
190
|
+
SelectValue,
|
|
191
|
+
}
|