vuepress / vuepress-community

:bulb: Community supported ecosystem for VuePress
https://vuepress-community.netlify.app
MIT License
81 stars 62 forks source link

[Question] How can I get parsed markdown from vuepress-plugin-container? #20

Closed YunYouJun closed 4 years ago

YunYouJun commented 4 years ago

Environment

What's your question?

How can I get parsed markdown from vuepress-plugin-container? I cannot find it in docmention.

I want to implement a demo type container.

I just need input:

::: demo
<button class="demo">demo</button>
:::

Then I can get:

image

and display its code:

<button class="demo">demo</button>

But I cannot get the code in markdown.

By the way, I think this is a useful function. It can be added as a default feature like :::tip.

meteorlxy commented 4 years ago

What do you mean by "get parsed markdown"?

Do you want to get the literal code, rather than HTML rendered? So why not wrap it in markdown code block?

::: demo
```html
<button class="demo">demo</button>

:::

meteorlxy commented 4 years ago

Uh I guess I got your point. You want to get both "rendered HTML" and "literal code" in the mean time.

An interesting feature. I have no good idea for now.

Maybe there are two different ways for this:

🤔

meteorlxy commented 4 years ago

Currently we repeat the code for demo. You can check how vuepress official docs does:

https://github.com/vuejs/vuepress/blame/master/packages/docs/docs/guide/markdown.md#L90-L100

YunYouJun commented 4 years ago

Yeah! Thank you for your reply. I think it is a good feature for docs. Maybe this can be a [Feature request]?

meteorlxy commented 4 years ago

In fact I think it is out of scope of plugin-container. We can make it another plugin, or intergrate it into vuepress' default theme

YunYouJun commented 4 years ago

I find bootstrap and element both use similar features.

Bootstrap use hugo-plugin. button.md - bootstrap

And element write some configs about markdown-it. md-loader - element

meteorlxy commented 4 years ago

I see. ElementUI is using "markdown-it + vue" way as I mentioned above. See https://github.com/ElemeFE/element/blob/0706805226cc8ad90011a568c1a14bf0701abd37/examples/components/demo-block.vue

YunYouJun commented 4 years ago

Yeah, I also used this method to implement the container of demo. I think this way is more convenient for users to customize styles and layouts.

henrikruscon commented 4 years ago

I did the same but I have issues with the script part of demo code. For example if I got two components going through the demo, they seem to apply as a parent and overwrite each other. So the last demo I made is the only script that goes through.

Meaning I can't have multiple demo examples on the same page. Not sure why, can't see the difference between method and Elements method.

Anyone else have that issue?

henrikruscon commented 4 years ago

This part handles displaying the code to a PrismJS component I created in Vue. Works well. Now to handle the rendering of the demo-component tag.

markdown: {
        extendMarkdown: (markdown) => {
            markdown.renderer.rules.fence = (tokens, idx, options, env, self) => {
                const token = tokens[idx]
                const prevToken = tokens[idx - 1]
                const isInDemoComponent = prevToken && prevToken.nesting === 1 && prevToken.info.trim().match(/^demo\s*(.*)$/)

                if (token.info === 'html' && isInDemoComponent) {
                    return `<template slot="code">${markdown.utils.escapeHtml(token.content)}</template>`
                }
            }

            markdown.use(require('markdown-it-container'), 'demo', {
                    validate: (params) => {
                        return params.trim().match(/^demo\s*(.*)$/)
                    },

                    render: (tokens, idx) => {
                        const { nesting, info } = tokens[idx]
                        const nextToken = tokens[idx + 1]
                        const content = nextToken.type === 'fence' ? nextToken.content : ''

                        if (nesting === 1) {
                            return `
                                <DemoComponent>
                                    <!--demo-component: ${content} :demo-component-->
                            `
                        }

                        return '</DemoComponent>'
                }
            })
        }
    },

The previous method I used to render the components failed to handle script tags well. Like I mentioned previously, they kept replacing one an other if there was multiple ones.

Hoping this new approach based on ElementUI will solve it, will comment again if I find a good solution for that part.

YunYouJun commented 4 years ago

@henrikdahl Looks good! BTW, I found two plugins about demo code. vuepress-plugin-demo-code vuepress-plugin-demo-block

henrikruscon commented 4 years ago

@YunYouJun Thanks! Also thanks for sharing.

vuepress-plugin-demo-code has the same bug I mentioned above. Was using that one as a reference to begin with.

The other one doesn't use a Vue component as a base which is a requirement for me. I'm thinking it might share the same bug as well. Haven't tried that one.

I got it to render both the code and the demo part, however the script tag throws an error and hence the components don't work properly.

Expanded:

Screenshot 2020-03-05 at 16 03 12

Imploded:

Screenshot 2020-03-05 at 16 07 24

Any suggestions? How did you get script tags working properly? With two way binding (v-model) and such?

YunYouJun commented 4 years ago

In fact, I didn't find this problem until you mentioned it.

I think it may be caused by script-style-hoisting.

I tried it and no better method found.


Since they both need export default, I think maybe you can write them in .vuepress/componets. Then import them by import-code-snippets.

.vupress/components/test-demo1

<template>
  <input :disabled="disabled" />
</template>

<script>
export default {
  data() {
    return {
      disabled: true
    };
  }
};
</script>

.vupress/components/test-demo2

<template>
  <input :disabled="disabled" />
</template>

<script>
export default {
  data() {
    return {
      disabled: false
    };
  }
};
</script>

Docs markdown

<test-demo1/>

<<< @/docs/.vuepress/components/test-demo1.vue

<test-demo2/>

<<< @/docs/.vuepress/components/test-demo2.vue

It works. QQ20200306-002241@2x.png

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.