路由嵌套修改
This commit is contained in:
1 parent
8ecc32da6d
commit
d6ec0afbd6
16 files changed
+836
-759
No files matched your search
@@ -31,23 +31,25 @@ function BreadcrumbItem({ className, ...props }: React.ComponentProps<"li">) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function BreadcrumbLink({
|
const BreadcrumbLink = React.forwardRef<
|
||||||
asChild,
|
HTMLAnchorElement,
|
||||||
className,
|
React.ComponentProps<"a"> & {
|
||||||
...props
|
asChild?: boolean;
|
||||||
}: React.ComponentProps<"a"> & {
|
}
|
||||||
asChild?: boolean;
|
>(({ asChild, className, ...props }, ref) => {
|
||||||
}) {
|
const Comp = asChild ? Slot : "a";
|
||||||
const Comp = asChild ? Slot : "a";
|
|
||||||
|
return (
|
||||||
return (
|
<Comp
|
||||||
<Comp
|
ref={ref}
|
||||||
data-slot="breadcrumb-link"
|
data-slot="breadcrumb-link"
|
||||||
className={cn("hover:text-foreground transition-colors", className)}
|
className={cn("hover:text-foreground transition-colors", className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
BreadcrumbLink.displayName = "BreadcrumbLink";
|
||||||
|
|
||||||
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
function BreadcrumbPage({ className, ...props }: React.ComponentProps<"span">) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { Slot } from "@radix-ui/react-slot";
|
import { Slot } from "@radix-ui/react-slot";
|
||||||
import { cva, type VariantProps } from "class-variance-authority";
|
import { cva, type VariantProps } from "class-variance-authority";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -37,27 +37,27 @@ const buttonVariants = cva(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function Button({
|
const Button = React.forwardRef<
|
||||||
className,
|
HTMLButtonElement,
|
||||||
variant = "default",
|
React.ComponentProps<"button"> &
|
||||||
size = "default",
|
VariantProps<typeof buttonVariants> & {
|
||||||
asChild = false,
|
asChild?: boolean;
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<"button"> &
|
>(({ className, variant = "default", size = "default", asChild = false, ...props }, ref) => {
|
||||||
VariantProps<typeof buttonVariants> & {
|
const Comp = asChild ? Slot : "button";
|
||||||
asChild?: boolean;
|
|
||||||
}) {
|
return (
|
||||||
const Comp = asChild ? Slot : "button";
|
<Comp
|
||||||
|
ref={ref}
|
||||||
return (
|
data-slot="button"
|
||||||
<Comp
|
{...(variant !== undefined && { "data-variant": variant })}
|
||||||
data-slot="button"
|
{...(size !== undefined && { "data-size": size })}
|
||||||
{...(variant !== undefined && { "data-variant": variant })}
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
{...(size !== undefined && { "data-size": size })}
|
{...props}
|
||||||
className={cn(buttonVariants({ variant, size, className }))}
|
/>
|
||||||
{...props}
|
);
|
||||||
/>
|
});
|
||||||
);
|
|
||||||
}
|
Button.displayName = "Button";
|
||||||
|
|
||||||
export { Button, buttonVariants };
|
export { Button, buttonVariants };
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
import * as React from "react";
|
||||||
|
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
|
||||||
|
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
@@ -10,28 +11,37 @@ function Collapsible({
|
|||||||
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function CollapsibleTrigger({
|
const CollapsibleTrigger = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof CollapsiblePrimitive.CollapsibleTrigger>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleTrigger>
|
||||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<CollapsiblePrimitive.CollapsibleTrigger
|
<CollapsiblePrimitive.CollapsibleTrigger
|
||||||
data-slot="collapsible-trigger"
|
ref={ref}
|
||||||
className={cn("cursor-pointer", className)}
|
data-slot="collapsible-trigger"
|
||||||
{...props}
|
className={cn("cursor-pointer", className)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
function CollapsibleContent({
|
|
||||||
...props
|
CollapsibleTrigger.displayName =
|
||||||
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
|
CollapsiblePrimitive.CollapsibleTrigger.displayName;
|
||||||
return (
|
|
||||||
<CollapsiblePrimitive.CollapsibleContent
|
const CollapsibleContent = React.forwardRef<
|
||||||
data-slot="collapsible-content"
|
React.ElementRef<typeof CollapsiblePrimitive.CollapsibleContent>,
|
||||||
{...props}
|
React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>
|
||||||
/>
|
>(({ ...props }, ref) => {
|
||||||
);
|
return (
|
||||||
}
|
<CollapsiblePrimitive.CollapsibleContent
|
||||||
|
ref={ref}
|
||||||
|
data-slot="collapsible-content"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
CollapsibleContent.displayName =
|
||||||
|
CollapsiblePrimitive.CollapsibleContent.displayName;
|
||||||
|
|
||||||
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
export { Collapsible, CollapsibleTrigger, CollapsibleContent };
|
||||||
@@ -12,11 +12,20 @@ function Dialog({
|
|||||||
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
return <DialogPrimitive.Root data-slot="dialog" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogTrigger({
|
const DialogTrigger = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof DialogPrimitive.Trigger>,
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Trigger>) {
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Trigger>
|
||||||
return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;
|
>(({ ...props }, ref) => {
|
||||||
}
|
return (
|
||||||
|
<DialogPrimitive.Trigger
|
||||||
|
ref={ref}
|
||||||
|
data-slot="dialog-trigger"
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
DialogTrigger.displayName = DialogPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
function DialogPortal({
|
function DialogPortal({
|
||||||
...props
|
...props
|
||||||
@@ -24,61 +33,68 @@ function DialogPortal({
|
|||||||
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DialogClose({
|
const DialogClose = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof DialogPrimitive.Close>,
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Close>) {
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Close>
|
||||||
return <DialogPrimitive.Close data-slot="dialog-close" {...props} />;
|
>(({ ...props }, ref) => {
|
||||||
}
|
return <DialogPrimitive.Close ref={ref} data-slot="dialog-close" {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
DialogClose.displayName = DialogPrimitive.Close.displayName;
|
||||||
|
|
||||||
function DialogOverlay({
|
const DialogOverlay = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Overlay>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<DialogPrimitive.Overlay
|
<DialogPrimitive.Overlay
|
||||||
data-slot="dialog-overlay"
|
ref={ref}
|
||||||
className={cn(
|
data-slot="dialog-overlay"
|
||||||
"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",
|
className={cn(
|
||||||
className,
|
"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",
|
||||||
)}
|
className,
|
||||||
{...props}
|
)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
function DialogContent({
|
const DialogContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||||
children,
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
||||||
showCloseButton = true,
|
showCloseButton?: boolean;
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
|
>(({ className, children, showCloseButton = true, ...props }, ref) => {
|
||||||
showCloseButton?: boolean;
|
return (
|
||||||
}) {
|
<DialogPortal data-slot="dialog-portal">
|
||||||
return (
|
<DialogOverlay />
|
||||||
<DialogPortal data-slot="dialog-portal">
|
<DialogPrimitive.Content
|
||||||
<DialogOverlay />
|
ref={ref}
|
||||||
<DialogPrimitive.Content
|
data-slot="dialog-content"
|
||||||
data-slot="dialog-content"
|
className={cn(
|
||||||
className={cn(
|
"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 outline-none sm:max-w-lg",
|
||||||
"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 outline-none sm:max-w-lg",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...props}
|
||||||
{...props}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
{showCloseButton && (
|
||||||
{showCloseButton && (
|
<DialogPrimitive.Close
|
||||||
<DialogPrimitive.Close
|
data-slot="dialog-close"
|
||||||
data-slot="dialog-close"
|
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"
|
||||||
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"
|
>
|
||||||
>
|
<XIcon />
|
||||||
<XIcon />
|
<span className="sr-only">Close</span>
|
||||||
<span className="sr-only">Close</span>
|
</DialogPrimitive.Close>
|
||||||
</DialogPrimitive.Close>
|
)}
|
||||||
)}
|
</DialogPrimitive.Content>
|
||||||
</DialogPrimitive.Content>
|
</DialogPortal>
|
||||||
</DialogPortal>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||||
|
|
||||||
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
function DialogHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -20,36 +20,42 @@ function DropdownMenuPortal({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuTrigger({
|
const DropdownMenuTrigger = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof DropdownMenuPrimitive.Trigger>,
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Trigger>
|
||||||
return (
|
>(({ ...props }, ref) => {
|
||||||
<DropdownMenuPrimitive.Trigger
|
return (
|
||||||
data-slot="dropdown-menu-trigger"
|
<DropdownMenuPrimitive.Trigger
|
||||||
{...props}
|
ref={ref}
|
||||||
/>
|
data-slot="dropdown-menu-trigger"
|
||||||
);
|
{...props}
|
||||||
}
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
DropdownMenuTrigger.displayName = DropdownMenuPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
function DropdownMenuContent({
|
const DropdownMenuContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||||
sideOffset = 4,
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||||
...props
|
>(({ className, sideOffset = 4, ...props }, ref) => {
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {
|
return (
|
||||||
return (
|
<DropdownMenuPrimitive.Portal>
|
||||||
<DropdownMenuPrimitive.Portal>
|
<DropdownMenuPrimitive.Content
|
||||||
<DropdownMenuPrimitive.Content
|
ref={ref}
|
||||||
data-slot="dropdown-menu-content"
|
data-slot="dropdown-menu-content"
|
||||||
sideOffset={sideOffset}
|
sideOffset={sideOffset}
|
||||||
className={cn(
|
className={cn(
|
||||||
"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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
"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 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
</DropdownMenuPrimitive.Portal>
|
</DropdownMenuPrimitive.Portal>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||||
|
|
||||||
function DropdownMenuGroup({
|
function DropdownMenuGroup({
|
||||||
...props
|
...props
|
||||||
@@ -59,28 +65,29 @@ function DropdownMenuGroup({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuItem({
|
const DropdownMenuItem = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||||
inset,
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||||
variant = "default",
|
inset?: boolean;
|
||||||
...props
|
variant?: "default" | "destructive";
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
|
}
|
||||||
inset?: boolean;
|
>(({ className, inset, variant = "default", ...props }, ref) => {
|
||||||
variant?: "default" | "destructive";
|
return (
|
||||||
}) {
|
<DropdownMenuPrimitive.Item
|
||||||
return (
|
ref={ref}
|
||||||
<DropdownMenuPrimitive.Item
|
data-slot="dropdown-menu-item"
|
||||||
data-slot="dropdown-menu-item"
|
data-inset={inset}
|
||||||
data-inset={inset}
|
data-variant={variant}
|
||||||
data-variant={variant}
|
className={cn(
|
||||||
className={cn(
|
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...props}
|
||||||
{...props}
|
/>
|
||||||
/>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||||
|
|
||||||
function DropdownMenuCheckboxItem({
|
function DropdownMenuCheckboxItem({
|
||||||
className,
|
className,
|
||||||
@@ -198,45 +205,51 @@ function DropdownMenuSub({
|
|||||||
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function DropdownMenuSubTrigger({
|
const DropdownMenuSubTrigger = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||||
inset,
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||||
children,
|
inset?: boolean;
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
|
>(({ className, inset, children, ...props }, ref) => {
|
||||||
inset?: boolean;
|
return (
|
||||||
}) {
|
<DropdownMenuPrimitive.SubTrigger
|
||||||
return (
|
ref={ref}
|
||||||
<DropdownMenuPrimitive.SubTrigger
|
data-slot="dropdown-menu-sub-trigger"
|
||||||
data-slot="dropdown-menu-sub-trigger"
|
data-inset={inset}
|
||||||
data-inset={inset}
|
className={cn(
|
||||||
className={cn(
|
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
"focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...props}
|
||||||
{...props}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
<ChevronRightIcon className="ml-auto size-4" />
|
||||||
<ChevronRightIcon className="ml-auto size-4" />
|
</DropdownMenuPrimitive.SubTrigger>
|
||||||
</DropdownMenuPrimitive.SubTrigger>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
DropdownMenuSubTrigger.displayName =
|
||||||
|
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||||
|
|
||||||
function DropdownMenuSubContent({
|
const DropdownMenuSubContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||||
}: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<DropdownMenuPrimitive.SubContent
|
<DropdownMenuPrimitive.SubContent
|
||||||
data-slot="dropdown-menu-sub-content"
|
ref={ref}
|
||||||
className={cn(
|
data-slot="dropdown-menu-sub-content"
|
||||||
"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 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
className={cn(
|
||||||
className,
|
"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 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg",
|
||||||
)}
|
className,
|
||||||
{...props}
|
)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
DropdownMenuSubContent.displayName =
|
||||||
|
DropdownMenuPrimitive.SubContent.displayName;
|
||||||
|
|
||||||
export {
|
export {
|
||||||
DropdownMenu,
|
DropdownMenu,
|
||||||
|
|||||||
@@ -11,34 +11,42 @@ function HoverCard({
|
|||||||
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
|
return <HoverCardPrimitive.Root data-slot="hover-card" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function HoverCardTrigger({
|
const HoverCardTrigger = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof HoverCardPrimitive.Trigger>,
|
||||||
}: React.ComponentProps<typeof HoverCardPrimitive.Trigger>) {
|
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger>
|
||||||
return (
|
>(({ ...props }, ref) => {
|
||||||
<HoverCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
|
return (
|
||||||
);
|
<HoverCardPrimitive.Trigger
|
||||||
}
|
ref={ref}
|
||||||
|
data-slot="hover-card-trigger"
|
||||||
function HoverCardContent({
|
{...props}
|
||||||
className,
|
/>
|
||||||
align = "center",
|
);
|
||||||
sideOffset = 4,
|
});
|
||||||
...props
|
|
||||||
}: React.ComponentProps<typeof HoverCardPrimitive.Content>) {
|
HoverCardTrigger.displayName = HoverCardPrimitive.Trigger.displayName;
|
||||||
return (
|
|
||||||
<HoverCardPrimitive.Portal data-slot="hover-card-portal">
|
const HoverCardContent = React.forwardRef<
|
||||||
<HoverCardPrimitive.Content
|
React.ElementRef<typeof HoverCardPrimitive.Content>,
|
||||||
data-slot="hover-card-content"
|
React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
|
||||||
align={align}
|
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => {
|
||||||
sideOffset={sideOffset}
|
return (
|
||||||
className={cn(
|
<HoverCardPrimitive.Portal data-slot="hover-card-portal">
|
||||||
"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-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
<HoverCardPrimitive.Content
|
||||||
className,
|
ref={ref}
|
||||||
)}
|
data-slot="hover-card-content"
|
||||||
{...props}
|
align={align}
|
||||||
/>
|
sideOffset={sideOffset}
|
||||||
</HoverCardPrimitive.Portal>
|
className={cn(
|
||||||
);
|
"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-64 origin-(--radix-hover-card-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||||
}
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</HoverCardPrimitive.Portal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
HoverCardContent.displayName = HoverCardPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
export { HoverCard, HoverCardTrigger, HoverCardContent };
|
||||||
@@ -24,68 +24,69 @@ function SelectValue({
|
|||||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
return <SelectPrimitive.Value data-slot="select-value" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectTrigger({
|
const SelectTrigger = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||||
size = "default",
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> & {
|
||||||
children,
|
size?: "sm" | "default";
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
|
>(({ className, size = "default", children, ...props }, ref) => {
|
||||||
size?: "sm" | "default";
|
return (
|
||||||
}) {
|
<SelectPrimitive.Trigger
|
||||||
return (
|
ref={ref}
|
||||||
<SelectPrimitive.Trigger
|
data-slot="select-trigger"
|
||||||
data-slot="select-trigger"
|
data-size={size}
|
||||||
data-size={size}
|
className={cn(
|
||||||
className={cn(
|
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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 dark:hover:bg-input/50 flex w-fit cursor-pointer items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground 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 dark:hover:bg-input/50 flex w-fit cursor-pointer items-center justify-between gap-2 rounded-md border bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...props}
|
||||||
{...props}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
<SelectPrimitive.Icon asChild>
|
||||||
<SelectPrimitive.Icon asChild>
|
<ChevronDownIcon className="size-4 opacity-50" />
|
||||||
<ChevronDownIcon className="size-4 opacity-50" />
|
</SelectPrimitive.Icon>
|
||||||
</SelectPrimitive.Icon>
|
</SelectPrimitive.Trigger>
|
||||||
</SelectPrimitive.Trigger>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
function SelectContent({
|
const SelectContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||||
children,
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||||
position = "item-aligned",
|
>(({ className, children, position = "item-aligned", align = "center", ...props }, ref) => {
|
||||||
align = "center",
|
return (
|
||||||
...props
|
<SelectPrimitive.Portal>
|
||||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
<SelectPrimitive.Content
|
||||||
return (
|
ref={ref}
|
||||||
<SelectPrimitive.Portal>
|
data-slot="select-content"
|
||||||
<SelectPrimitive.Content
|
className={cn(
|
||||||
data-slot="select-content"
|
"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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
||||||
className={cn(
|
position === "popper" &&
|
||||||
"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 relative z-50 max-h-(--radix-select-content-available-height) min-w-[8rem] origin-(--radix-select-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border shadow-md",
|
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||||
position === "popper" &&
|
className,
|
||||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
)}
|
||||||
className,
|
position={position}
|
||||||
)}
|
align={align}
|
||||||
position={position}
|
{...props}
|
||||||
align={align}
|
>
|
||||||
{...props}
|
<SelectScrollUpButton />
|
||||||
>
|
<SelectPrimitive.Viewport
|
||||||
<SelectScrollUpButton />
|
className={cn(
|
||||||
<SelectPrimitive.Viewport
|
"p-1",
|
||||||
className={cn(
|
position === "popper" &&
|
||||||
"p-1",
|
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
|
||||||
position === "popper" &&
|
)}
|
||||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
|
>
|
||||||
)}
|
{children}
|
||||||
>
|
</SelectPrimitive.Viewport>
|
||||||
{children}
|
<SelectScrollDownButton />
|
||||||
</SelectPrimitive.Viewport>
|
</SelectPrimitive.Content>
|
||||||
<SelectScrollDownButton />
|
</SelectPrimitive.Portal>
|
||||||
</SelectPrimitive.Content>
|
);
|
||||||
</SelectPrimitive.Portal>
|
});
|
||||||
);
|
|
||||||
}
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||||
|
|
||||||
function SelectLabel({
|
function SelectLabel({
|
||||||
className,
|
className,
|
||||||
@@ -100,32 +101,34 @@ function SelectLabel({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SelectItem({
|
const SelectItem = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||||
children,
|
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||||
...props
|
>(({ className, children, ...props }, ref) => {
|
||||||
}: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
return (
|
||||||
return (
|
<SelectPrimitive.Item
|
||||||
<SelectPrimitive.Item
|
ref={ref}
|
||||||
data-slot="select-item"
|
data-slot="select-item"
|
||||||
className={cn(
|
className={cn(
|
||||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-pointer items-center gap-2 rounded-sm py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2",
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
data-slot="select-item-indicator"
|
data-slot="select-item-indicator"
|
||||||
className="absolute right-2 flex size-3.5 items-center justify-center"
|
className="absolute right-2 flex size-3.5 items-center justify-center"
|
||||||
>
|
>
|
||||||
<SelectPrimitive.ItemIndicator>
|
<SelectPrimitive.ItemIndicator>
|
||||||
<CheckIcon className="size-4" />
|
<CheckIcon className="size-4" />
|
||||||
</SelectPrimitive.ItemIndicator>
|
</SelectPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||||
|
|
||||||
function SelectSeparator({
|
function SelectSeparator({
|
||||||
className,
|
className,
|
||||||
|
|||||||
@@ -10,17 +10,23 @@ function Sheet({ ...props }: React.ComponentProps<typeof SheetPrimitive.Root>) {
|
|||||||
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
return <SheetPrimitive.Root data-slot="sheet" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetTrigger({
|
const SheetTrigger = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof SheetPrimitive.Trigger>,
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Trigger>) {
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Trigger>
|
||||||
return <SheetPrimitive.Trigger data-slot="sheet-trigger" {...props} />;
|
>(({ ...props }, ref) => {
|
||||||
}
|
return <SheetPrimitive.Trigger ref={ref} data-slot="sheet-trigger" {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
SheetTrigger.displayName = SheetPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
function SheetClose({
|
const SheetClose = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof SheetPrimitive.Close>,
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Close>) {
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Close>
|
||||||
return <SheetPrimitive.Close data-slot="sheet-close" {...props} />;
|
>(({ ...props }, ref) => {
|
||||||
}
|
return <SheetPrimitive.Close ref={ref} data-slot="sheet-close" {...props} />;
|
||||||
|
});
|
||||||
|
|
||||||
|
SheetClose.displayName = SheetPrimitive.Close.displayName;
|
||||||
|
|
||||||
function SheetPortal({
|
function SheetPortal({
|
||||||
...props
|
...props
|
||||||
@@ -28,58 +34,62 @@ function SheetPortal({
|
|||||||
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
return <SheetPrimitive.Portal data-slot="sheet-portal" {...props} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SheetOverlay({
|
const SheetOverlay = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Overlay>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<SheetPrimitive.Overlay
|
<SheetPrimitive.Overlay
|
||||||
data-slot="sheet-overlay"
|
ref={ref}
|
||||||
className={cn(
|
data-slot="sheet-overlay"
|
||||||
"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",
|
className={cn(
|
||||||
className,
|
"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",
|
||||||
)}
|
className,
|
||||||
{...props}
|
)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
|
||||||
|
|
||||||
function SheetContent({
|
const SheetContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof SheetPrimitive.Content>,
|
||||||
children,
|
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & {
|
||||||
side = "right",
|
side?: "top" | "right" | "bottom" | "left";
|
||||||
...props
|
}
|
||||||
}: React.ComponentProps<typeof SheetPrimitive.Content> & {
|
>(({ className, children, side = "right", ...props }, ref) => {
|
||||||
side?: "top" | "right" | "bottom" | "left";
|
return (
|
||||||
}) {
|
<SheetPortal>
|
||||||
return (
|
<SheetOverlay />
|
||||||
<SheetPortal>
|
<SheetPrimitive.Content
|
||||||
<SheetOverlay />
|
ref={ref}
|
||||||
<SheetPrimitive.Content
|
data-slot="sheet-content"
|
||||||
data-slot="sheet-content"
|
className={cn(
|
||||||
className={cn(
|
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
||||||
"bg-background data-[state=open]:animate-in data-[state=closed]:animate-out fixed z-50 flex flex-col gap-4 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
side === "right" &&
|
||||||
side === "right" &&
|
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
|
||||||
"data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
|
side === "left" &&
|
||||||
side === "left" &&
|
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
|
||||||
"data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
|
side === "top" &&
|
||||||
side === "top" &&
|
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
|
||||||
"data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top inset-x-0 top-0 h-auto border-b",
|
side === "bottom" &&
|
||||||
side === "bottom" &&
|
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
||||||
"data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom inset-x-0 bottom-0 h-auto border-t",
|
className,
|
||||||
className,
|
)}
|
||||||
)}
|
{...props}
|
||||||
{...props}
|
>
|
||||||
>
|
{children}
|
||||||
{children}
|
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary 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">
|
||||||
<SheetPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-secondary 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">
|
<XIcon className="size-4" />
|
||||||
<XIcon className="size-4" />
|
<span className="sr-only">Close</span>
|
||||||
<span className="sr-only">Close</span>
|
</SheetPrimitive.Close>
|
||||||
</SheetPrimitive.Close>
|
</SheetPrimitive.Content>
|
||||||
</SheetPrimitive.Content>
|
</SheetPortal>
|
||||||
</SheetPortal>
|
);
|
||||||
);
|
});
|
||||||
}
|
|
||||||
|
SheetContent.displayName = SheetPrimitive.Content.displayName;
|
||||||
|
|
||||||
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
function SheetHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -397,49 +397,53 @@ function SidebarGroup({ className, ...props }: React.ComponentProps<"div">) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SidebarGroupLabel({
|
const SidebarGroupLabel = React.forwardRef<
|
||||||
className,
|
HTMLDivElement,
|
||||||
asChild = false,
|
React.ComponentProps<"div"> & { asChild?: boolean }
|
||||||
...props
|
>(({ className, asChild = false, ...props }, ref) => {
|
||||||
}: React.ComponentProps<"div"> & { asChild?: boolean }) {
|
const Comp = asChild ? Slot : "div";
|
||||||
const Comp = asChild ? Slot : "div";
|
|
||||||
|
return (
|
||||||
|
<Comp
|
||||||
|
ref={ref}
|
||||||
|
data-slot="sidebar-group-label"
|
||||||
|
data-sidebar="group-label"
|
||||||
|
className={cn(
|
||||||
|
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
|
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
SidebarGroupLabel.displayName = "SidebarGroupLabel";
|
||||||
|
|
||||||
return (
|
const SidebarGroupAction = React.forwardRef<
|
||||||
<Comp
|
HTMLButtonElement,
|
||||||
data-slot="sidebar-group-label"
|
React.ComponentProps<"button"> & { asChild?: boolean }
|
||||||
data-sidebar="group-label"
|
>(({ className, asChild = false, ...props }, ref) => {
|
||||||
className={cn(
|
const Comp = asChild ? Slot : "button";
|
||||||
"text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
||||||
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
|
return (
|
||||||
className,
|
<Comp
|
||||||
)}
|
ref={ref}
|
||||||
{...props}
|
data-slot="sidebar-group-action"
|
||||||
/>
|
data-sidebar="group-action"
|
||||||
);
|
className={cn(
|
||||||
}
|
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
|
// Increases the hit area of the button on mobile.
|
||||||
function SidebarGroupAction({
|
"after:absolute after:-inset-2 md:after:hidden",
|
||||||
className,
|
"group-data-[collapsible=icon]:hidden",
|
||||||
asChild = false,
|
className,
|
||||||
...props
|
)}
|
||||||
}: React.ComponentProps<"button"> & { asChild?: boolean }) {
|
{...props}
|
||||||
const Comp = asChild ? Slot : "button";
|
/>
|
||||||
|
);
|
||||||
return (
|
});
|
||||||
<Comp
|
|
||||||
data-slot="sidebar-group-action"
|
SidebarGroupAction.displayName = "SidebarGroupAction";
|
||||||
data-sidebar="group-action"
|
|
||||||
className={cn(
|
|
||||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute top-3.5 right-3 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
||||||
// Increases the hit area of the button on mobile.
|
|
||||||
"after:absolute after:-inset-2 md:after:hidden",
|
|
||||||
"group-data-[collapsible=icon]:hidden",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SidebarGroupContent({
|
function SidebarGroupContent({
|
||||||
className,
|
className,
|
||||||
@@ -499,87 +503,99 @@ const sidebarMenuButtonVariants = cva(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function SidebarMenuButton({
|
const SidebarMenuButton = React.forwardRef<
|
||||||
asChild = false,
|
HTMLButtonElement,
|
||||||
isActive = false,
|
React.ComponentProps<"button"> & {
|
||||||
variant = "default",
|
asChild?: boolean;
|
||||||
size = "default",
|
isActive?: boolean;
|
||||||
tooltip,
|
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
|
||||||
className,
|
} & VariantProps<typeof sidebarMenuButtonVariants>
|
||||||
...props
|
>(
|
||||||
}: React.ComponentProps<"button"> & {
|
(
|
||||||
asChild?: boolean;
|
{
|
||||||
isActive?: boolean;
|
asChild = false,
|
||||||
tooltip?: string | React.ComponentProps<typeof TooltipContent>;
|
isActive = false,
|
||||||
} & VariantProps<typeof sidebarMenuButtonVariants>) {
|
variant = "default",
|
||||||
const Comp = asChild ? Slot : "button";
|
size = "default",
|
||||||
const { isMobile, state } = useSidebar();
|
tooltip,
|
||||||
|
className,
|
||||||
|
...props
|
||||||
|
},
|
||||||
|
ref,
|
||||||
|
) => {
|
||||||
|
const Comp = asChild ? Slot : "button";
|
||||||
|
const { isMobile, state } = useSidebar();
|
||||||
|
|
||||||
|
const button = (
|
||||||
|
<Comp
|
||||||
|
ref={ref}
|
||||||
|
data-slot="sidebar-menu-button"
|
||||||
|
data-sidebar="menu-button"
|
||||||
|
data-size={size}
|
||||||
|
data-active={isActive}
|
||||||
|
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!tooltip) {
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof tooltip === "string") {
|
||||||
|
tooltip = {
|
||||||
|
children: tooltip,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip>
|
||||||
|
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
||||||
|
<TooltipContent
|
||||||
|
side="right"
|
||||||
|
align="center"
|
||||||
|
hidden={state !== "collapsed" || isMobile}
|
||||||
|
{...tooltip}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
SidebarMenuButton.displayName = "SidebarMenuButton";
|
||||||
|
|
||||||
const button = (
|
const SidebarMenuAction = React.forwardRef<
|
||||||
<Comp
|
HTMLButtonElement,
|
||||||
data-slot="sidebar-menu-button"
|
React.ComponentProps<"button"> & {
|
||||||
data-sidebar="menu-button"
|
asChild?: boolean;
|
||||||
data-size={size}
|
showOnHover?: boolean;
|
||||||
data-active={isActive}
|
}
|
||||||
className={cn(sidebarMenuButtonVariants({ variant, size }), className)}
|
>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
|
||||||
{...props}
|
const Comp = asChild ? Slot : "button";
|
||||||
/>
|
|
||||||
);
|
return (
|
||||||
|
<Comp
|
||||||
if (!tooltip) {
|
ref={ref}
|
||||||
return button;
|
data-slot="sidebar-menu-action"
|
||||||
}
|
data-sidebar="menu-action"
|
||||||
|
className={cn(
|
||||||
if (typeof tooltip === "string") {
|
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
tooltip = {
|
// Increases the hit area of the button on mobile.
|
||||||
children: tooltip,
|
"after:absolute after:-inset-2 md:after:hidden",
|
||||||
};
|
"peer-data-[size=sm]/menu-button:top-1",
|
||||||
}
|
"peer-data-[size=default]/menu-button:top-1.5",
|
||||||
|
"peer-data-[size=lg]/menu-button:top-2.5",
|
||||||
return (
|
"group-data-[collapsible=icon]:hidden",
|
||||||
<Tooltip>
|
showOnHover &&
|
||||||
<TooltipTrigger asChild>{button}</TooltipTrigger>
|
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
|
||||||
<TooltipContent
|
className,
|
||||||
side="right"
|
)}
|
||||||
align="center"
|
{...props}
|
||||||
hidden={state !== "collapsed" || isMobile}
|
/>
|
||||||
{...tooltip}
|
);
|
||||||
/>
|
});
|
||||||
</Tooltip>
|
|
||||||
);
|
SidebarMenuAction.displayName = "SidebarMenuAction";
|
||||||
}
|
|
||||||
|
|
||||||
function SidebarMenuAction({
|
|
||||||
className,
|
|
||||||
asChild = false,
|
|
||||||
showOnHover = false,
|
|
||||||
...props
|
|
||||||
}: React.ComponentProps<"button"> & {
|
|
||||||
asChild?: boolean;
|
|
||||||
showOnHover?: boolean;
|
|
||||||
}) {
|
|
||||||
const Comp = asChild ? Slot : "button";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Comp
|
|
||||||
data-slot="sidebar-menu-action"
|
|
||||||
data-sidebar="menu-action"
|
|
||||||
className={cn(
|
|
||||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute top-1.5 right-1 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-hidden transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
||||||
// Increases the hit area of the button on mobile.
|
|
||||||
"after:absolute after:-inset-2 md:after:hidden",
|
|
||||||
"peer-data-[size=sm]/menu-button:top-1",
|
|
||||||
"peer-data-[size=default]/menu-button:top-1.5",
|
|
||||||
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
||||||
"group-data-[collapsible=icon]:hidden",
|
|
||||||
showOnHover &&
|
|
||||||
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0",
|
|
||||||
className,
|
|
||||||
)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function SidebarMenuBadge({
|
function SidebarMenuBadge({
|
||||||
className,
|
className,
|
||||||
@@ -670,37 +686,37 @@ function SidebarMenuSubItem({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function SidebarMenuSubButton({
|
const SidebarMenuSubButton = React.forwardRef<
|
||||||
asChild = false,
|
HTMLAnchorElement,
|
||||||
size = "md",
|
React.ComponentProps<"a"> & {
|
||||||
isActive = false,
|
asChild?: boolean;
|
||||||
className,
|
size?: "sm" | "md";
|
||||||
...props
|
isActive?: boolean;
|
||||||
}: React.ComponentProps<"a"> & {
|
}
|
||||||
asChild?: boolean;
|
>(({ asChild = false, size = "md", isActive = false, className, ...props }, ref) => {
|
||||||
size?: "sm" | "md";
|
const Comp = asChild ? Slot : "a";
|
||||||
isActive?: boolean;
|
|
||||||
}) {
|
return (
|
||||||
const Comp = asChild ? Slot : "a";
|
<Comp
|
||||||
|
ref={ref}
|
||||||
return (
|
data-slot="sidebar-menu-sub-button"
|
||||||
<Comp
|
data-sidebar="menu-sub-button"
|
||||||
data-slot="sidebar-menu-sub-button"
|
data-size={size}
|
||||||
data-sidebar="menu-sub-button"
|
data-active={isActive}
|
||||||
data-size={size}
|
className={cn(
|
||||||
data-active={isActive}
|
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
||||||
className={cn(
|
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
|
||||||
"text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-hidden focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
|
size === "sm" && "text-xs",
|
||||||
"data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground",
|
size === "md" && "text-sm",
|
||||||
size === "sm" && "text-xs",
|
"group-data-[collapsible=icon]:hidden",
|
||||||
size === "md" && "text-sm",
|
className,
|
||||||
"group-data-[collapsible=icon]:hidden",
|
)}
|
||||||
className,
|
{...props}
|
||||||
)}
|
/>
|
||||||
{...props}
|
);
|
||||||
/>
|
});
|
||||||
);
|
|
||||||
}
|
SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Sidebar,
|
Sidebar,
|
||||||
|
|||||||
@@ -40,52 +40,60 @@ const tabsListVariants = cva(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
function TabsList({
|
const TabsList = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof TabsPrimitive.List>,
|
||||||
variant = "default",
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> &
|
||||||
...props
|
VariantProps<typeof tabsListVariants>
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.List> &
|
>(({ className, variant = "default", ...props }, ref) => {
|
||||||
VariantProps<typeof tabsListVariants>) {
|
return (
|
||||||
return (
|
<TabsPrimitive.List
|
||||||
<TabsPrimitive.List
|
ref={ref}
|
||||||
data-slot="tabs-list"
|
data-slot="tabs-list"
|
||||||
data-variant={variant}
|
data-variant={variant}
|
||||||
className={cn(tabsListVariants({ variant }), className)}
|
className={cn(tabsListVariants({ variant }), className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
|
TabsList.displayName = TabsPrimitive.List.displayName;
|
||||||
|
|
||||||
function TabsTrigger({
|
const TabsTrigger = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof TabsPrimitive.Trigger>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.Trigger>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.Trigger
|
<TabsPrimitive.Trigger
|
||||||
data-slot="tabs-trigger"
|
ref={ref}
|
||||||
className={cn(
|
data-slot="tabs-trigger"
|
||||||
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
className={cn(
|
||||||
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
|
"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:outline-ring text-foreground/60 hover:text-foreground dark:text-muted-foreground dark:hover:text-foreground relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap transition-all group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start focus-visible:ring-[3px] focus-visible:outline-1 disabled:pointer-events-none disabled:opacity-50 group-data-[variant=default]/tabs-list:data-[state=active]:shadow-sm group-data-[variant=line]/tabs-list:data-[state=active]:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
|
"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:border-transparent dark:group-data-[variant=line]/tabs-list:data-[state=active]:bg-transparent",
|
||||||
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
|
"data-[state=active]:bg-background dark:data-[state=active]:text-foreground dark:data-[state=active]:border-input dark:data-[state=active]:bg-input/30 data-[state=active]:text-foreground",
|
||||||
className,
|
"after:bg-foreground after:absolute after:opacity-0 after:transition-opacity group-data-[orientation=horizontal]/tabs:after:inset-x-0 group-data-[orientation=horizontal]/tabs:after:bottom-[-5px] group-data-[orientation=horizontal]/tabs:after:h-0.5 group-data-[orientation=vertical]/tabs:after:inset-y-0 group-data-[orientation=vertical]/tabs:after:-right-1 group-data-[orientation=vertical]/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-[state=active]:after:opacity-100",
|
||||||
)}
|
className,
|
||||||
{...props}
|
)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
|
||||||
|
|
||||||
function TabsContent({
|
const TabsContent = React.forwardRef<
|
||||||
className,
|
React.ElementRef<typeof TabsPrimitive.Content>,
|
||||||
...props
|
React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
|
||||||
}: React.ComponentProps<typeof TabsPrimitive.Content>) {
|
>(({ className, ...props }, ref) => {
|
||||||
return (
|
return (
|
||||||
<TabsPrimitive.Content
|
<TabsPrimitive.Content
|
||||||
data-slot="tabs-content"
|
ref={ref}
|
||||||
className={cn("flex-1 outline-none", className)}
|
data-slot="tabs-content"
|
||||||
{...props}
|
className={cn("flex-1 outline-none", className)}
|
||||||
/>
|
{...props}
|
||||||
);
|
/>
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants };
|
||||||
@@ -28,33 +28,43 @@ function Tooltip({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function TooltipTrigger({
|
const TooltipTrigger = React.forwardRef<
|
||||||
...props
|
React.ElementRef<typeof TooltipPrimitive.Trigger>,
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
|
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>
|
||||||
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
|
>(({ ...props }, ref) => {
|
||||||
}
|
return (
|
||||||
|
<TooltipPrimitive.Trigger
|
||||||
function TooltipContent({
|
ref={ref}
|
||||||
className,
|
data-slot="tooltip-trigger"
|
||||||
sideOffset,
|
{...props}
|
||||||
children,
|
/>
|
||||||
...props
|
);
|
||||||
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
|
});
|
||||||
return (
|
|
||||||
<TooltipPrimitive.Portal>
|
TooltipTrigger.displayName = TooltipPrimitive.Trigger.displayName;
|
||||||
<TooltipPrimitive.Content
|
|
||||||
data-slot="tooltip-content"
|
const TooltipContent = React.forwardRef<
|
||||||
sideOffset={sideOffset ?? 4}
|
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||||
className={cn(
|
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||||
"animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 bg-foreground text-background dark:text-foreground z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md border px-3 py-1.5 text-xs text-balance shadow-xs dark:border-white/18 dark:bg-[#050504]",
|
>(({ className, sideOffset, children, ...props }, ref) => {
|
||||||
className,
|
return (
|
||||||
)}
|
<TooltipPrimitive.Portal>
|
||||||
{...props}
|
<TooltipPrimitive.Content
|
||||||
>
|
ref={ref}
|
||||||
{children}
|
data-slot="tooltip-content"
|
||||||
</TooltipPrimitive.Content>
|
sideOffset={sideOffset ?? 4}
|
||||||
</TooltipPrimitive.Portal>
|
className={cn(
|
||||||
);
|
"animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 bg-foreground text-background dark:text-foreground z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md border px-3 py-1.5 text-xs text-balance shadow-xs dark:border-white/18 dark:bg-[#050504]",
|
||||||
}
|
className,
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</TooltipPrimitive.Content>
|
||||||
|
</TooltipPrimitive.Portal>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||||
|
|
||||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||||
@@ -173,91 +173,89 @@ export function RecentChatList() {
|
|||||||
<div className="flex w-full flex-col gap-1">
|
<div className="flex w-full flex-col gap-1">
|
||||||
{visibleThreads.map((thread) => {
|
{visibleThreads.map((thread) => {
|
||||||
const isActive = pathOfThread(thread) === pathname;
|
const isActive = pathOfThread(thread) === pathname;
|
||||||
return (
|
return (
|
||||||
<SidebarMenuItem
|
<SidebarMenuItem
|
||||||
key={thread.thread_id}
|
key={thread.thread_id}
|
||||||
className="group/side-menu-item"
|
className="group/side-menu-item"
|
||||||
>
|
>
|
||||||
<SidebarMenuButton isActive={isActive} asChild>
|
<SidebarMenuButton isActive={isActive} asChild>
|
||||||
<div>
|
<Link
|
||||||
<Link
|
className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
|
||||||
className="text-muted-foreground block w-full whitespace-nowrap group-hover/side-menu-item:overflow-hidden"
|
href={pathOfThread(thread)}
|
||||||
href={pathOfThread(thread)}
|
>
|
||||||
>
|
{titleOfThread(thread)}
|
||||||
{titleOfThread(thread)}
|
</Link>
|
||||||
</Link>
|
</SidebarMenuButton>
|
||||||
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true" && (
|
{env.NEXT_PUBLIC_STATIC_WEBSITE_ONLY !== "true" && (
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
<DropdownMenuTrigger asChild>
|
<DropdownMenuTrigger asChild>
|
||||||
<SidebarMenuAction
|
<SidebarMenuAction
|
||||||
showOnHover
|
showOnHover
|
||||||
className="bg-background/50 hover:bg-background"
|
className="bg-background/50 hover:bg-background"
|
||||||
>
|
>
|
||||||
<MoreHorizontal />
|
<MoreHorizontal />
|
||||||
<span className="sr-only">{t.common.more}</span>
|
<span className="sr-only">{t.common.more}</span>
|
||||||
</SidebarMenuAction>
|
</SidebarMenuAction>
|
||||||
</DropdownMenuTrigger>
|
</DropdownMenuTrigger>
|
||||||
<DropdownMenuContent
|
<DropdownMenuContent
|
||||||
className="w-48 rounded-lg"
|
className="w-48 rounded-lg"
|
||||||
side={"right"}
|
side={"right"}
|
||||||
align={"start"}
|
align={"start"}
|
||||||
>
|
>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onSelect={() =>
|
onSelect={() =>
|
||||||
handleRenameClick(
|
handleRenameClick(
|
||||||
thread.thread_id,
|
thread.thread_id,
|
||||||
titleOfThread(thread),
|
titleOfThread(thread),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Pencil className="text-muted-foreground" />
|
<Pencil className="text-muted-foreground" />
|
||||||
<span>{t.common.rename}</span>
|
<span>{t.common.rename}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onSelect={() => handleShare(thread)}
|
onSelect={() => handleShare(thread)}
|
||||||
>
|
>
|
||||||
<Share2 className="text-muted-foreground" />
|
<Share2 className="text-muted-foreground" />
|
||||||
<span>{t.common.share}</span>
|
<span>{t.common.share}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuSub>
|
<DropdownMenuSub>
|
||||||
<DropdownMenuSubTrigger>
|
<DropdownMenuSubTrigger>
|
||||||
<Download className="text-muted-foreground" />
|
<Download className="text-muted-foreground" />
|
||||||
<span>{t.common.export}</span>
|
<span>{t.common.export}</span>
|
||||||
</DropdownMenuSubTrigger>
|
</DropdownMenuSubTrigger>
|
||||||
<DropdownMenuSubContent>
|
<DropdownMenuSubContent>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onSelect={() =>
|
onSelect={() =>
|
||||||
handleExport(thread, "markdown")
|
handleExport(thread, "markdown")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FileText className="text-muted-foreground" />
|
<FileText className="text-muted-foreground" />
|
||||||
<span>{t.common.exportAsMarkdown}</span>
|
<span>{t.common.exportAsMarkdown}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onSelect={() =>
|
onSelect={() =>
|
||||||
handleExport(thread, "json")
|
handleExport(thread, "json")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<FileJson className="text-muted-foreground" />
|
<FileJson className="text-muted-foreground" />
|
||||||
<span>{t.common.exportAsJSON}</span>
|
<span>{t.common.exportAsJSON}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuSubContent>
|
</DropdownMenuSubContent>
|
||||||
</DropdownMenuSub>
|
</DropdownMenuSub>
|
||||||
<DropdownMenuSeparator />
|
<DropdownMenuSeparator />
|
||||||
<DropdownMenuItem
|
<DropdownMenuItem
|
||||||
onSelect={() => handleDelete(thread.thread_id)}
|
onSelect={() => handleDelete(thread.thread_id)}
|
||||||
>
|
>
|
||||||
<Trash2 className="text-muted-foreground" />
|
<Trash2 className="text-muted-foreground" />
|
||||||
<span>{t.common.delete}</span>
|
<span>{t.common.delete}</span>
|
||||||
</DropdownMenuItem>
|
</DropdownMenuItem>
|
||||||
</DropdownMenuContent>
|
</DropdownMenuContent>
|
||||||
</DropdownMenu>
|
</DropdownMenu>
|
||||||
)}
|
)}
|
||||||
</div>
|
</SidebarMenuItem>
|
||||||
</SidebarMenuButton>
|
);
|
||||||
</SidebarMenuItem>
|
})}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</SidebarMenu>
|
</SidebarMenu>
|
||||||
</SidebarGroupContent>
|
</SidebarGroupContent>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ArrowLeftIcon,
|
ArrowLeftIcon,
|
||||||
@@ -17,13 +17,6 @@ import {
|
|||||||
} from "@/components/ai-elements/prompt-input";
|
} from "@/components/ai-elements/prompt-input";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import {
|
|
||||||
Select,
|
|
||||||
SelectContent,
|
|
||||||
SelectItem,
|
|
||||||
SelectTrigger,
|
|
||||||
SelectValue,
|
|
||||||
} from "@/components/ui/select";
|
|
||||||
import { Textarea } from "@/components/ui/textarea";
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
||||||
import {
|
import {
|
||||||
@@ -120,7 +113,7 @@ export default function NewAgentPage() {
|
|||||||
model_name: chatModelInput || undefined,
|
model_name: chatModelInput || undefined,
|
||||||
},
|
},
|
||||||
onToolEnd() {
|
onToolEnd() {
|
||||||
// setup_agent never actually executes in this flow — it gets
|
// setup_agent never actually executes in this flow 鈥?it gets
|
||||||
// intercepted by SetupAgentApprovalMiddleware and the form is filled
|
// intercepted by SetupAgentApprovalMiddleware and the form is filled
|
||||||
// from the approval ToolMessage payload (handleApproveSetupAgent).
|
// from the approval ToolMessage payload (handleApproveSetupAgent).
|
||||||
// No agent record is fetched/refreshed during chat.
|
// No agent record is fetched/refreshed during chat.
|
||||||
@@ -156,7 +149,7 @@ export default function NewAgentPage() {
|
|||||||
if (!name) {
|
if (!name) {
|
||||||
// Names are display-only and may collide, so a timestamped placeholder
|
// Names are display-only and may collide, so a timestamped placeholder
|
||||||
// is safe to send to the backend just to satisfy the required-field
|
// is safe to send to the backend just to satisfy the required-field
|
||||||
// validation. Intentionally NOT written back into the visible input —
|
// validation. Intentionally NOT written back into the visible input 鈥?
|
||||||
// the user wants the name box to stay blank while they chat, and we
|
// the user wants the name box to stay blank while they chat, and we
|
||||||
// refill it later (with the model's proposed name) on setup_agent
|
// refill it later (with the model's proposed name) on setup_agent
|
||||||
// approval.
|
// approval.
|
||||||
@@ -245,7 +238,7 @@ export default function NewAgentPage() {
|
|||||||
// Chat is purely a discussion channel. The agent record is only
|
// Chat is purely a discussion channel. The agent record is only
|
||||||
// created when the user explicitly clicks Save (top-right). If the
|
// created when the user explicitly clicks Save (top-right). If the
|
||||||
// model proposes a config via setup_agent, our approval handler
|
// model proposes a config via setup_agent, our approval handler
|
||||||
// prefills the form locally — it does NOT persist anything.
|
// prefills the form locally 鈥?it does NOT persist anything.
|
||||||
await ensureThreadExists();
|
await ensureThreadExists();
|
||||||
await sendMessage(threadId, { text: trimmed, files: [] });
|
await sendMessage(threadId, { text: trimmed, files: [] });
|
||||||
},
|
},
|
||||||
@@ -255,7 +248,7 @@ export default function NewAgentPage() {
|
|||||||
const handleApproveSetupAgent = useCallback(
|
const handleApproveSetupAgent = useCallback(
|
||||||
async (payload: SetupAgentApprovalPayload) => {
|
async (payload: SetupAgentApprovalPayload) => {
|
||||||
// Approving the model's setup_agent proposal **does not** persist
|
// Approving the model's setup_agent proposal **does not** persist
|
||||||
// anything — it only mirrors the proposal into the form so the user
|
// anything 鈥?it only mirrors the proposal into the form so the user
|
||||||
// can review it. Creation/update happens later when the user clicks
|
// can review it. Creation/update happens later when the user clicks
|
||||||
// the top-right Save button.
|
// the top-right Save button.
|
||||||
const proposedName = payload.name?.trim() ?? "";
|
const proposedName = payload.name?.trim() ?? "";
|
||||||
@@ -338,22 +331,23 @@ export default function NewAgentPage() {
|
|||||||
<span className="text-muted-foreground text-xs">
|
<span className="text-muted-foreground text-xs">
|
||||||
当前对话模型
|
当前对话模型
|
||||||
</span>
|
</span>
|
||||||
<Select
|
<select
|
||||||
value={chatModelInput}
|
value={chatModelInput}
|
||||||
onValueChange={setChatModelInput}
|
onChange={(event) =>
|
||||||
|
setChatModelInput(event.currentTarget.value)
|
||||||
|
}
|
||||||
disabled={isModelsLoading || thread.isLoading}
|
disabled={isModelsLoading || thread.isLoading}
|
||||||
|
className="border-input bg-background h-7 min-w-[10rem] rounded-md border px-2 text-xs shadow-xs outline-none"
|
||||||
>
|
>
|
||||||
<SelectTrigger className="h-7 w-auto min-w-[10rem] gap-2 px-2 text-xs">
|
<option value="" disabled>
|
||||||
<SelectValue placeholder="选择模型" />
|
选择模型
|
||||||
</SelectTrigger>
|
</option>
|
||||||
<SelectContent>
|
{models.map((model) => (
|
||||||
{models.map((model) => (
|
<option key={model.name} value={model.name}>
|
||||||
<SelectItem key={model.name} value={model.name}>
|
{model.display_name || model.name}
|
||||||
{model.display_name || model.name}
|
</option>
|
||||||
</SelectItem>
|
))}
|
||||||
))}
|
</select>
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
</div>
|
</div>
|
||||||
<PromptInput
|
<PromptInput
|
||||||
onSubmit={({ text }) => void handleChatSubmit(text)}
|
onSubmit={({ text }) => void handleChatSubmit(text)}
|
||||||
@@ -405,22 +399,21 @@ export default function NewAgentPage() {
|
|||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<label className="text-sm font-medium">模型</label>
|
<label className="text-sm font-medium">模型</label>
|
||||||
<Select
|
<select
|
||||||
value={modelInput}
|
value={modelInput}
|
||||||
onValueChange={setModelInput}
|
onChange={(event) => setModelInput(event.currentTarget.value)}
|
||||||
disabled={isModelsLoading}
|
disabled={isModelsLoading}
|
||||||
|
className="border-input bg-background h-9 w-full rounded-md border px-3 text-sm shadow-xs outline-none"
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<option value="" disabled>
|
||||||
<SelectValue placeholder="选择模型" />
|
选择模型
|
||||||
</SelectTrigger>
|
</option>
|
||||||
<SelectContent>
|
{models.map((model) => (
|
||||||
{models.map((model) => (
|
<option key={model.name} value={model.name}>
|
||||||
<SelectItem key={model.name} value={model.name}>
|
{model.display_name || model.name}
|
||||||
{model.display_name || model.name}
|
</option>
|
||||||
</SelectItem>
|
))}
|
||||||
))}
|
</select>
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<p className="text-muted-foreground text-xs">
|
<p className="text-muted-foreground text-xs">
|
||||||
该专家被使用时调用的模型。
|
该专家被使用时调用的模型。
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import StrategyRoutes from "./StrategyRoutes";
|
|||||||
import Header from "@/strategy-components/Header";
|
import Header from "@/strategy-components/Header";
|
||||||
|
|
||||||
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
|
// 设为 true 时隐藏侧边栏(开发中,暂未完成)
|
||||||
const SIDEBAR_ENABLED = false;
|
const SIDEBAR_ENABLED = true;
|
||||||
|
|
||||||
function PageLayout() {
|
function PageLayout() {
|
||||||
const [collapsed, setCollapsed] = useState(false);
|
const [collapsed, setCollapsed] = useState(false);
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
import { Navigate, Route, Routes } from "react-router-dom";
|
import { Navigate, Route, Routes } from "react-router-dom";
|
||||||
import type { ReactNode } from "react";
|
|
||||||
import { Toaster } from "sonner";
|
import { Toaster } from "sonner";
|
||||||
|
|
||||||
import { getStoredAuth } from "@/core/auth";
|
import { getStoredAuth } from "@/core/auth";
|
||||||
import { RouteBaseProvider } from "@/core/route-base";
|
import { RouteBaseProvider } from "@/core/route-base";
|
||||||
import { SubtasksProvider } from "@/core/tasks/context";
|
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||||
import { ArtifactsProvider } from "@/components/workspace/artifacts";
|
|
||||||
import { PromptInputProvider } from "@/components/ai-elements/prompt-input";
|
|
||||||
|
|
||||||
import GeneralQA from "@/strategy-components/components/qa/GeneralQA";
|
import GeneralQA from "@/strategy-components/components/qa/GeneralQA";
|
||||||
|
import { ChatRuntime } from "./WorkspaceRoutes";
|
||||||
import AgentsPage from "./AgentsPage";
|
import AgentsPage from "./AgentsPage";
|
||||||
import ChatsPage from "./ChatsPage";
|
import ChatsPage from "./ChatsPage";
|
||||||
import ChatPage from "./ChatPage";
|
import ChatPage from "./ChatPage";
|
||||||
@@ -18,19 +16,10 @@ import ScheduledTasksPage from "./ScheduledTasksPage";
|
|||||||
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
import ScheduledTaskRunDetailPage from "./ScheduledTaskRunDetailPage";
|
||||||
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
import RecommendedQuestionsPage from "./RecommendedQuestionsPage";
|
||||||
|
|
||||||
function ChatRuntime({ children }: { children: ReactNode }) {
|
|
||||||
return (
|
|
||||||
<SubtasksProvider>
|
|
||||||
<ArtifactsProvider>
|
|
||||||
<PromptInputProvider>{children}</PromptInputProvider>
|
|
||||||
</ArtifactsProvider>
|
|
||||||
</SubtasksProvider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function StrategyRoutes() {
|
export default function StrategyRoutes() {
|
||||||
return (
|
return (
|
||||||
<RouteBaseProvider value="/page/strategy">
|
<RouteBaseProvider value="/page/strategy">
|
||||||
|
<SidebarProvider>
|
||||||
<div className="h-full w-full overflow-hidden">
|
<div className="h-full w-full overflow-hidden">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route index element={<Navigate to="qa/general" replace />} />
|
<Route index element={<Navigate to="qa/general" replace />} />
|
||||||
@@ -89,6 +78,7 @@ export default function StrategyRoutes() {
|
|||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
|
</SidebarProvider>
|
||||||
<Toaster position="top-center" />
|
<Toaster position="top-center" />
|
||||||
</RouteBaseProvider>
|
</RouteBaseProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function WorkspaceLayout({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ChatRuntime({ children }: { children: ReactNode }) {
|
export function ChatRuntime({ children }: { children: ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<SubtasksProvider>
|
<SubtasksProvider>
|
||||||
<ArtifactsProvider>
|
<ArtifactsProvider>
|
||||||
|
|||||||
Reference in new issue
Block a user