dify/web/app/components/base/drawer/index.tsx

117 lines
3.4 KiB
TypeScript

'use client'
import { Dialog, DialogBackdrop, DialogTitle } from '@headlessui/react'
import { XMarkIcon } from '@heroicons/react/24/outline'
import { useTranslation } from 'react-i18next'
import { cn } from '@/utils/classnames'
import Button from '../button'
export type IDrawerProps = {
title?: string
description?: string
dialogClassName?: string
dialogBackdropClassName?: string
containerClassName?: string
panelClassName?: string
children: React.ReactNode
footer?: React.ReactNode
mask?: boolean
positionCenter?: boolean
isOpen: boolean
showClose?: boolean
clickOutsideNotOpen?: boolean
onClose: () => void
onCancel?: () => void
onOk?: () => void
unmount?: boolean
noOverlay?: boolean
}
export default function Drawer({
title = '',
description = '',
dialogClassName = '',
dialogBackdropClassName = '',
containerClassName = '',
panelClassName = '',
children,
footer,
mask = true,
positionCenter,
showClose = false,
isOpen,
clickOutsideNotOpen,
onClose,
onCancel,
onOk,
unmount = false,
noOverlay = false,
}: IDrawerProps) {
const { t } = useTranslation()
return (
<Dialog
unmount={unmount}
open={isOpen}
onClose={() => {
if (!clickOutsideNotOpen)
onClose()
}}
className={cn('fixed inset-0 z-[30] overflow-y-auto', dialogClassName)}
>
<div className={cn('flex h-screen w-screen justify-end', positionCenter && '!justify-center', containerClassName)}>
{/* mask */}
{!noOverlay && (
<DialogBackdrop
className={cn('fixed inset-0 z-[40]', mask && 'bg-black/30', dialogBackdropClassName)}
onClick={() => {
if (!clickOutsideNotOpen)
onClose()
}}
/>
)}
<div className={cn('relative z-[50] flex w-full max-w-sm flex-col justify-between overflow-hidden bg-components-panel-bg p-6 text-left align-middle shadow-xl', panelClassName)}>
<>
<div className="flex justify-between">
{title && (
<DialogTitle
as="h3"
className="text-lg font-medium leading-6 text-text-primary"
>
{title}
</DialogTitle>
)}
{showClose && (
<DialogTitle className="mb-4 flex cursor-pointer items-center" as="div">
<XMarkIcon className="h-4 w-4 text-text-tertiary" onClick={onClose} />
</DialogTitle>
)}
</div>
{description && <div className="mt-2 text-xs font-normal text-text-tertiary">{description}</div>}
{children}
</>
{footer || (footer === null
? null
: (
<div className="mt-10 flex flex-row justify-end">
<Button
className="mr-2"
onClick={() => {
onCancel?.()
}}
>
{t('operation.cancel', { ns: 'common' })}
</Button>
<Button
onClick={() => {
onOk?.()
}}
>
{t('operation.save', { ns: 'common' })}
</Button>
</div>
))}
</div>
</div>
</Dialog>
)
}