mui / material-ui

Material UI: Comprehensive React component library that implements Google's Material Design. Free forever.
https://mui.com/material-ui/
MIT License
93.93k stars 32.27k forks source link

[docs-infra] Reuse md files for both docs pages and GitHub exploration #38065

Open alexfauquette opened 1 year ago

alexfauquette commented 1 year ago

Wondering what is the way to go in cases when we want to reuse .md files that we write for the docs which contain "our" custom syntax.

For example, we reuse the .md file that powers this docs page: https://mui.com/toolpad/examples/admin-app/ as a README.md here: https://github.com/mui/mui-toolpad/blob/master/examples/admin-app/README.md

TL;DR: Problem: To allow .md files reusability. Solution: For the docs markdown parser: Parse custom syntax within comments, and add a directive to ignore lines. (edited)

Option 1 - Use comments

One idea is to potentially allow parsing any custom syntax within comments, so:

{{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/marketing/admin-app.png", "alt": "Admin application", "caption": "A CRUD application"}}

could become:

<!-- {{"component": "modules/components/DocsImage.tsx", "src": "/static/toolpad/marketing/admin-app.png", "alt": "Admin application", "caption": "A CRUD application"}} -->

and still be parsed by the docs markdown parser, but ignored when rendering plain markdown. And, for the other way around, we could add a directive like:

<!-- mui-markdown-ignore-start -->
![screenshot](/static/toolpad/marketing/admin-app.png)
<!-- mui-markdown-ignore-end -->

allowing us to add lines to the .md that don't get parsed by our parsers.

Option 2 - Use a cusomized <img />

If the problem only concern the images, we could use special renderer for <img /> tags in the docs, and let GitHub handle them by itself

Mark <img/> as special sections

--- a/packages/markdown/parseMarkdown.js
+++ b/packages/markdown/parseMarkdown.js
@@ -161,6 +161,7 @@ function getContents(markdown) {
     .replace(headerRegExp, '') // Remove header information
     .split(/^{{("(?:demo|component)":.*)}}$/gm) // Split markdown into an array, separating demos
     .flatMap((text) => text.split(/^(<codeblock.*?<\/codeblock>)$/gmsu))
+    .flatMap((text) => text.split(/^(<img.*?\/>)$/gms))
     .filter((content) => !emptyRegExp.test(content)); // Remove empty lines
   return rep;
 }
@@ -560,6 +561,11 @@ ${headers.hooks
             storageKey,
           };
         }
+        if (content.startsWith('<img')) {
+          return {
+            type: 'image',
+          };
+        }

         return render(content);
       });

Render them with React component instead of static HTML

--- a/docs/src/modules/components/MarkdownDocs.js
+++ b/docs/src/modules/components/MarkdownDocs.js
@@ -115,6 +115,13 @@ export default function MarkdownDocs(props) {
               </Wrapper>
             );
           }
+          if (renderedMarkdownOrDemo.type === 'image') {
+            return (
+              <Wrapper key={index} {...(isJoy && { mode: theme.palette.mode })}>
+                <DocsImage {...renderedMarkdownOrDemo.props} />
+              </Wrapper>
+            );
+          }

           const name = renderedMarkdownOrDemo.demo;
           const demo = demos?.[name];

One limitation is that images should be stored in a way that can be handled by both the docs and GitHub. So src should be a static url, not a url generated by nextJs or whatever JS magic

brijeshb42 commented 1 year ago

I vote for the 1st solution though it'll require more work.

alexfauquette commented 1 year ago

I vote for the 1st solution though it'll require more work.

Is there a specific reason? a special use-case you have in mind, an experience you had, or a fealing?

oliviertassinari commented 1 year ago

Option 1: sounds clean, but how is it worth the overhead vs. duplicating the content at this stage? Option 2: it won't work for other types of content, this is an image-only solution. Option 3: duplicate the content.