Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add new richtext #923

Merged
merged 10 commits into from
Nov 8, 2024
89 changes: 89 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,95 @@ Which is the short-hand equivalent to using `useStoryblokApi` inside `useState`

## Rendering Rich Text

You can render rich text fields by using the `StoryblokRichText` component:

```html
<template>
<StoryblokRichText :doc="blok.articleContent" />
</template>
```

Or you can have more control by using the `useStoryblokRichText` composable:

```html
<script setup>
const { render } = useStoryblokRichText({
// options like resolvers
})

const root = () => render(blok.articleContent);
</script>

<template>
<root />
</template>
```

For more incredible options you can pass to the `useStoryblokRichText`, please consult the [Full options](https://github.com/storyblok/richtext?tab=readme-ov-file#options) documentation.


#### Overriding the default resolvers

You can override the default resolvers by passing a `resolver` prop to the `StoryblokRichText` component, for example, to use vue-router links or add a custom codeblok component: :

```html
<script setup>
import { NuxtLink } from '#components';
import type { StoryblokRichTextNode } from '@storyblok/vue';
import CodeBlok from "./components/CodeBlok.vue";

const resolvers = {
// NuxtLink example:
[MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
h(NuxtLink, {
to: node.attrs?.href,
target: node.attrs?.target,
}, node.text),
// Custom code block component example:
[BlockTypes.CODE_BLOCK]: (node: Node) => {
return h(CodeBlock, {
class: node?.attrs?.class,
}, node.children)
},
}
</script>

<template>
<StoryblokRichText :doc="blok.articleContent" :resolvers="resolvers" />
</template>
```

If you want to use the `useStoryblokRichText` composable, you can pass the `resolvers` via the options object:

```html
<script setup>
import CodeBlok from "./components/CodeBlok.vue";

const { render } = useStoryblokRichText({
resolvers: {
// NuxtLink example:
[MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) =>
h(NuxtLink, {
to: node.attrs?.href,
target: node.attrs?.target,
}, node.text),
// Custom code block component example:
[BlockTypes.CODE_BLOCK]: (node: Node) =>
h(CodeBlock, {
class: node?.attrs?.class,
}, node.children)
}
});

const root = () => render(blok.articleContent);
</script>
```

### Legacy Rendering Rich Text

> [!WARNING]
> The legacy `richTextResolver` is soon to be deprecated. We recommend migrating to the new approach described above instead.

You can easily render rich text by using the `renderRichText` function that comes with `@storyblok/nuxt` and a Vue computed property:

```html
Expand Down
42 changes: 42 additions & 0 deletions playground/pages/richtext.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { NuxtLink } from '#build/components';
import { MarkTypes, type StoryblokRichTextNode } from '@storyblok/vue';

const story = await useAsyncStoryblok(
"vue/test-richtext",
{
version: "draft"
}
// { resolveRelations: "Article.categories" }
);

const resolvers = {
[MarkTypes.LINK]: (node: StoryblokRichTextNode<VNode>) => {
return node.attrs?.linktype === "STORY"
? h(
NuxtLink,
{
to: node.attrs?.href,
target: node.attrs?.target
},
node.text
)
: h(
"a",
{
href: node.attrs?.href,
target: node.attrs?.target
},
node.text
);
}
};
</script>

<template>
<StoryblokRichText
v-if="story.content.richText"
:doc="story.content.richText"
:resolvers="resolvers"
/>
</template>
11 changes: 11 additions & 0 deletions playground/storyblok/iframe-embed/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<script setup lang="ts">
defineProps({
blok: {
type: Object,
required: true
}
});
</script>
<template>
<iframe :src="blok.url.url" class="w-full aspect-video" frameborder="0" />
</template>
6 changes: 6 additions & 0 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ export default defineNuxtModule<ModuleOptions>({
'useStoryblokBridge',
'renderRichText',
'RichTextSchema',
'StoryblokRichText',
'useStoryblokRichText',
'MarkTypes',
'BlockTypes',
'LinkTypes',
'AssetTypes',
];
for (const name of names) {
addImports({ name, as: name, from: '@storyblok/vue' });
Expand Down
Loading