From 15449b6170b0723f0c2ed98c073e614108a8302e Mon Sep 17 00:00:00 2001 From: Rob Ellison Date: Fri, 19 May 2023 11:56:13 +0000 Subject: [PATCH] feat: replace mdxprovider --- .../mdxProvider.js | 16 +- layouts/SlidePage.jsx | 2 + pages/_app.js | 6 +- pages/output/[...parms].jsx | 7 +- tmp/output/[...parms].jsx | 325 ++++++++++++++++++ 5 files changed, 341 insertions(+), 15 deletions(-) rename components/MDXProvider.jsx => constants/mdxProvider.js (89%) create mode 100644 tmp/output/[...parms].jsx diff --git a/components/MDXProvider.jsx b/constants/mdxProvider.js similarity index 89% rename from components/MDXProvider.jsx rename to constants/mdxProvider.js index e16916b5..f4648b88 100644 --- a/components/MDXProvider.jsx +++ b/constants/mdxProvider.js @@ -1,5 +1,5 @@ import React from "react"; -import { MDXProvider } from "@mdx-js/react"; +// import { MDXProvider } from "@mdx-js/react"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import okaidia from "react-syntax-highlighter/dist/cjs/styles/prism/okaidia"; import SlidePage from "../layouts/SlidePage"; @@ -11,9 +11,9 @@ import Image from "next/image"; import { TitleSlide, Header, Banner, Footer, Insights, Chevrons, Nest, Roadmap, Layout, Column, Item, Slide, HeaderCard } from 'airview-mdx' // import Cover from "./Cover"; -import SpeakerNotes from "./SpeakerNotes"; -import Step from "./Step"; -import Steps from "./Steps"; +import SpeakerNotes from "../components/SpeakerNotes"; +import Step from "../components/Step"; +import Steps from "../components/Steps"; import { motion } from "framer-motion"; // MUI Components @@ -29,7 +29,7 @@ import Alert from '@mui/material/Alert'; // import { Insight, InsightTable, ChevronProcessTable, StatementBanner, Roadmap } from './Playback'; // import {FaIcon, Icon} from './Images.jsx'; import {FaIcon, Icon} from 'airview-mdx'; -import { ProgressTable } from './Tables.jsx'; +import { ProgressTable } from '../components/Tables.jsx'; // import { HeaderCard, Nest } from './Cards'; // import { HeaderCard } from './Cards'; // import { Font } from './Styling'; @@ -90,6 +90,6 @@ export const mdComponents = { Layout, Column, Item }; -export default ({ children }) => ( - {children} -); +// export default ({ children }) => ( +// {children} +// ); diff --git a/layouts/SlidePage.jsx b/layouts/SlidePage.jsx index d48b7164..a7037132 100644 --- a/layouts/SlidePage.jsx +++ b/layouts/SlidePage.jsx @@ -228,6 +228,7 @@ function SlidePage({ children, next }) { const pageSize = { width:1920, height:1080} return ( + @@ -239,5 +240,6 @@ function SlidePage({ children, next }) { + ); } diff --git a/pages/_app.js b/pages/_app.js index e45ccda1..a02d15b7 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -1,19 +1,21 @@ import Head from "next/head"; import { siteConfig } from "../site.config.js"; -import MDXProvider from "../components/MDXProvider"; +// import MDXProvider from "../components/MDXProvider"; import { AnimatePresence } from "framer-motion"; import { CurrentSlideProvider } from "../context/CurrentSlideContext"; import { ModeProvider } from "../context/ModeContext"; import TransitionPage from "../layouts/TransitionPage"; import Script from 'next/script'; import ErrorBoundary from "../components/ErrorBoundary.jsx"; +import { MDXProvider } from "@mdx-js/react"; +import { mdComponents } from "../constants/mdxProvider"; export default function App({ Component, pageProps }) { return ( // - + diff --git a/pages/output/[...parms].jsx b/pages/output/[...parms].jsx index 951d0c29..bccf3ab1 100644 --- a/pages/output/[...parms].jsx +++ b/pages/output/[...parms].jsx @@ -19,7 +19,7 @@ import { useRouter } from 'next/router'; import { theme } from '../../constants/theme'; import { ThemeProvider } from '@mui/material/styles'; import CssBaseline from '@mui/material/CssBaseline'; -import { mdComponents } from "../../components/MDXProvider"; +import { mdComponents } from "../../constants/mdxProvider"; import * as matter from 'gray-matter'; import { Previewer } from 'pagedjs' @@ -190,13 +190,10 @@ function Page() { .catch(error => { // console.log(error) return { fileData: null, error: error } - }) - .finally(() => { - console.log('timeout: ', refreshToken); }); }; - console.log('effectloading file', router) + // console.log('effectloading file', router) if (source === 'file') { fetchFileContent() setTimeout(() => setRefreshToken(Math.random()), 50000); diff --git a/tmp/output/[...parms].jsx b/tmp/output/[...parms].jsx new file mode 100644 index 00000000..71fd0432 --- /dev/null +++ b/tmp/output/[...parms].jsx @@ -0,0 +1,325 @@ +import React, { useState, useEffect, useCallback, useRef } from 'react' +import { VFile } from 'vfile' +import { VFileMessage } from 'vfile-message' +import * as provider from '@mdx-js/react' +import * as runtime from 'react/jsx-runtime' +// import {statistics} from 'vfile-statistics' +// import {reporter} from 'vfile-reporter' +import { evaluate } from '@mdx-js/mdx' +import remarkGfm from 'remark-gfm' +import remarkFrontmatter from 'remark-frontmatter' +import remarkMdxFrontmatter from 'remark-mdx-frontmatter' +import remarkUnwrapImages from 'remark-unwrap-images'; + +// import remarkMath from 'remark-math' +import { ErrorBoundary } from 'react-error-boundary' +import { useDebounceFn } from 'ahooks' +import dynamic from 'next/dynamic' +import { useRouter } from 'next/router'; +import { theme } from '../../constants/theme'; +import { ThemeProvider } from '@mui/material/styles'; +import CssBaseline from '@mui/material/CssBaseline'; +import { mdComponents } from "../../constants/MDXProvider"; +import * as matter from 'gray-matter'; +import { Previewer } from 'pagedjs' + +function removeSection(pad, tagName) { + const re = new RegExp("<" + tagName + "\\s+[^>]*>(.*?)", "gs"); + return (pad.replace(re, "")); +} + +function useMdx(defaults) { + const [state, setState] = useState({ ...defaults, file: null }) + + const { run: setConfig } = useDebounceFn( + async (config) => { + const file = new VFile({ basename: 'example.mdx', value: config.value }) + + const capture = (name) => () => (tree) => { + file.data[name] = tree + } + + const remarkPlugins = [] + + if (config.gfm) remarkPlugins.push(remarkGfm) + if (config.frontmatter) { + remarkPlugins.push(remarkFrontmatter); + remarkPlugins.push(remarkMdxFrontmatter); + } + if (config.unwrapImages) remarkPlugins.push(remarkUnwrapImages) + // remarkPlugins.push(capture('mdast')) + + try { + file.result = ( + await evaluate(file, { + ...provider, + ...runtime, + useDynamicImport: true, + remarkPlugins, + // rehypePlugins: [capture('hast')], + // recmaPlugins: [capture('esast')], + + }) + ).default + } catch (error) { + // console.log('output:evalutate:Error: ', error) + // console.log('output:evalutate:Error/Content: ', file) + const message = + error instanceof VFileMessage ? error : new VFileMessage(error) + + if (!file.messages.includes(message)) { + file.messages.push(message) + } + + message.fatal = true + } + // console.log('output:evalutate:Success/Content: ', file) + setState({ ...config, file }) + }, + { leading: true, trailing: true, wait: 0 } + ) + + return [state, setConfig] +} + +function ErrorFallback({ error, resetErrorBoundary }) { + return ( +
+

