Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import { memo } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import { RiCloseLine } from '@remixicon/react'
  4. import {
  5. PortalToFollowElem,
  6. PortalToFollowElemContent,
  7. } from '@/app/components/base/portal-to-follow-elem'
  8. import Button from '@/app/components/base/button'
  9. import type { ButtonProps } from '@/app/components/base/button'
  10. import cn from '@/utils/classnames'
  11. type ModalProps = {
  12. onClose?: () => void
  13. size?: 'sm' | 'md'
  14. title: string
  15. subTitle?: string
  16. children?: React.ReactNode
  17. confirmButtonText?: string
  18. onConfirm?: () => void
  19. cancelButtonText?: string
  20. onCancel?: () => void
  21. showExtraButton?: boolean
  22. extraButtonText?: string
  23. extraButtonVariant?: ButtonProps['variant']
  24. onExtraButtonClick?: () => void
  25. footerSlot?: React.ReactNode
  26. bottomSlot?: React.ReactNode
  27. disabled?: boolean
  28. }
  29. const Modal = ({
  30. onClose,
  31. size = 'sm',
  32. title,
  33. subTitle,
  34. children,
  35. confirmButtonText,
  36. onConfirm,
  37. cancelButtonText,
  38. onCancel,
  39. showExtraButton,
  40. extraButtonVariant = 'warning',
  41. extraButtonText,
  42. onExtraButtonClick,
  43. footerSlot,
  44. bottomSlot,
  45. disabled,
  46. }: ModalProps) => {
  47. const { t } = useTranslation()
  48. return (
  49. <PortalToFollowElem open>
  50. <PortalToFollowElemContent
  51. className='z-[9998] flex h-full w-full items-center justify-center bg-background-overlay'
  52. onClick={onClose}
  53. >
  54. <div
  55. className={cn(
  56. 'max-h-[80%] w-[480px] overflow-y-auto rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xs',
  57. size === 'sm' && 'w-[480px',
  58. size === 'md' && 'w-[640px]',
  59. )}
  60. onClick={e => e.stopPropagation()}
  61. >
  62. <div className='title-2xl-semi-bold relative p-6 pb-3 pr-14 text-text-primary'>
  63. {title}
  64. {
  65. subTitle && (
  66. <div className='system-xs-regular mt-1 text-text-tertiary'>
  67. {subTitle}
  68. </div>
  69. )
  70. }
  71. <div
  72. className='absolute right-5 top-5 flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg'
  73. onClick={onClose}
  74. >
  75. <RiCloseLine className='h-5 w-5 text-text-tertiary' />
  76. </div>
  77. </div>
  78. {
  79. children && (
  80. <div className='px-6 py-3'>{children}</div>
  81. )
  82. }
  83. <div className='flex justify-between p-6 pt-5'>
  84. <div>
  85. {footerSlot}
  86. </div>
  87. <div className='flex items-center'>
  88. {
  89. showExtraButton && (
  90. <>
  91. <Button
  92. variant={extraButtonVariant}
  93. onClick={onExtraButtonClick}
  94. disabled={disabled}
  95. >
  96. {extraButtonText || t('common.operation.remove')}
  97. </Button>
  98. <div className='mx-3 h-4 w-[1px] bg-divider-regular'></div>
  99. </>
  100. )
  101. }
  102. <Button
  103. onClick={onCancel}
  104. disabled={disabled}
  105. >
  106. {cancelButtonText || t('common.operation.cancel')}
  107. </Button>
  108. <Button
  109. className='ml-2'
  110. variant='primary'
  111. onClick={onConfirm}
  112. disabled={disabled}
  113. >
  114. {confirmButtonText || t('common.operation.save')}
  115. </Button>
  116. </div>
  117. </div>
  118. {bottomSlot}
  119. </div>
  120. </PortalToFollowElemContent>
  121. </PortalToFollowElem>
  122. )
  123. }
  124. export default memo(Modal)