vuejs / vitepress

Vite & Vue powered static site generator.
https://vitepress.dev
MIT License
11.47k stars 1.86k forks source link

Support code groups and allow adding title to code blocks #728

Closed jd-solanki closed 1 year ago

jd-solanki commented 1 year ago

Is your feature request related to a problem? Please describe.

VueJS community is moving from JS to TS now. Hence, we have to provide both TS & JS code.

I already started using VitePress alpha in my OSS project but for another project, I prefer providing TS & JS code via code groups like VuePress.

Describe the solution you'd like

Provide code blocks via markdown (using component is bit ugly for markdown only content). We can inspire from Nuxt content 2 for new syntax

:::code group

:::group{ts}

```ts
const a: number = 1
```

:::

:::group{js}

```js
const a = 1
```

:::

:::

Describe alternatives you've considered

None

Additional context

https://content.nuxtjs.org/guide/writing/mdc

Validations

kecrily commented 1 year ago

Maybe it could be simpler?

:::code group
```ts
const a: number = 1
```

```js
const a = 1
```
:::
brc-dd commented 1 year ago

@kecrily I guess the OP meant to have title of each group too. :::group{foo} --> title is foo.

kecrily commented 1 year ago

We can custom group title in code block

```ts [TypeScript]
const a: number = 1
```

Minimizing layers (especially this kind without indentation) is useful to keep the plain text readability of markdown.

Zhengqbbb commented 1 year ago

Looking forward this feature, which will have a different experience with such code experience: image

marshallswain commented 1 year ago

Can we expose the markdown-it rendered to be used inside of Tab components? It would be really nice to be able to use Vue components to render tab groups:

<Tabs>
  <Tab name="TypeScript">
    ``ts
    nested fenced code block here.
    ``
  </Tab>
  <Tab name="JavaScript">
  ``js
    nested fenced code block here.
  ``
  </Tab>
</Tabs>

The goal would be to use the same renderer in a clean way in order to more-easily reuse the same markdown styles.

brc-dd commented 1 year ago

@marshallswain Sorry, I didn't get you. You can still do what you've wrote. You need to add spaces before and after the fences in this. HTML (or Vue in this case) should be separated from Markdown by empty lines.

marshallswain commented 1 year ago

@brc-dd wow! I can't believe it was that simple. I just needed the extra line breaks and it now works as expected. Thank you!

kecrily commented 1 year ago

Off-topic: this behavior is consistent with that on GitHub. On GitHub you can also embed markdown in html with line breaks.

brc-dd commented 1 year ago

@kecrily This is part of the CommonMark standard actually (https://spec.commonmark.org/0.29/#html-blocks). Anything that follows or is based on that will properly render that.

alokVishu commented 1 year ago

I am also building js + ts docs. Code groups will be a great addition to show ts and js code.

Sepush commented 1 year ago

I prefer nuxt's solution like the following

UI: https://v3.nuxtjs.org/guide/directory-structure/layouts#overriding-a-layout-on-a-per-page-basis 图片

Grammar: https://github.com/nuxt/framework/blob/d135608ef0d607259c0ae6f5156c8f46ff78ddc3/docs/content/2.guide/3.directory-structure/7.layouts.md?plain=1#L140-L175

brc-dd commented 1 year ago

Also track #1027 here. I think we should go with what @kecrily wrote. Its similar to what we have in Nuxt too.

VoVAllen commented 1 year ago

Hi, I'm interested in taking this, and have some questions on the implementation. Currently code block's function (line number, highlight, etc.) is based on plugin with mdit and pure DOM operation, which is perfect for the static component. But code group (such as in nuxt doc) is a dynamic component, which seems better to have a SFC for it. What do you think? @brc-dd

My current thought is to use a simple component wrap over the doc blocks by slot. And use pure dom operation to control the tab change inside. Any suggestion is welcomed since I'm a newbie to vue. Thanks!

Nuxt reference: https://github.com/nuxt/content/blob/v1/packages/theme-docs/src/components/global/base/CodeGroup.vue

brc-dd commented 1 year ago

@VoVAllen I don't think highlighting and all needs to be done in the code group component. I was thinking of just having a wrapper component (with some md sugar) that can take multiple code blocks (with titles). Regarding tab change, it can be done using basic refs, there is no need to directly manipulate DOM.

VoVAllen commented 1 year ago

@brc-dd Yeah actually this what I thought. I don't want to change the way of highlighting by mdit plugin. My question is whether we need a component(SFC) here or there's a simpler way than SFC.

Current code blocks are <code></code>. My thought for code group is like

<CodeGroup> // This logic is handles by a new SFC

// This is still handled by mdit
<code>
<code/>

<code>
<code/>

</CodeGroup>

which is similar to the container logic but the outside wrapper is a SFC.

What do you think?

brc-dd commented 1 year ago

@VoVAllen Yeah, that's similar to what others wrote. This is the intended syntax BTW:

:::code-group

```js [JavaScript]
some js stuff
some ts stuff

:::



So, if you implement such a component (the one you wrote), then we just need to add some stuff in our markdown component plugin to make it understand `:::code-group` and ` ```ts [TypeScript]`.
brc-dd commented 1 year ago

Can you guys review #1560 and see if there are any issues (especially with UI)? Here is the deploy preview: https://deploy-preview-1560--vitepress-docs.netlify.app/test

jd-solanki commented 1 year ago

Hi @brc-dd

I am really glad that this is implemented.

UI looks a bit different than what VitePress already provides due to the following:

In my opinion, VuePress already has an excellent UI, why not reuse it? 🤔

P.S. Sorry I commented here, I should have commented in PR