PagePresentationModal.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. import React, { useCallback } from 'react';
  2. import type { PresentationProps } from '@growi/presentation';
  3. import { LoadingSpinner } from '@growi/ui/dist/components';
  4. import { useFullScreen } from '@growi/ui/dist/utils';
  5. import dynamic from 'next/dynamic';
  6. import type { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown';
  7. import {
  8. Modal, ModalBody,
  9. } from 'reactstrap';
  10. import { useIsEnabledMarp } from '~/stores/context';
  11. import { usePagePresentationModal } from '~/stores/modal';
  12. import { useSWRxCurrentPage } from '~/stores/page';
  13. import { usePresentationViewOptions } from '~/stores/renderer';
  14. import { useNextThemes } from '~/stores/use-next-themes';
  15. import styles from './PagePresentationModal.module.scss';
  16. const Presentation = dynamic<PresentationProps>(() => import('./Presentation/Presentation').then(mod => mod.Presentation), {
  17. ssr: false,
  18. loading: () => (
  19. <LoadingSpinner className="text-muted fs-1" />
  20. ),
  21. });
  22. const PagePresentationModal = (): JSX.Element => {
  23. const { data: presentationModalData, close: closePresentationModal } = usePagePresentationModal();
  24. const { isDarkMode } = useNextThemes();
  25. const fullscreen = useFullScreen();
  26. const { data: currentPage } = useSWRxCurrentPage();
  27. const { data: rendererOptions } = usePresentationViewOptions();
  28. const { data: isEnabledMarp } = useIsEnabledMarp();
  29. const toggleFullscreenHandler = useCallback(() => {
  30. if (fullscreen.active) {
  31. fullscreen.exit();
  32. }
  33. else {
  34. fullscreen.enter();
  35. }
  36. }, [fullscreen]);
  37. const closeHandler = useCallback(() => {
  38. if (fullscreen.active) {
  39. fullscreen.exit();
  40. }
  41. closePresentationModal();
  42. }, [fullscreen, closePresentationModal]);
  43. const isOpen = presentationModalData?.isOpened ?? false;
  44. if (!isOpen) {
  45. return <></>;
  46. }
  47. const markdown = currentPage?.revision?.body;
  48. return (
  49. <Modal
  50. isOpen={isOpen}
  51. toggle={closeHandler}
  52. data-testid="page-presentation-modal"
  53. className={`grw-presentation-modal ${styles['grw-presentation-modal']}`}
  54. >
  55. <div className="grw-presentation-controls d-flex">
  56. <button
  57. className="btn material-symbols-outlined"
  58. type="button"
  59. aria-label="fullscreen"
  60. onClick={toggleFullscreenHandler}
  61. >
  62. {fullscreen.active ? 'close_fullscreen' : 'open_in_full'}
  63. </button>
  64. <button className="btn-close" type="button" aria-label="Close" onClick={closeHandler}></button>
  65. </div>
  66. <ModalBody className="modal-body d-flex justify-content-center align-items-center">
  67. { rendererOptions != null && isEnabledMarp != null && (
  68. <Presentation
  69. options={{
  70. rendererOptions: rendererOptions as ReactMarkdownOptions,
  71. revealOptions: {
  72. embedded: true,
  73. hash: true,
  74. },
  75. isDarkMode,
  76. }}
  77. isEnabledMarp={isEnabledMarp}
  78. >
  79. {markdown}
  80. </Presentation>
  81. ) }
  82. </ModalBody>
  83. </Modal>
  84. );
  85. };
  86. export default PagePresentationModal;