Modal.tsx 2.3 KB

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