Modal.tsx 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. import { JSX } from "preact";
  2. import { useEffect, useState } from "preact/hooks";
  3. interface ModalAction {
  4. text: string;
  5. onClick?: (text: string) => void | Promise<void>;
  6. }
  7. interface ModalGlobalHook {
  8. show: (
  9. title: string,
  10. content: string | JSX.Element,
  11. actions: ModalAction[],
  12. ) => void;
  13. hide: () => void;
  14. }
  15. declare global {
  16. var $modal: ModalGlobalHook | undefined;
  17. }
  18. export default function Modal() {
  19. const [visible, setVisible] = useState(false);
  20. const [title, setTitle] = useState("");
  21. const [content, setContent] = useState<string | JSX.Element>("");
  22. const [actions, setActions] = useState<ModalAction[]>([]);
  23. const showModal = (
  24. newTitle: string,
  25. newContent: string | JSX.Element,
  26. newActions: ModalAction[],
  27. ) => {
  28. setTitle(newTitle || "");
  29. setContent(newContent || "");
  30. setActions(newActions || []);
  31. setVisible(true);
  32. };
  33. const hideModal = () => {
  34. setVisible(false);
  35. };
  36. useEffect(() => {
  37. globalThis.$modal = {
  38. show: (
  39. title: string,
  40. content: string | JSX.Element,
  41. actions: ModalAction[],
  42. ) => showModal(title, content, actions),
  43. hide: () => hideModal(),
  44. };
  45. return () => {
  46. delete globalThis.$modal;
  47. };
  48. }, []);
  49. return (
  50. <>
  51. <div className={`pd-modal${!visible ? " pd-modal-hidden" : ""}`}>
  52. <div className="pd-modal-content">
  53. <i
  54. className="bi bi-x pd-modal-close"
  55. onClick={() => {
  56. hideModal();
  57. }}
  58. />
  59. {title ? <div className="pd-modal-title">{title}</div> : null}
  60. <div className="pd-modal-body">{content}</div>
  61. {actions.length > 0
  62. ? (
  63. <div className="pd-modal-footer">
  64. {actions.map((action, index) => (
  65. <button
  66. type="button"
  67. key={index}
  68. onClick={() => {
  69. action.onClick
  70. ? action.onClick(action.text)
  71. : hideModal();
  72. }}
  73. >
  74. {action.text}
  75. </button>
  76. ))}
  77. </div>
  78. )
  79. : null}
  80. </div>
  81. </div>
  82. </>
  83. );
  84. }