selftune 0.2.2 → 0.2.6
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 +11 -0
- package/apps/local-dashboard/dist/assets/index-C75H1Q3n.css +1 -0
- package/apps/local-dashboard/dist/assets/index-axE4kz3Q.js +15 -0
- package/apps/local-dashboard/dist/assets/vendor-ui-r2k_Ku_V.js +346 -0
- package/apps/local-dashboard/dist/index.html +3 -3
- package/cli/selftune/analytics.ts +354 -0
- package/cli/selftune/badge/badge.ts +2 -2
- package/cli/selftune/dashboard-server.ts +3 -3
- package/cli/selftune/evolution/evolve-body.ts +1 -1
- package/cli/selftune/evolution/evolve.ts +1 -1
- package/cli/selftune/index.ts +15 -1
- package/cli/selftune/init.ts +5 -1
- package/cli/selftune/observability.ts +63 -2
- package/cli/selftune/orchestrate.ts +1 -1
- package/cli/selftune/quickstart.ts +1 -1
- package/cli/selftune/status.ts +2 -2
- package/cli/selftune/types.ts +1 -0
- package/cli/selftune/utils/llm-call.ts +2 -1
- package/package.json +6 -4
- package/packages/ui/README.md +113 -0
- package/packages/ui/index.ts +10 -0
- package/packages/ui/package.json +62 -0
- package/packages/ui/src/components/ActivityTimeline.tsx +171 -0
- package/packages/ui/src/components/EvidenceViewer.tsx +718 -0
- package/packages/ui/src/components/EvolutionTimeline.tsx +252 -0
- package/packages/ui/src/components/InfoTip.tsx +19 -0
- package/packages/ui/src/components/OrchestrateRunsPanel.tsx +164 -0
- package/packages/ui/src/components/index.ts +7 -0
- package/packages/ui/src/components/section-cards.tsx +155 -0
- package/packages/ui/src/components/skill-health-grid.tsx +686 -0
- package/packages/ui/src/lib/constants.tsx +43 -0
- package/packages/ui/src/lib/format.ts +37 -0
- package/packages/ui/src/lib/index.ts +3 -0
- package/packages/ui/src/lib/utils.ts +6 -0
- package/packages/ui/src/primitives/badge.tsx +52 -0
- package/packages/ui/src/primitives/button.tsx +58 -0
- package/packages/ui/src/primitives/card.tsx +103 -0
- package/packages/ui/src/primitives/checkbox.tsx +27 -0
- package/packages/ui/src/primitives/collapsible.tsx +7 -0
- package/packages/ui/src/primitives/dropdown-menu.tsx +266 -0
- package/packages/ui/src/primitives/index.ts +55 -0
- package/packages/ui/src/primitives/label.tsx +20 -0
- package/packages/ui/src/primitives/select.tsx +197 -0
- package/packages/ui/src/primitives/table.tsx +114 -0
- package/packages/ui/src/primitives/tabs.tsx +82 -0
- package/packages/ui/src/primitives/tooltip.tsx +64 -0
- package/packages/ui/src/types.ts +87 -0
- package/packages/ui/tsconfig.json +17 -0
- package/skill/SKILL.md +3 -0
- package/skill/Workflows/Telemetry.md +59 -0
- package/apps/local-dashboard/dist/assets/index-C4EOTFZ2.js +0 -15
- package/apps/local-dashboard/dist/assets/index-bl-Webyd.css +0 -1
- package/apps/local-dashboard/dist/assets/vendor-ui-D7_zX_qy.js +0 -346
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AlertTriangleIcon,
|
|
3
|
+
CheckCircleIcon,
|
|
4
|
+
CircleDotIcon,
|
|
5
|
+
HelpCircleIcon,
|
|
6
|
+
XCircleIcon,
|
|
7
|
+
} from "lucide-react";
|
|
8
|
+
import type { SkillHealthStatus } from "../types";
|
|
9
|
+
|
|
10
|
+
export const STATUS_CONFIG: Record<
|
|
11
|
+
SkillHealthStatus,
|
|
12
|
+
{
|
|
13
|
+
icon: React.ReactNode;
|
|
14
|
+
variant: "default" | "secondary" | "destructive" | "outline";
|
|
15
|
+
label: string;
|
|
16
|
+
}
|
|
17
|
+
> = {
|
|
18
|
+
HEALTHY: {
|
|
19
|
+
icon: <CheckCircleIcon className="size-4 text-emerald-600" />,
|
|
20
|
+
variant: "outline",
|
|
21
|
+
label: "Healthy",
|
|
22
|
+
},
|
|
23
|
+
WARNING: {
|
|
24
|
+
icon: <AlertTriangleIcon className="size-4 text-amber-500" />,
|
|
25
|
+
variant: "secondary",
|
|
26
|
+
label: "Warning",
|
|
27
|
+
},
|
|
28
|
+
CRITICAL: {
|
|
29
|
+
icon: <XCircleIcon className="size-4 text-red-500" />,
|
|
30
|
+
variant: "destructive",
|
|
31
|
+
label: "Critical",
|
|
32
|
+
},
|
|
33
|
+
UNGRADED: {
|
|
34
|
+
icon: <CircleDotIcon className="size-4 text-muted-foreground" />,
|
|
35
|
+
variant: "secondary",
|
|
36
|
+
label: "Ungraded",
|
|
37
|
+
},
|
|
38
|
+
UNKNOWN: {
|
|
39
|
+
icon: <HelpCircleIcon className="size-4 text-muted-foreground/60" />,
|
|
40
|
+
variant: "secondary",
|
|
41
|
+
label: "Unknown",
|
|
42
|
+
},
|
|
43
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { SkillHealthStatus } from "../types";
|
|
2
|
+
|
|
3
|
+
export function deriveStatus(passRate: number, checks: number): SkillHealthStatus {
|
|
4
|
+
if (checks < 5) return "UNGRADED";
|
|
5
|
+
if (passRate >= 0.8) return "HEALTHY";
|
|
6
|
+
if (passRate >= 0.5) return "WARNING";
|
|
7
|
+
return "CRITICAL";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function formatRate(rate: number | null | undefined): string {
|
|
11
|
+
if (rate === null || rate === undefined || !Number.isFinite(rate)) return "--";
|
|
12
|
+
return `${Math.round(rate * 100)}%`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function sortByPassRateAndChecks<T extends { passRate: number | null; checks: number }>(
|
|
16
|
+
items: T[],
|
|
17
|
+
): T[] {
|
|
18
|
+
return [...items].sort((a, b) => {
|
|
19
|
+
const aRate = a.passRate ?? 1;
|
|
20
|
+
const bRate = b.passRate ?? 1;
|
|
21
|
+
if (aRate !== bRate) return aRate - bRate;
|
|
22
|
+
return b.checks - a.checks;
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function timeAgo(timestamp: string): string {
|
|
27
|
+
const ts = new Date(timestamp).getTime();
|
|
28
|
+
if (Number.isNaN(ts)) return "--";
|
|
29
|
+
const diff = Math.max(0, Date.now() - ts);
|
|
30
|
+
const mins = Math.floor(diff / 60000);
|
|
31
|
+
if (mins < 1) return "just now";
|
|
32
|
+
if (mins < 60) return `${mins}m ago`;
|
|
33
|
+
const hours = Math.floor(mins / 60);
|
|
34
|
+
if (hours < 24) return `${hours}h ago`;
|
|
35
|
+
const days = Math.floor(hours / 24);
|
|
36
|
+
return `${days}d ago`;
|
|
37
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { mergeProps } from "@base-ui/react/merge-props"
|
|
2
|
+
import { useRender } from "@base-ui/react/use-render"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/utils"
|
|
6
|
+
|
|
7
|
+
const badgeVariants = cva(
|
|
8
|
+
"group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
13
|
+
secondary:
|
|
14
|
+
"bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
|
|
15
|
+
destructive:
|
|
16
|
+
"bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
|
|
17
|
+
outline:
|
|
18
|
+
"border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
|
|
19
|
+
ghost:
|
|
20
|
+
"hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
|
|
21
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
defaultVariants: {
|
|
25
|
+
variant: "default",
|
|
26
|
+
},
|
|
27
|
+
}
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
function Badge({
|
|
31
|
+
className,
|
|
32
|
+
variant = "default",
|
|
33
|
+
render,
|
|
34
|
+
...props
|
|
35
|
+
}: useRender.ComponentProps<"span"> & VariantProps<typeof badgeVariants>) {
|
|
36
|
+
return useRender({
|
|
37
|
+
defaultTagName: "span",
|
|
38
|
+
props: mergeProps<"span">(
|
|
39
|
+
{
|
|
40
|
+
className: cn(badgeVariants({ variant }), className),
|
|
41
|
+
},
|
|
42
|
+
props
|
|
43
|
+
),
|
|
44
|
+
render,
|
|
45
|
+
state: {
|
|
46
|
+
slot: "badge",
|
|
47
|
+
variant,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
|
2
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
3
|
+
|
|
4
|
+
import { cn } from "../lib/utils"
|
|
5
|
+
|
|
6
|
+
const buttonVariants = cva(
|
|
7
|
+
"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
|
|
12
|
+
outline:
|
|
13
|
+
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",
|
|
14
|
+
secondary:
|
|
15
|
+
"bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
|
16
|
+
ghost:
|
|
17
|
+
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
|
18
|
+
destructive:
|
|
19
|
+
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
|
20
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
21
|
+
},
|
|
22
|
+
size: {
|
|
23
|
+
default:
|
|
24
|
+
"h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
|
25
|
+
xs: "h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",
|
|
26
|
+
sm: "h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5",
|
|
27
|
+
lg: "h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
|
28
|
+
icon: "size-8",
|
|
29
|
+
"icon-xs":
|
|
30
|
+
"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",
|
|
31
|
+
"icon-sm":
|
|
32
|
+
"size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg",
|
|
33
|
+
"icon-lg": "size-9",
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
defaultVariants: {
|
|
37
|
+
variant: "default",
|
|
38
|
+
size: "default",
|
|
39
|
+
},
|
|
40
|
+
}
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
function Button({
|
|
44
|
+
className,
|
|
45
|
+
variant = "default",
|
|
46
|
+
size = "default",
|
|
47
|
+
...props
|
|
48
|
+
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
|
49
|
+
return (
|
|
50
|
+
<ButtonPrimitive
|
|
51
|
+
data-slot="button"
|
|
52
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
53
|
+
{...props}
|
|
54
|
+
/>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils"
|
|
4
|
+
|
|
5
|
+
function Card({
|
|
6
|
+
className,
|
|
7
|
+
size = "default",
|
|
8
|
+
...props
|
|
9
|
+
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
data-slot="card"
|
|
13
|
+
data-size={size}
|
|
14
|
+
className={cn(
|
|
15
|
+
"group/card flex flex-col gap-4 overflow-hidden rounded-xl bg-card py-4 text-sm text-card-foreground ring-1 ring-foreground/10 has-data-[slot=card-footer]:pb-0 has-[>img:first-child]:pt-0 data-[size=sm]:gap-3 data-[size=sm]:py-3 data-[size=sm]:has-data-[slot=card-footer]:pb-0 *:[img:first-child]:rounded-t-xl *:[img:last-child]:rounded-b-xl",
|
|
16
|
+
className
|
|
17
|
+
)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
|
24
|
+
return (
|
|
25
|
+
<div
|
|
26
|
+
data-slot="card-header"
|
|
27
|
+
className={cn(
|
|
28
|
+
"group/card-header @container/card-header grid auto-rows-min items-start gap-1 rounded-t-xl px-4 group-data-[size=sm]/card:px-3 has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-4 group-data-[size=sm]/card:[.border-b]:pb-3",
|
|
29
|
+
className
|
|
30
|
+
)}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
|
37
|
+
return (
|
|
38
|
+
<div
|
|
39
|
+
data-slot="card-title"
|
|
40
|
+
className={cn(
|
|
41
|
+
"text-base leading-snug font-medium group-data-[size=sm]/card:text-sm",
|
|
42
|
+
className
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
|
50
|
+
return (
|
|
51
|
+
<div
|
|
52
|
+
data-slot="card-description"
|
|
53
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
54
|
+
{...props}
|
|
55
|
+
/>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
|
60
|
+
return (
|
|
61
|
+
<div
|
|
62
|
+
data-slot="card-action"
|
|
63
|
+
className={cn(
|
|
64
|
+
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
|
65
|
+
className
|
|
66
|
+
)}
|
|
67
|
+
{...props}
|
|
68
|
+
/>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
|
73
|
+
return (
|
|
74
|
+
<div
|
|
75
|
+
data-slot="card-content"
|
|
76
|
+
className={cn("px-4 group-data-[size=sm]/card:px-3", className)}
|
|
77
|
+
{...props}
|
|
78
|
+
/>
|
|
79
|
+
)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
|
83
|
+
return (
|
|
84
|
+
<div
|
|
85
|
+
data-slot="card-footer"
|
|
86
|
+
className={cn(
|
|
87
|
+
"flex items-center rounded-b-xl border-t bg-muted/50 p-4 group-data-[size=sm]/card:p-3",
|
|
88
|
+
className
|
|
89
|
+
)}
|
|
90
|
+
{...props}
|
|
91
|
+
/>
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export {
|
|
96
|
+
Card,
|
|
97
|
+
CardHeader,
|
|
98
|
+
CardFooter,
|
|
99
|
+
CardTitle,
|
|
100
|
+
CardAction,
|
|
101
|
+
CardDescription,
|
|
102
|
+
CardContent,
|
|
103
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
|
|
2
|
+
|
|
3
|
+
import { cn } from "../lib/utils"
|
|
4
|
+
import { CheckIcon } from "lucide-react"
|
|
5
|
+
|
|
6
|
+
function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
|
|
7
|
+
return (
|
|
8
|
+
<CheckboxPrimitive.Root
|
|
9
|
+
data-slot="checkbox"
|
|
10
|
+
className={cn(
|
|
11
|
+
"peer relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary",
|
|
12
|
+
className
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
>
|
|
16
|
+
<CheckboxPrimitive.Indicator
|
|
17
|
+
data-slot="checkbox-indicator"
|
|
18
|
+
className="grid place-content-center text-current transition-none [&>svg]:size-3.5"
|
|
19
|
+
>
|
|
20
|
+
<CheckIcon
|
|
21
|
+
/>
|
|
22
|
+
</CheckboxPrimitive.Indicator>
|
|
23
|
+
</CheckboxPrimitive.Root>
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { Checkbox }
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Collapsible as CollapsiblePrimitive } from "@base-ui/react/collapsible"
|
|
2
|
+
|
|
3
|
+
const Collapsible = CollapsiblePrimitive.Root
|
|
4
|
+
const CollapsibleTrigger = CollapsiblePrimitive.Trigger
|
|
5
|
+
const CollapsibleContent = CollapsiblePrimitive.Panel
|
|
6
|
+
|
|
7
|
+
export { Collapsible, CollapsibleTrigger, CollapsibleContent }
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Menu as MenuPrimitive } from "@base-ui/react/menu"
|
|
3
|
+
|
|
4
|
+
import { cn } from "../lib/utils"
|
|
5
|
+
import { ChevronRightIcon, CheckIcon } from "lucide-react"
|
|
6
|
+
|
|
7
|
+
function DropdownMenu({ ...props }: MenuPrimitive.Root.Props) {
|
|
8
|
+
return <MenuPrimitive.Root data-slot="dropdown-menu" {...props} />
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function DropdownMenuPortal({ ...props }: MenuPrimitive.Portal.Props) {
|
|
12
|
+
return <MenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function DropdownMenuTrigger({ ...props }: MenuPrimitive.Trigger.Props) {
|
|
16
|
+
return <MenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function DropdownMenuContent({
|
|
20
|
+
align = "start",
|
|
21
|
+
alignOffset = 0,
|
|
22
|
+
side = "bottom",
|
|
23
|
+
sideOffset = 4,
|
|
24
|
+
className,
|
|
25
|
+
...props
|
|
26
|
+
}: MenuPrimitive.Popup.Props &
|
|
27
|
+
Pick<
|
|
28
|
+
MenuPrimitive.Positioner.Props,
|
|
29
|
+
"align" | "alignOffset" | "side" | "sideOffset"
|
|
30
|
+
>) {
|
|
31
|
+
return (
|
|
32
|
+
<MenuPrimitive.Portal>
|
|
33
|
+
<MenuPrimitive.Positioner
|
|
34
|
+
className="isolate z-50 outline-hidden"
|
|
35
|
+
align={align}
|
|
36
|
+
alignOffset={alignOffset}
|
|
37
|
+
side={side}
|
|
38
|
+
sideOffset={sideOffset}
|
|
39
|
+
>
|
|
40
|
+
<MenuPrimitive.Popup
|
|
41
|
+
data-slot="dropdown-menu-content"
|
|
42
|
+
className={cn("z-50 max-h-(--available-height) w-(--anchor-width) min-w-32 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg bg-popover p-1 text-popover-foreground shadow-md ring-1 ring-foreground/10 duration-100 outline-hidden data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:overflow-hidden data-closed:fade-out-0 data-closed:zoom-out-95", className )}
|
|
43
|
+
{...props}
|
|
44
|
+
/>
|
|
45
|
+
</MenuPrimitive.Positioner>
|
|
46
|
+
</MenuPrimitive.Portal>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function DropdownMenuGroup({ ...props }: MenuPrimitive.Group.Props) {
|
|
51
|
+
return <MenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function DropdownMenuLabel({
|
|
55
|
+
className,
|
|
56
|
+
inset,
|
|
57
|
+
...props
|
|
58
|
+
}: MenuPrimitive.GroupLabel.Props & {
|
|
59
|
+
inset?: boolean
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
<MenuPrimitive.GroupLabel
|
|
63
|
+
data-slot="dropdown-menu-label"
|
|
64
|
+
data-inset={inset}
|
|
65
|
+
className={cn(
|
|
66
|
+
"px-1.5 py-1 text-xs font-medium text-muted-foreground data-inset:pl-7",
|
|
67
|
+
className
|
|
68
|
+
)}
|
|
69
|
+
{...props}
|
|
70
|
+
/>
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function DropdownMenuItem({
|
|
75
|
+
className,
|
|
76
|
+
inset,
|
|
77
|
+
variant = "default",
|
|
78
|
+
...props
|
|
79
|
+
}: MenuPrimitive.Item.Props & {
|
|
80
|
+
inset?: boolean
|
|
81
|
+
variant?: "default" | "destructive"
|
|
82
|
+
}) {
|
|
83
|
+
return (
|
|
84
|
+
<MenuPrimitive.Item
|
|
85
|
+
data-slot="dropdown-menu-item"
|
|
86
|
+
data-inset={inset}
|
|
87
|
+
data-variant={variant}
|
|
88
|
+
className={cn(
|
|
89
|
+
"group/dropdown-menu-item relative flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 data-[variant=destructive]:[&_svg]:text-destructive",
|
|
90
|
+
className
|
|
91
|
+
)}
|
|
92
|
+
{...props}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function DropdownMenuSub({ ...props }: MenuPrimitive.SubmenuRoot.Props) {
|
|
98
|
+
return <MenuPrimitive.SubmenuRoot data-slot="dropdown-menu-sub" {...props} />
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function DropdownMenuSubTrigger({
|
|
102
|
+
className,
|
|
103
|
+
inset,
|
|
104
|
+
children,
|
|
105
|
+
...props
|
|
106
|
+
}: MenuPrimitive.SubmenuTrigger.Props & {
|
|
107
|
+
inset?: boolean
|
|
108
|
+
}) {
|
|
109
|
+
return (
|
|
110
|
+
<MenuPrimitive.SubmenuTrigger
|
|
111
|
+
data-slot="dropdown-menu-sub-trigger"
|
|
112
|
+
data-inset={inset}
|
|
113
|
+
className={cn(
|
|
114
|
+
"flex cursor-default items-center gap-1.5 rounded-md px-1.5 py-1 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground data-inset:pl-7 data-popup-open:bg-accent data-popup-open:text-accent-foreground data-open:bg-accent data-open:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
115
|
+
className
|
|
116
|
+
)}
|
|
117
|
+
{...props}
|
|
118
|
+
>
|
|
119
|
+
{children}
|
|
120
|
+
<ChevronRightIcon className="ml-auto" />
|
|
121
|
+
</MenuPrimitive.SubmenuTrigger>
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function DropdownMenuSubContent({
|
|
126
|
+
align = "start",
|
|
127
|
+
alignOffset = -3,
|
|
128
|
+
side = "right",
|
|
129
|
+
sideOffset = 0,
|
|
130
|
+
className,
|
|
131
|
+
...props
|
|
132
|
+
}: React.ComponentProps<typeof DropdownMenuContent>) {
|
|
133
|
+
return (
|
|
134
|
+
<DropdownMenuContent
|
|
135
|
+
data-slot="dropdown-menu-sub-content"
|
|
136
|
+
className={cn("w-auto min-w-[96px] rounded-lg bg-popover p-1 text-popover-foreground shadow-lg ring-1 ring-foreground/10 duration-100 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 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", className )}
|
|
137
|
+
align={align}
|
|
138
|
+
alignOffset={alignOffset}
|
|
139
|
+
side={side}
|
|
140
|
+
sideOffset={sideOffset}
|
|
141
|
+
{...props}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function DropdownMenuCheckboxItem({
|
|
147
|
+
className,
|
|
148
|
+
children,
|
|
149
|
+
checked,
|
|
150
|
+
inset,
|
|
151
|
+
...props
|
|
152
|
+
}: MenuPrimitive.CheckboxItem.Props & {
|
|
153
|
+
inset?: boolean
|
|
154
|
+
}) {
|
|
155
|
+
return (
|
|
156
|
+
<MenuPrimitive.CheckboxItem
|
|
157
|
+
data-slot="dropdown-menu-checkbox-item"
|
|
158
|
+
data-inset={inset}
|
|
159
|
+
className={cn(
|
|
160
|
+
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
161
|
+
className
|
|
162
|
+
)}
|
|
163
|
+
checked={checked}
|
|
164
|
+
{...props}
|
|
165
|
+
>
|
|
166
|
+
<span
|
|
167
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
168
|
+
data-slot="dropdown-menu-checkbox-item-indicator"
|
|
169
|
+
>
|
|
170
|
+
<MenuPrimitive.CheckboxItemIndicator>
|
|
171
|
+
<CheckIcon
|
|
172
|
+
/>
|
|
173
|
+
</MenuPrimitive.CheckboxItemIndicator>
|
|
174
|
+
</span>
|
|
175
|
+
{children}
|
|
176
|
+
</MenuPrimitive.CheckboxItem>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function DropdownMenuRadioGroup({ ...props }: MenuPrimitive.RadioGroup.Props) {
|
|
181
|
+
return (
|
|
182
|
+
<MenuPrimitive.RadioGroup
|
|
183
|
+
data-slot="dropdown-menu-radio-group"
|
|
184
|
+
{...props}
|
|
185
|
+
/>
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function DropdownMenuRadioItem({
|
|
190
|
+
className,
|
|
191
|
+
children,
|
|
192
|
+
inset,
|
|
193
|
+
...props
|
|
194
|
+
}: MenuPrimitive.RadioItem.Props & {
|
|
195
|
+
inset?: boolean
|
|
196
|
+
}) {
|
|
197
|
+
return (
|
|
198
|
+
<MenuPrimitive.RadioItem
|
|
199
|
+
data-slot="dropdown-menu-radio-item"
|
|
200
|
+
data-inset={inset}
|
|
201
|
+
className={cn(
|
|
202
|
+
"relative flex cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground data-inset:pl-7 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
|
203
|
+
className
|
|
204
|
+
)}
|
|
205
|
+
{...props}
|
|
206
|
+
>
|
|
207
|
+
<span
|
|
208
|
+
className="pointer-events-none absolute right-2 flex items-center justify-center"
|
|
209
|
+
data-slot="dropdown-menu-radio-item-indicator"
|
|
210
|
+
>
|
|
211
|
+
<MenuPrimitive.RadioItemIndicator>
|
|
212
|
+
<CheckIcon
|
|
213
|
+
/>
|
|
214
|
+
</MenuPrimitive.RadioItemIndicator>
|
|
215
|
+
</span>
|
|
216
|
+
{children}
|
|
217
|
+
</MenuPrimitive.RadioItem>
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function DropdownMenuSeparator({
|
|
222
|
+
className,
|
|
223
|
+
...props
|
|
224
|
+
}: MenuPrimitive.Separator.Props) {
|
|
225
|
+
return (
|
|
226
|
+
<MenuPrimitive.Separator
|
|
227
|
+
data-slot="dropdown-menu-separator"
|
|
228
|
+
className={cn("-mx-1 my-1 h-px bg-border", className)}
|
|
229
|
+
{...props}
|
|
230
|
+
/>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function DropdownMenuShortcut({
|
|
235
|
+
className,
|
|
236
|
+
...props
|
|
237
|
+
}: React.ComponentProps<"span">) {
|
|
238
|
+
return (
|
|
239
|
+
<span
|
|
240
|
+
data-slot="dropdown-menu-shortcut"
|
|
241
|
+
className={cn(
|
|
242
|
+
"ml-auto text-xs tracking-widest text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground",
|
|
243
|
+
className
|
|
244
|
+
)}
|
|
245
|
+
{...props}
|
|
246
|
+
/>
|
|
247
|
+
)
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export {
|
|
251
|
+
DropdownMenu,
|
|
252
|
+
DropdownMenuPortal,
|
|
253
|
+
DropdownMenuTrigger,
|
|
254
|
+
DropdownMenuContent,
|
|
255
|
+
DropdownMenuGroup,
|
|
256
|
+
DropdownMenuLabel,
|
|
257
|
+
DropdownMenuItem,
|
|
258
|
+
DropdownMenuCheckboxItem,
|
|
259
|
+
DropdownMenuRadioGroup,
|
|
260
|
+
DropdownMenuRadioItem,
|
|
261
|
+
DropdownMenuSeparator,
|
|
262
|
+
DropdownMenuShortcut,
|
|
263
|
+
DropdownMenuSub,
|
|
264
|
+
DropdownMenuSubTrigger,
|
|
265
|
+
DropdownMenuSubContent,
|
|
266
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export { Badge, badgeVariants } from "./badge";
|
|
2
|
+
export { Button, buttonVariants } from "./button";
|
|
3
|
+
export {
|
|
4
|
+
Card,
|
|
5
|
+
CardAction,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardDescription,
|
|
8
|
+
CardFooter,
|
|
9
|
+
CardHeader,
|
|
10
|
+
CardTitle,
|
|
11
|
+
} from "./card";
|
|
12
|
+
export { Checkbox } from "./checkbox";
|
|
13
|
+
export { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./collapsible";
|
|
14
|
+
export {
|
|
15
|
+
DropdownMenu,
|
|
16
|
+
DropdownMenuCheckboxItem,
|
|
17
|
+
DropdownMenuContent,
|
|
18
|
+
DropdownMenuGroup,
|
|
19
|
+
DropdownMenuItem,
|
|
20
|
+
DropdownMenuLabel,
|
|
21
|
+
DropdownMenuPortal,
|
|
22
|
+
DropdownMenuRadioGroup,
|
|
23
|
+
DropdownMenuRadioItem,
|
|
24
|
+
DropdownMenuSeparator,
|
|
25
|
+
DropdownMenuShortcut,
|
|
26
|
+
DropdownMenuSub,
|
|
27
|
+
DropdownMenuSubContent,
|
|
28
|
+
DropdownMenuSubTrigger,
|
|
29
|
+
DropdownMenuTrigger,
|
|
30
|
+
} from "./dropdown-menu";
|
|
31
|
+
export { Label } from "./label";
|
|
32
|
+
export {
|
|
33
|
+
Select,
|
|
34
|
+
SelectContent,
|
|
35
|
+
SelectGroup,
|
|
36
|
+
SelectItem,
|
|
37
|
+
SelectLabel,
|
|
38
|
+
SelectScrollDownButton,
|
|
39
|
+
SelectScrollUpButton,
|
|
40
|
+
SelectSeparator,
|
|
41
|
+
SelectTrigger,
|
|
42
|
+
SelectValue,
|
|
43
|
+
} from "./select";
|
|
44
|
+
export {
|
|
45
|
+
Table,
|
|
46
|
+
TableBody,
|
|
47
|
+
TableCaption,
|
|
48
|
+
TableCell,
|
|
49
|
+
TableFooter,
|
|
50
|
+
TableHead,
|
|
51
|
+
TableHeader,
|
|
52
|
+
TableRow,
|
|
53
|
+
} from "./table";
|
|
54
|
+
export { Tabs, TabsContent, TabsList, TabsTrigger, tabsListVariants } from "./tabs";
|
|
55
|
+
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
|
|
5
|
+
import { cn } from "../lib/utils"
|
|
6
|
+
|
|
7
|
+
function Label({ className, ...props }: React.ComponentProps<"label">) {
|
|
8
|
+
return (
|
|
9
|
+
<label
|
|
10
|
+
data-slot="label"
|
|
11
|
+
className={cn(
|
|
12
|
+
"flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export { Label }
|