ShareLinkPageView.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import type { IPagePopulatedToShowRevision } from '@growi/core';
  2. import { useSlidesByFrontmatter } from '@growi/presentation/dist/services';
  3. import dynamic from 'next/dynamic';
  4. import { type JSX, useMemo } from 'react';
  5. import { PagePathNavTitle } from '~/components/Common/PagePathNavTitle';
  6. import type { RendererConfig } from '~/interfaces/services/renderer';
  7. import type { IShareLinkHasId } from '~/interfaces/share-link';
  8. import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
  9. import { generateSSRViewOptions } from '~/services/renderer/renderer';
  10. import { useIsNotFound } from '~/stores/page';
  11. import { useViewOptions } from '~/stores/renderer';
  12. import loggerFactory from '~/utils/logger';
  13. import { PageContentFooter } from '../PageView/PageContentFooter';
  14. import { PageViewLayout } from '../PageView/PageViewLayout';
  15. import RevisionRenderer from '../PageView/RevisionRenderer';
  16. import ShareLinkAlert from './ShareLinkAlert';
  17. const logger = loggerFactory('growi:Page');
  18. const PageSideContents = dynamic(
  19. () =>
  20. import('~/client/components/PageSideContents').then(
  21. (mod) => mod.PageSideContents,
  22. ),
  23. { ssr: false },
  24. );
  25. const ForbiddenPage = dynamic(
  26. () => import('~/client/components/ForbiddenPage'),
  27. { ssr: false },
  28. );
  29. const SlideRenderer = dynamic(
  30. () =>
  31. import('~/client/components/Page/SlideRenderer').then(
  32. (mod) => mod.SlideRenderer,
  33. ),
  34. { ssr: false },
  35. );
  36. type Props = {
  37. pagePath: string;
  38. rendererConfig: RendererConfig;
  39. page?: IPagePopulatedToShowRevision;
  40. shareLink?: IShareLinkHasId;
  41. isExpired: boolean;
  42. disableLinkSharing: boolean;
  43. };
  44. export const ShareLinkPageView = (props: Props): JSX.Element => {
  45. const {
  46. pagePath,
  47. rendererConfig,
  48. page,
  49. shareLink,
  50. isExpired,
  51. disableLinkSharing,
  52. } = props;
  53. const { data: isNotFoundMeta } = useIsNotFound();
  54. const { data: viewOptions } = useViewOptions();
  55. const shouldExpandContent = useShouldExpandContent(page);
  56. const markdown = page?.revision?.body;
  57. const isSlide = useSlidesByFrontmatter(
  58. markdown,
  59. rendererConfig.isEnabledMarp,
  60. );
  61. const isNotFound = isNotFoundMeta || page == null || shareLink == null;
  62. const specialContents = useMemo(() => {
  63. if (disableLinkSharing) {
  64. return <ForbiddenPage isLinkSharingDisabled={props.disableLinkSharing} />;
  65. }
  66. }, [disableLinkSharing, props.disableLinkSharing]);
  67. const headerContents = (
  68. <PagePathNavTitle
  69. pageId={page?._id}
  70. pagePath={pagePath}
  71. isWipPage={page?.wip}
  72. />
  73. );
  74. const sideContents = !isNotFound ? <PageSideContents page={page} /> : null;
  75. const footerContents = !isNotFound ? <PageContentFooter page={page} /> : null;
  76. const Contents = () => {
  77. if (isNotFound || page.revision == null) {
  78. return <></>;
  79. }
  80. if (isExpired) {
  81. return (
  82. <>
  83. <h2 className="text-muted mt-4">
  84. <span className="material-symbols-outlined" aria-hidden="true">
  85. block
  86. </span>
  87. <span> Page is expired</span>
  88. </h2>
  89. </>
  90. );
  91. }
  92. const rendererOptions =
  93. viewOptions ?? generateSSRViewOptions(rendererConfig, pagePath);
  94. const markdown = page.revision.body;
  95. return isSlide != null ? (
  96. <SlideRenderer marp={isSlide.marp} markdown={markdown} />
  97. ) : (
  98. <RevisionRenderer rendererOptions={rendererOptions} markdown={markdown} />
  99. );
  100. };
  101. return (
  102. <PageViewLayout
  103. headerContents={headerContents}
  104. sideContents={sideContents}
  105. expandContentWidth={shouldExpandContent}
  106. footerContents={footerContents}
  107. >
  108. {specialContents}
  109. {specialContents == null && (
  110. <>
  111. {isNotFound && (
  112. <h2 className="text-muted mt-4">
  113. <span className="material-symbols-outlined" aria-hidden="true">
  114. block
  115. </span>
  116. <span> Page is not found</span>
  117. </h2>
  118. )}
  119. {!isNotFound && (
  120. <>
  121. <ShareLinkAlert
  122. expiredAt={shareLink.expiredAt}
  123. createdAt={shareLink.createdAt}
  124. />
  125. <div className="mb-5">
  126. <Contents />
  127. </div>
  128. </>
  129. )}
  130. </>
  131. )}
  132. </PageViewLayout>
  133. );
  134. };