index.tsx 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { Dialog, Transition } from '@headlessui/react'
  2. import { Fragment } from 'react'
  3. import { XMarkIcon } from '@heroicons/react/24/outline'
  4. // https://headlessui.com/react/dialog
  5. type IModal = {
  6. className?: string
  7. isShow: boolean
  8. onClose: () => void
  9. title?: React.ReactNode
  10. description?: React.ReactNode
  11. children: React.ReactNode
  12. closable?: boolean
  13. }
  14. export default function Modal({
  15. className,
  16. isShow,
  17. onClose,
  18. title,
  19. description,
  20. children,
  21. closable = false,
  22. }: IModal) {
  23. return (
  24. <Transition appear show={isShow} as={Fragment}>
  25. <Dialog as="div" className="relative z-10" onClose={onClose}>
  26. <Transition.Child
  27. as={Fragment}
  28. enter="ease-out duration-300"
  29. enterFrom="opacity-0"
  30. enterTo="opacity-100"
  31. leave="ease-in duration-200"
  32. leaveFrom="opacity-100"
  33. leaveTo="opacity-0"
  34. >
  35. <div className="fixed inset-0 bg-black bg-opacity-25" />
  36. </Transition.Child>
  37. <div className="fixed inset-0 overflow-y-auto">
  38. <div className="flex min-h-full items-center justify-center p-4 text-center">
  39. <Transition.Child
  40. as={Fragment}
  41. enter="ease-out duration-300"
  42. enterFrom="opacity-0 scale-95"
  43. enterTo="opacity-100 scale-100"
  44. leave="ease-in duration-200"
  45. leaveFrom="opacity-100 scale-100"
  46. leaveTo="opacity-0 scale-95"
  47. >
  48. <Dialog.Panel className={`w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all ${className}`}>
  49. {title && <Dialog.Title
  50. as="h3"
  51. className="text-lg font-medium leading-6 text-gray-900"
  52. >
  53. {title}
  54. </Dialog.Title>}
  55. {description && <Dialog.Description className='text-gray-500 text-xs font-normal mt-2'>
  56. {description}
  57. </Dialog.Description>}
  58. {closable
  59. && <div className='absolute top-6 right-6 w-5 h-5 rounded-2xl flex items-center justify-center hover:cursor-pointer hover:bg-gray-100'>
  60. <XMarkIcon className='w-4 h-4 text-gray-500' onClick={onClose} />
  61. </div>}
  62. {children}
  63. </Dialog.Panel>
  64. </Transition.Child>
  65. </div>
  66. </div>
  67. </Dialog>
  68. </Transition>
  69. )
  70. }