Modal.tsx 2.2 KB

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