Modal.tsx 2.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  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 Window {
  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. window.$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 window.$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. key={index}
  69. onClick={() => {
  70. action.onClick
  71. ? action.onClick(action.text)
  72. : hideModal();
  73. }}
  74. >
  75. {action.text}
  76. </button>
  77. ))}
  78. </div>
  79. )
  80. : null}
  81. </div>
  82. </div>
  83. </>
  84. );
  85. }