Skip to content

Commit

Permalink
fix(runtime): ContentRenderer extra props (#1300)
Browse files Browse the repository at this point in the history
  • Loading branch information
Atinux committed Jun 29, 2022
1 parent c31d95f commit 711eced
Show file tree
Hide file tree
Showing 20 changed files with 93 additions and 25 deletions.
4 changes: 2 additions & 2 deletions docs/content/4.api/1.components/2.content-renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: 'Takes your component from an AST to a wonderful template.'

The `<ContentRenderer>`{lang=html} component renders a document coming from a query.

It will use `<MarkdownRenderer>`{lang=html} component to render `.md` file types.
It will use `<ContentRendererMarkdown>`{lang=html} component to render `.md` file types.

Other types will currently be passed to default slot via `v-slot="{ data }"` or be rendered inside `<pre />` tag.

Expand Down Expand Up @@ -34,7 +34,7 @@ const { data } = await useAsyncData('page-data', () => queryContent('/hello').fi
<main>
<ContentRenderer :value="data">
<h1>{{ data.title }}</h1>
<MarkdownRenderer :value="data" />
<ContentRendererMarkdown :value="data" />
</ContentRenderer>
</main>
</template>
Expand Down
4 changes: 2 additions & 2 deletions playground/basic/content/1.real-content/content.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,15 @@ const { data } = await useAsyncData(`doc-${route.path}`, () => queryContent(rout
</template>
```

### `<MarkdownRenderer>`
### `<ContentRendererMarkdown>`

> This component is used by `<ContentRenderer>` under the hood.
Render a markdown content.

```vue
<template>
<MarkdownRenderer :value="data" />
<ContentRendererMarkdown :value="data" />
</template>
```

Expand Down
32 changes: 32 additions & 0 deletions playground/basic/content/2.features/6.variables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
---
title: Variables
cover: https://nuxtjs.org/design-kit/colored-logo.svg
---

:img{:src="cover"}

# {{ $doc.title }}

MDC stands for _**M**ark**D**own **C**omponents_.

This syntax supercharges regular Markdown to write documents interacting deeply with any Vue component from your \`components/content/\` directory or provided by a module.

## Next steps
- [Install Nuxt Content](/get-started)
- [Explore the MDC syntax](/guide/writing/mdc)


You are visiting document: {{ $doc._id }}

Current route is: {{ $route.path }}

::alert
---
type: success
---
This is an alert for {{ type }}
::

::alert{type="danger"}
This is an alert for {{ type }}
::
6 changes: 6 additions & 0 deletions playground/document-driven/components/content/Hello.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<template>
<div>
<h1>Hello</h1>
<slot />
</div>
</template>
5 changes: 5 additions & 0 deletions playground/document-driven/content/8.component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
component: Hello
---

Will use the `<Hello>` component as wrapper.
4 changes: 4 additions & 0 deletions playground/shared/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export default defineNuxtConfig({
{
global: true,
path: resolveThemeDir('./components')
},
{
global: true,
path: resolveThemeDir('./components/content')
}
],
modules: [contentModule, '@nuxthq/admin'],
Expand Down
1 change: 1 addition & 0 deletions src/runtime/components/ContentDoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import ContentQuery from './ContentQuery'
import { useRoute, useContentHead } from '#imports'

export default defineComponent({
name: 'ContentDoc',
props: {
/**
* Renderer props
Expand Down
1 change: 1 addition & 0 deletions src/runtime/components/ContentList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { QueryBuilderParams } from '../types'
import ContentQuery from './ContentQuery'

export default defineComponent({
name: 'ContentList',
props: {
/**
* Query props
Expand Down
1 change: 1 addition & 0 deletions src/runtime/components/ContentNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { QueryBuilder } from '../types'
import { useAsyncData, fetchContentNavigation } from '#imports'

export default defineComponent({
name: 'ContentNavigation',
props: {
/**
* A query to be passed to `fetchContentNavigation()`.
Expand Down
1 change: 1 addition & 0 deletions src/runtime/components/ContentQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ParsedContent, QueryBuilder, SortParams } from '../types'
import { computed, useAsyncData, queryContent } from '#imports'

export default defineComponent({
name: 'ContentQuery',
props: {
/**
* The path of the content to load from content source.
Expand Down
7 changes: 4 additions & 3 deletions src/runtime/components/ContentRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { defineComponent, watch, h, useSlots } from 'vue'
import MarkdownRenderer from './MarkdownRenderer'
import ContentRendererMarkdown from './ContentRendererMarkdown'

export default defineComponent({
name: 'ContentRenderer',
props: {
/**
* The document to render.
Expand Down Expand Up @@ -54,10 +55,10 @@ export default defineComponent({

const { value, excerpt, tag } = ctx

// Use built-in MarkdownRenderer
// Use built-in ContentRendererMarkdown
if (value && value?._type === 'markdown' && value?.body?.children?.length) {
return h(
MarkdownRenderer,
ContentRendererMarkdown,
{
value,
excerpt,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { h, resolveComponent, Text, defineComponent, toRefs } from 'vue'
import { h, resolveComponent, Text, defineComponent } from 'vue'
import destr from 'destr'
import { pascalCase } from 'scule'
import { find, html } from 'property-information'
Expand Down Expand Up @@ -46,27 +46,21 @@ export default defineComponent({
default: 'div'
}
},
setup (props) {
setup () {
const { content: { tags = {} } } = useRuntimeConfig().public

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { tag: _t, value: _d, ...contentProps } = toRefs(props)

return {
tags,
contentProps
}
return { tags }
},
render (ctx) {
const { tags, tag, value, contentProps } = ctx
const { tags, tag, value } = ctx

if (!value) {
return null
}

// Get body from value
let body = (value.body || value) as MarkdownNode
if (this.excerpt && value.excerpt) {
if (ctx.excerpt && value.excerpt) {
body = value.excerpt
}
const meta: ParsedContentMeta = {
Expand All @@ -92,7 +86,6 @@ export default defineComponent({
return h(
component as any,
{
...contentProps,
...meta.component?.props,
...this.$attrs
},
Expand Down Expand Up @@ -338,7 +331,7 @@ function getSlotName (node: MarkdownNode) {
* Create a factory function if there is a node in the list
*/
function createSlotFunction (nodes: Array<VNode | string>) {
return (nodes.length ? () => nodes : undefined)
return (nodes.length ? () => mergeTextNodes(nodes as VNode[]) : undefined)
}

/**
Expand All @@ -354,3 +347,19 @@ function isDefaultTemplate (node: MarkdownNode) {
function isTemplate (node: MarkdownNode) {
return node.tag === 'template'
}

/**
* Merge consequent Text nodes into single node
*/
function mergeTextNodes (nodes: Array<VNode>) {
const mergedNodes: Array<VNode> = []
for (const node of nodes) {
const previousNode = mergedNodes[mergedNodes.length - 1]
if (node.type === Text && previousNode?.type === Text) {
previousNode.children = (previousNode.children as string) + node.children
} else {
mergedNodes.push(node)
}
}
return mergedNodes
}
1 change: 1 addition & 0 deletions src/runtime/components/DocumentDrivenEmpty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { ParsedContent } from '../types'
* Used in `src/runtime/pages/document-driven.vue`
*/
export default defineComponent({
name: 'DocumentDrivenEmpty',
props: {
value: {
type: Object as PropType<ParsedContent>,
Expand Down
1 change: 1 addition & 0 deletions src/runtime/components/DocumentDrivenNotFound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { defineComponent, h } from 'vue'
* Used in `src/runtime/pages/document-driven.vue`
*/
export default defineComponent({
name: 'DocumentDrivenNotFound',
render () {
return h('div', 'Document not found')
}
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/markdown-parser/utils/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function isTag (vnode: VNode | MarkdownNode, tag: string | symbol): boole
if (vnode.type === tag) {
return true
}
// Vue 3 VNode `type` can be an object (tag is provided by MarkdownRenderer)
// Vue 3 VNode `type` can be an object (tag is provided by ContentRendererMarkdown)
if (typeof vnode.type === 'object' && (vnode.type as any).tag === tag) {
return true
}
Expand Down
1 change: 0 additions & 1 deletion src/runtime/pages/document-driven.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ useContentHead(page)
<DocumentDrivenEmpty :value="value" />
</template>
</ContentRenderer>

<DocumentDrivenNotFound v-else />
</div>
</template>
Expand Down
1 change: 1 addition & 0 deletions src/runtime/plugins/documentDriven.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export default defineNuxtPlugin((nuxt) => {
const promises: (() => Promise<any> | any)[] = []

/**
*
* `navigation`
*/
if (moduleOptions.navigation) {
Expand Down
2 changes: 1 addition & 1 deletion test/features/renderer-markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export const testMarkdownRenderer = () => {
test('bindings', async () => {
const rendered = await $fetch('/parse', {
params: {
content
content: encodeURIComponent(content)
}
})

Expand Down
5 changes: 5 additions & 0 deletions test/fixtures/basic/components/content/Alert.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
<Markdown />
</div>
</template>
4 changes: 2 additions & 2 deletions test/fixtures/basic/pages/parse.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<div>
<MarkdownRenderer :value="data" />
<ContentRendererMarkdown :value="data" />
</div>
</template>

Expand All @@ -12,7 +12,7 @@ const { data } = await useAsyncData(content, async () => {
cors: true,
body: {
id: 'content:index.md',
content
content: decodeURIComponent(content)
}
})
})
Expand Down

0 comments on commit 711eced

Please sign in to comment.