|
@@ -1,15 +1,7 @@
|
|
|
-import React, { useEffect, useState } from 'react';
|
|
|
|
|
|
|
+import React from 'react';
|
|
|
|
|
|
|
|
-import dynamic from 'next/dynamic';
|
|
|
|
|
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
|
|
import { ErrorBoundary, FallbackProps } from 'react-error-boundary';
|
|
|
import ReactMarkdown from 'react-markdown';
|
|
import ReactMarkdown from 'react-markdown';
|
|
|
-import { ReactMarkdownOptions } from 'react-markdown/lib/react-markdown';
|
|
|
|
|
-import remarkFrontmatter from 'remark-frontmatter';
|
|
|
|
|
-import remarkParse from 'remark-parse';
|
|
|
|
|
-import remarkStringify from 'remark-stringify';
|
|
|
|
|
-import { unified } from 'unified';
|
|
|
|
|
-import { visit } from 'unist-util-visit';
|
|
|
|
|
-
|
|
|
|
|
|
|
|
|
|
import type { RendererOptions } from '~/interfaces/renderer-options';
|
|
import type { RendererOptions } from '~/interfaces/renderer-options';
|
|
|
import loggerFactory from '~/utils/logger';
|
|
import loggerFactory from '~/utils/logger';
|
|
@@ -38,65 +30,12 @@ const ErrorFallback: React.FC<FallbackProps> = React.memo(({ error, resetErrorBo
|
|
|
});
|
|
});
|
|
|
ErrorFallback.displayName = 'ErrorFallback';
|
|
ErrorFallback.displayName = 'ErrorFallback';
|
|
|
|
|
|
|
|
-const Slides = dynamic(() => import('@growi/presentation').then(mod => mod.Slides), { ssr: false });
|
|
|
|
|
-
|
|
|
|
|
const RevisionRenderer = React.memo((props: Props): JSX.Element => {
|
|
const RevisionRenderer = React.memo((props: Props): JSX.Element => {
|
|
|
|
|
|
|
|
const {
|
|
const {
|
|
|
rendererOptions, markdown, additionalClassName, isSlidesOverviewEnabled,
|
|
rendererOptions, markdown, additionalClassName, isSlidesOverviewEnabled,
|
|
|
} = props;
|
|
} = props;
|
|
|
|
|
|
|
|
- const [hasSlideFlag, setHasSlideFlag] = useState<boolean>();
|
|
|
|
|
- const [hasMarpFlag, setHasMarpFlag] = useState<boolean>();
|
|
|
|
|
-
|
|
|
|
|
- // use useEffect to avoid ssr
|
|
|
|
|
- useEffect(() => {
|
|
|
|
|
- if (isSlidesOverviewEnabled) {
|
|
|
|
|
- const processMarkdown = () => (tree) => {
|
|
|
|
|
- setHasSlideFlag(false);
|
|
|
|
|
- setHasMarpFlag(false);
|
|
|
|
|
- visit(tree, 'yaml', (node) => {
|
|
|
|
|
- if (node.value != null) {
|
|
|
|
|
- const lines = node.value.split('\n');
|
|
|
|
|
-
|
|
|
|
|
- lines.forEach((line) => {
|
|
|
|
|
- const [key, value] = line.split(':').map(part => part.trim());
|
|
|
|
|
-
|
|
|
|
|
- if (key === 'slide' && value === 'true') {
|
|
|
|
|
- setHasSlideFlag(true);
|
|
|
|
|
- }
|
|
|
|
|
- else if (key === 'marp' && value === 'true') {
|
|
|
|
|
- setHasMarpFlag(true);
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- }
|
|
|
|
|
- });
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- unified()
|
|
|
|
|
- .use(remarkParse)
|
|
|
|
|
- .use(remarkStringify)
|
|
|
|
|
- .use(remarkFrontmatter, ['yaml'])
|
|
|
|
|
- .use(processMarkdown)
|
|
|
|
|
- .process(markdown);
|
|
|
|
|
- }
|
|
|
|
|
- }, [markdown, setHasSlideFlag, setHasMarpFlag, isSlidesOverviewEnabled]);
|
|
|
|
|
-
|
|
|
|
|
- if (isSlidesOverviewEnabled && (hasSlideFlag || hasMarpFlag)) {
|
|
|
|
|
- const options = {
|
|
|
|
|
- rendererOptions: rendererOptions as ReactMarkdownOptions,
|
|
|
|
|
- isDarkMode: false,
|
|
|
|
|
- disableSeparationsByHeader: false,
|
|
|
|
|
- hasMarpFlag,
|
|
|
|
|
- };
|
|
|
|
|
- return (
|
|
|
|
|
- <Slides
|
|
|
|
|
- options={options}
|
|
|
|
|
- hasMarpFlag={hasMarpFlag}
|
|
|
|
|
- >{markdown}</Slides>
|
|
|
|
|
- );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return (
|
|
return (
|
|
|
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
|
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
|
|
<ReactMarkdown
|
|
<ReactMarkdown
|