mirror of
https://github.com/eigent-ai/eigent.git
synced 2026-04-28 03:30:06 +00:00
Some checks are pending
CodeQL Advanced / Analyze (actions) (push) Waiting to run
CodeQL Advanced / Analyze (javascript-typescript) (push) Waiting to run
CodeQL Advanced / Analyze (python) (push) Waiting to run
Pre-commit / pre-commit (push) Waiting to run
Test / Run Python Tests (push) Waiting to run
Co-authored-by: Pakchoioioi <happy.regina.bai@gmail.com> Co-authored-by: Douglas Lai <115660088+Douglasymlai@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Douglas <douglas.ym.lai@gmail.com> Co-authored-by: Wendong-Fan <133094783+Wendong-Fan@users.noreply.github.com> Co-authored-by: Wendong-Fan <w3ndong.fan@gmail.com>
344 lines
9.8 KiB
TypeScript
344 lines
9.8 KiB
TypeScript
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
// ========= Copyright 2025-2026 @ Eigent.ai All Rights Reserved. =========
|
|
|
|
'use client';
|
|
|
|
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
|
import { cva, type VariantProps } from 'class-variance-authority';
|
|
import { AlertCircle, ChevronLeft, X } from 'lucide-react';
|
|
import * as React from 'react';
|
|
|
|
import { Button } from '@/components/ui/button';
|
|
import { TooltipSimple } from '@/components/ui/tooltip';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
const Dialog = DialogPrimitive.Root;
|
|
|
|
const DialogTrigger = DialogPrimitive.Trigger;
|
|
|
|
const DialogPortal = DialogPrimitive.Portal;
|
|
|
|
const DialogClose = DialogPrimitive.Close;
|
|
|
|
const DialogOverlay = React.forwardRef<
|
|
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
>(({ className, ...props }, ref) => (
|
|
<DialogPrimitive.Overlay
|
|
ref={ref}
|
|
className={cn(
|
|
'fixed inset-0 z-50 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
|
|
className
|
|
)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
|
|
export type DialogOverlayVariant = 'default' | 'dark';
|
|
|
|
// Size variants for dialog content
|
|
const dialogContentVariants = cva(
|
|
'fixed left-[50%] top-[50%] z-50 grid w-full translate-x-[-50%] translate-y-[-50%] gap-0 border border-solid border-popup-border bg-popup-bg shadow-perfect duration-200 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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] rounded-xl',
|
|
{
|
|
variants: {
|
|
size: {
|
|
sm: 'max-w-[400px]',
|
|
md: 'max-w-[600px]',
|
|
lg: 'max-w-[900px]',
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
size: 'md',
|
|
},
|
|
}
|
|
);
|
|
|
|
// Enhanced Dialog Content with size variants
|
|
interface DialogContentProps
|
|
extends
|
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,
|
|
VariantProps<typeof dialogContentVariants> {
|
|
showCloseButton?: boolean;
|
|
closeButtonClassName?: string;
|
|
closeButtonIcon?: React.ReactNode;
|
|
onClose?: () => void;
|
|
/** Overlay behind the dialog: 'default' (transparent) or 'dark' (black overlay) */
|
|
overlayVariant?: DialogOverlayVariant;
|
|
}
|
|
|
|
const DialogContent = React.forwardRef<
|
|
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
DialogContentProps
|
|
>(
|
|
(
|
|
{
|
|
className,
|
|
children,
|
|
size,
|
|
showCloseButton = true,
|
|
closeButtonClassName,
|
|
closeButtonIcon,
|
|
onClose,
|
|
overlayVariant = 'default',
|
|
...props
|
|
},
|
|
ref
|
|
) => (
|
|
<DialogPortal>
|
|
<DialogOverlay
|
|
className={overlayVariant === 'dark' ? 'bg-black/40' : undefined}
|
|
style={
|
|
overlayVariant === 'dark'
|
|
? { backgroundColor: 'rgba(0, 0, 0, 0.4)' }
|
|
: undefined
|
|
}
|
|
/>
|
|
<DialogPrimitive.Content
|
|
ref={ref}
|
|
className={cn(
|
|
dialogContentVariants({ size }),
|
|
overlayVariant === 'dark' && 'z-[51]',
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
{showCloseButton && (
|
|
<DialogPrimitive.Close asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
className={cn(
|
|
'absolute right-4 top-4 focus:outline-none focus:ring-0 focus:ring-offset-0',
|
|
closeButtonClassName
|
|
)}
|
|
onClick={onClose}
|
|
>
|
|
{closeButtonIcon || <X className="h-4 w-4" />}
|
|
<span className="sr-only">Close</span>
|
|
</Button>
|
|
</DialogPrimitive.Close>
|
|
)}
|
|
</DialogPrimitive.Content>
|
|
</DialogPortal>
|
|
)
|
|
);
|
|
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
|
|
// Enhanced Dialog Header with title, subtitle, and tooltip support
|
|
interface DialogHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
title?: string;
|
|
subtitle?: string;
|
|
tooltip?: string;
|
|
showTooltip?: boolean;
|
|
showBackButton?: boolean;
|
|
onBackClick?: () => void;
|
|
}
|
|
|
|
const DialogHeader = React.forwardRef<HTMLDivElement, DialogHeaderProps>(
|
|
(
|
|
{
|
|
className,
|
|
title,
|
|
subtitle,
|
|
tooltip,
|
|
showTooltip = false,
|
|
showBackButton = false,
|
|
onBackClick,
|
|
children,
|
|
...props
|
|
},
|
|
ref
|
|
) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
'relative flex w-full shrink-0 items-center justify-between gap-2 overflow-hidden rounded-t-xl bg-popup-surface p-4',
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
{showBackButton && (
|
|
<Button
|
|
variant="ghost"
|
|
size="icon"
|
|
onClick={onBackClick}
|
|
className="h-6 w-6 p-0 hover:bg-transparent"
|
|
>
|
|
<ChevronLeft className="h-4 w-4 text-icon-primary" />
|
|
</Button>
|
|
)}
|
|
<div className="flex flex-col text-center sm:text-left">
|
|
{title && (
|
|
<div className="flex items-center gap-1">
|
|
<DialogPrimitive.Title asChild>
|
|
<span className="my-[1px] text-body-md font-bold text-text-heading">
|
|
{title}
|
|
</span>
|
|
</DialogPrimitive.Title>
|
|
{showTooltip && tooltip && (
|
|
<TooltipSimple content={tooltip}>
|
|
<AlertCircle className="h-4 w-4 text-icon-primary" />
|
|
</TooltipSimple>
|
|
)}
|
|
</div>
|
|
)}
|
|
{subtitle && (
|
|
<DialogPrimitive.Description asChild>
|
|
<span className="mt-1 text-label-sm font-extralight text-text-label">
|
|
{subtitle}
|
|
</span>
|
|
</DialogPrimitive.Description>
|
|
)}
|
|
</div>
|
|
</div>
|
|
{children}
|
|
</div>
|
|
)
|
|
);
|
|
DialogHeader.displayName = 'DialogHeader';
|
|
|
|
// Enhanced Dialog Content section
|
|
const DialogContentSection = React.forwardRef<
|
|
HTMLDivElement,
|
|
React.HTMLAttributes<HTMLDivElement>
|
|
>(({ className, ...props }, ref) => (
|
|
<div ref={ref} className={cn('min-h-0 flex-1 p-4', className)} {...props} />
|
|
));
|
|
DialogContentSection.displayName = 'DialogContentSection';
|
|
|
|
// Enhanced Dialog Footer with button support
|
|
interface DialogFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
showConfirmButton?: boolean;
|
|
showCancelButton?: boolean;
|
|
confirmButtonText?: string;
|
|
cancelButtonText?: string;
|
|
onConfirm?: () => void;
|
|
onCancel?: () => void;
|
|
confirmButtonVariant?:
|
|
| 'primary'
|
|
| 'secondary'
|
|
| 'outline'
|
|
| 'ghost'
|
|
| 'success'
|
|
| 'cuation'
|
|
| 'information'
|
|
| 'warning';
|
|
cancelButtonVariant?:
|
|
| 'primary'
|
|
| 'secondary'
|
|
| 'outline'
|
|
| 'ghost'
|
|
| 'success'
|
|
| 'cuation'
|
|
| 'information'
|
|
| 'warning';
|
|
confirmButtonDisabled?: boolean;
|
|
cancelButtonDisabled?: boolean;
|
|
}
|
|
|
|
const DialogFooter = React.forwardRef<HTMLDivElement, DialogFooterProps>(
|
|
(
|
|
{
|
|
className,
|
|
showConfirmButton = false,
|
|
showCancelButton = false,
|
|
confirmButtonText = 'Confirm',
|
|
cancelButtonText = 'Cancel',
|
|
onConfirm,
|
|
onCancel,
|
|
confirmButtonVariant = 'primary',
|
|
cancelButtonVariant = 'outline',
|
|
confirmButtonDisabled = false,
|
|
cancelButtonDisabled = false,
|
|
children,
|
|
...props
|
|
},
|
|
ref
|
|
) => (
|
|
<div
|
|
ref={ref}
|
|
className={cn(
|
|
'relative flex w-full shrink-0 items-center justify-end gap-2 px-4 pb-4 pt-2',
|
|
className
|
|
)}
|
|
{...props}
|
|
>
|
|
{children}
|
|
{showCancelButton && (
|
|
<Button
|
|
variant={cancelButtonVariant}
|
|
size="sm"
|
|
onClick={onCancel}
|
|
disabled={cancelButtonDisabled}
|
|
>
|
|
{cancelButtonText}
|
|
</Button>
|
|
)}
|
|
{showConfirmButton && (
|
|
<Button
|
|
variant={confirmButtonVariant}
|
|
size="sm"
|
|
onClick={onConfirm}
|
|
disabled={confirmButtonDisabled}
|
|
>
|
|
{confirmButtonText}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
)
|
|
);
|
|
DialogFooter.displayName = 'DialogFooter';
|
|
|
|
// Legacy DialogTitle for backward compatibility
|
|
const DialogTitle = React.forwardRef<
|
|
React.ElementRef<typeof DialogPrimitive.Title>,
|
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
>(({ className, ...props }, ref) => (
|
|
<DialogPrimitive.Title
|
|
ref={ref}
|
|
className={cn('text-body-sm font-bold text-text-heading', className)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
|
|
// Legacy DialogDescription for backward compatibility
|
|
const DialogDescription = React.forwardRef<
|
|
React.ElementRef<typeof DialogPrimitive.Description>,
|
|
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
>(({ className, ...props }, ref) => (
|
|
<DialogPrimitive.Description
|
|
ref={ref}
|
|
className={cn('text-label-sm text-text-label', className)}
|
|
{...props}
|
|
/>
|
|
));
|
|
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
|
|
export {
|
|
Dialog,
|
|
DialogClose,
|
|
DialogContent,
|
|
DialogContentSection,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogOverlay,
|
|
DialogPortal,
|
|
DialogTitle,
|
|
DialogTrigger,
|
|
};
|