Spaces:
Running
Running
File size: 4,170 Bytes
2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 c0a9bce 2e1ab99 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
import * as RadixDialog from '@radix-ui/react-dialog';
import { motion, type Variants } from 'framer-motion';
import React, { memo, type ReactNode } from 'react';
import { classNames } from '~/utils/classNames';
import { cubicEasingFn } from '~/utils/easings';
import { IconButton } from './IconButton';
export { Close as DialogClose, Root as DialogRoot } from '@radix-ui/react-dialog';
interface DialogButtonProps {
type: 'primary' | 'secondary' | 'danger';
children: ReactNode;
onClick?: (event: React.MouseEvent) => void;
disabled?: boolean;
}
export const DialogButton = memo(({ type, children, onClick, disabled }: DialogButtonProps) => {
return (
<button
className={classNames('inline-flex items-center gap-2 px-4 py-2 rounded-lg text-sm transition-colors', {
'bg-purple-500 text-white hover:bg-purple-600 dark:bg-purple-500 dark:hover:bg-purple-600': type === 'primary',
'bg-transparent text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-gray-100':
type === 'secondary',
'bg-transparent text-red-500 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-500/10': type === 'danger',
})}
onClick={onClick}
disabled={disabled}
>
{children}
</button>
);
});
export const DialogTitle = memo(({ className, children, ...props }: RadixDialog.DialogTitleProps) => {
return (
<RadixDialog.Title
className={classNames('text-lg font-medium text-bolt-elements-textPrimary', 'flex items-center gap-2', className)}
{...props}
>
{children}
</RadixDialog.Title>
);
});
export const DialogDescription = memo(({ className, children, ...props }: RadixDialog.DialogDescriptionProps) => {
return (
<RadixDialog.Description
className={classNames('text-sm text-bolt-elements-textSecondary', 'mt-1', className)}
{...props}
>
{children}
</RadixDialog.Description>
);
});
const transition = {
duration: 0.15,
ease: cubicEasingFn,
};
export const dialogBackdropVariants = {
closed: {
opacity: 0,
transition,
},
open: {
opacity: 1,
transition,
},
} satisfies Variants;
export const dialogVariants = {
closed: {
x: '-50%',
y: '-40%',
scale: 0.96,
opacity: 0,
transition,
},
open: {
x: '-50%',
y: '-50%',
scale: 1,
opacity: 1,
transition,
},
} satisfies Variants;
interface DialogProps {
children: ReactNode;
className?: string;
showCloseButton?: boolean;
onClose?: () => void;
onBackdrop?: () => void;
}
export const Dialog = memo(({ children, className, showCloseButton = true, onClose, onBackdrop }: DialogProps) => {
return (
<RadixDialog.Portal>
<RadixDialog.Overlay asChild>
<motion.div
className={classNames(
'fixed inset-0 z-[9999]',
'bg-[#FAFAFA]/80 dark:bg-[#0A0A0A]/80',
'backdrop-blur-[2px]',
)}
initial="closed"
animate="open"
exit="closed"
variants={dialogBackdropVariants}
onClick={onBackdrop}
/>
</RadixDialog.Overlay>
<RadixDialog.Content asChild>
<motion.div
className={classNames(
'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2',
'bg-[#FAFAFA] dark:bg-[#0A0A0A]',
'rounded-lg shadow-lg',
'border border-[#E5E5E5] dark:border-[#1A1A1A]',
'z-[9999] w-[520px]',
className,
)}
initial="closed"
animate="open"
exit="closed"
variants={dialogVariants}
>
<div className="flex flex-col">
{children}
{showCloseButton && (
<RadixDialog.Close asChild onClick={onClose}>
<IconButton
icon="i-ph:x"
className="absolute top-3 right-3 text-bolt-elements-textSecondary hover:text-bolt-elements-textPrimary"
/>
</RadixDialog.Close>
)}
</div>
</motion.div>
</RadixDialog.Content>
</RadixDialog.Portal>
);
});
|