Something went wrong:

+
{error.message}
+ +
+ ) +} + +function FallbackComponent({ error }) { + const message = new VFileMessage(error) + message.fatal = true + return ( +
+      {String(message)}
+    
+ ) +} + + +export default dynamic(() => Promise.resolve(Page), { + ssr: true, +}); + +function Page() { + const router = useRouter(); + const [refreshToken, setRefreshToken] = useState(Math.random()); + const [rev, setRev] = useState(0); + + let format = 'default'; + + if (router.query.format) { + format = router.query.format; + } + + let source = null; + let location = null; + if (router.query.parms && router.query.parms.length > 1) { + source = router.query.parms[0]; + location = router.query.parms.slice(1).join('/'); + } + + const defaultValue = ` + # No Content Loaded + `; + + const [state, setConfig] = useMdx({ + gfm: true, + frontmatter: true, + math: false, + unwrapImages: true, + value: defaultValue + }) + + const mdxContent = (format, mdx, pageParms) => { + // console.log('pageParms: ', pageParms) + if (pageParms && pageParms.parms) { delete pageParms.parms }; + const { content, data } = matter(mdx); + let frontmatter = { ...data, ...pageParms }; + if (format === 'ppt') { + mdx = '\n' + content + '\n' + } else if (format === 'doc') { + mdx = '
\n' + content.replace(/---/g, '') + '\n
' + } else if (format === 'ppt-print') { + mdx = '\n' + content + '\n' + } else { + mdx = removeSection(mdx, 'TitleSlide'); + mdx = '\n' + content.replace(/---/g, '') + '\n' + } + mdx = matter.stringify(mdx, { ...frontmatter }); + return mdx + } + + + // Create a preview component that can handle errors with try-catch block; for catching invalid JS expressions errors that ErrorBoundary cannot catch. + const Preview = useCallback(() => { + try { + return state.file.result() + } catch (error) { + // console.log('/output:Preview:useCallback:Error: ', error) + return + } + }, [state]) + + // const stats = state.file ? statistics(state.file) : {} + useEffect(() => { + const fetchFileContent = async () => { + fetch(`/api/files/file?filePath=${location}`) + .then((res) => res.json()) + .then(data => { + if (data.content) { + // console.log('/output/[...params].jsx:useEffect:router.query: ', router.query) + + // console.log('/output/[...params].jsx:useEffect:content: ', mdxContent(format, data.content, router.query)) + + setConfig({ ...state, value: String(mdxContent(format, data.content, router.query)) }) + } else if (error) { + // console.log('output:error: ', error) + } else { + // console.log('output:error: unknown error') + } + }) + .catch(error => { + // console.log(error) + return { fileData: null, error: error } + }) + .finally(() => { + console.log('timeout: ', refreshToken); + }); + }; + + console.log('effectloading file', router) + if (source === 'file') { + fetchFileContent() + setTimeout(() => setRefreshToken(Math.random()), 50000); + } else if (!source) { + setTimeout(() => setRefreshToken(Math.random()), 500); + } + }, [refreshToken]); + + useEffect(() => { + const fetchPadContent = async () => { + fetch(`/api/etherpad/pad-revs?pad=${location}`) + .then((res) => res.json()) + .then(data => { + // console.log('data.rev : ', data.rev , 'rev : ', rev) + if (data.rev && data.rev > rev) { + // console.log('new revision :', data.rev) + const newrev = data.rev + fetch(`/api/etherpad/pad?pad=${location}&rev=${newrev}`) + .then((res) => res.json()) + .then(data => { + if (data.content) { + setConfig({ ...state, value: String(mdxContent(format, data.content, router.query)) }); + setRev(newrev); // update the revision after successful fetch + } + }) + .catch(error => { + // console.log(error) + }) + } + + }) + .catch(error => { + // console.log(error) + }) + .finally(() => { + setTimeout(() => setRefreshToken(Math.random()), 5000); + }); + } + + if (source === 'pad') { fetchPadContent() } + + }, [refreshToken]); + + + if (format === 'doc') { + if (state.file && state.file.result) { + // console.log('/output:PrintView:file: ', state.file.result) + } + return ( + + {state.file && state.file.result ? () : null} + + ) + } else { + + if (state.file && state.file.result) { + // console.log('/output:DefaultView:file: ', state.file.result) + } + return ( + + {state.file && state.file.result ? () : null} + + ) + }; +}; + + + + + +// PDF Print View component +function DocumentView({ children }) { + // console.log('/output:PrintView:children: ', children); + + const mdxContainer = useRef(null); + const previewContainer = useRef(null); + let contentMdx = ``; + + useEffect(() => { + if (mdxContainer.current !== null) { + const paged = new Previewer(); + contentMdx = `${mdxContainer.current?.innerHTML}`; + paged + .preview(contentMdx, + ['/pdf.css'], + previewContainer.current + ) + .then((flow) => { + // console.log('====flow====') + // console.log(flow) + }); + return () => { + document.head + .querySelectorAll("[data-pagedjs-inserted-styles]") + .forEach((e) => e.parentNode?.removeChild(e)); + }; + } + + }, [children]) + + return ( + <> +
+ + + + {children && children} + +
+
+ + + ) +}; + +// Normal View component +function DefaultView({ children }) { + + // console.log('DefaultView:children: ', children) + return ( + + + {children && children} + + ) +};