index.tsx 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import {
  2. Dialog,
  3. TransitionChild,
  4. Transition,
  5. DialogTitle,
  6. Description,
  7. DialogPanel,
  8. CloseButton,
  9. } from "@headlessui/react";
  10. import { XMarkIcon } from "@heroicons/react/24/outline";
  11. import type { ReactNode } from "react";
  12. import { Fragment } from "react";
  13. import { Button } from "../Button";
  14. type ModalProps = {
  15. show: boolean;
  16. onClose: () => void;
  17. afterLeave?: (() => void) | undefined;
  18. children: ReactNode;
  19. title: string;
  20. description?: string;
  21. };
  22. export const Modal = ({
  23. show,
  24. onClose,
  25. afterLeave,
  26. children,
  27. title,
  28. description,
  29. }: ModalProps) => (
  30. <Transition show={show} as={Fragment} {...(afterLeave && { afterLeave })}>
  31. <Dialog onClose={onClose} className="relative z-50">
  32. <TransitionChild
  33. as="div"
  34. className="fixed inset-0 bg-black/25 dark:bg-white/10"
  35. enter="transition-opacity ease-linear duration-300"
  36. enterFrom="opacity-0"
  37. enterTo="opacity-100"
  38. leave="transition-opacity ease-linear duration-300"
  39. leaveFrom="opacity-100"
  40. leaveTo="opacity-0"
  41. />
  42. <div className="fixed inset-0 overflow-y-auto">
  43. <div className="flex min-h-full items-center justify-center px-4 py-32 text-center">
  44. <TransitionChild
  45. as={Fragment}
  46. enter="ease-out duration-300"
  47. enterFrom="opacity-0 scale-95"
  48. enterTo="opacity-100 scale-100"
  49. leave="ease-in duration-200"
  50. leaveFrom="opacity-100 scale-100"
  51. leaveTo="opacity-0 scale-95"
  52. >
  53. <DialogPanel className="relative w-full max-w-md rounded-2xl bg-white p-8 text-left align-middle shadow-xl transition-all dark:bg-neutral-900 dark:shadow-white/5 md:max-w-xl lg:max-w-2xl xl:max-w-4xl">
  54. <DialogTitle
  55. as="h1"
  56. className="text-lg font-medium leading-6 text-neutral-800 dark:text-neutral-200 md:text-xl lg:text-2xl"
  57. >
  58. {title}
  59. </DialogTitle>
  60. <CloseButton className="absolute right-3 top-3 rounded-md p-2 text-neutral-500 transition hover:bg-black/10 dark:hover:bg-white/5">
  61. <XMarkIcon className="size-5" />
  62. </CloseButton>
  63. {description && (
  64. <Description className="mb-10 mt-2 text-sm text-neutral-500 dark:text-neutral-400">
  65. {description}
  66. </Description>
  67. )}
  68. {children}
  69. <div className="mt-8 text-right">
  70. <CloseButton as={Button} className="px-4 py-2">
  71. Close
  72. </CloseButton>
  73. </div>
  74. </DialogPanel>
  75. </TransitionChild>
  76. </div>
  77. </div>
  78. </Dialog>
  79. </Transition>
  80. );