storyblok / storyblok-nuxt

Storyblok Nuxt module
https://www.storyblok.com/tp/nuxt-js-multilanguage-website-tutorial
273 stars 42 forks source link

Render Blok Components within RichText #476

Open joezimjs opened 1 year ago

joezimjs commented 1 year ago

Description

Right now, there's no built-in way to render Blok components within rich text. This is odd... why would you give us the ability to embed bloks inside our rich text and then completely ignore that inside your SDKs? Sure, there are several "solutions" thrown around, but they all have issues:

The Astro Storyblok SDK has implemented this directly. I'm honestly quite surprised this hasn't been done for a while now.

Suggested solution or improvement

Implement a RichText component that will render blok component where bloks are used. Also, it would be nice to allow the rich text resolver to return VNodes so we can render custom components there, but if the first thing is implemented, I'm not sure what use I'd have for this.

Additional context

No response

Validations

Dawntraoz commented 1 year ago

Hi, @joezimjs, you are completely right in your statement; thanks for sharing your concerns with us. Actually, the Astro implementation is our first try at introducing this in our SDKs (I see you fast there 😏). As Astro is kind of new as an SDK in our list, it is easy to test new initiatives (it is less used by our clients) to then introduce this in the rest of the SDKs, so sooner than later, this will be implemented to the Nuxt SDK too (@alexjoverm do you want to add anything here?).

For now, about the links you mention, the 3rd one you should ignore it since we are using Nuxt 3 here, and that article is for the old Nuxt 2. For the FAQ and the runtime template compiler, for now, this is a working approach. I know it is not the ideal case, but for now, it is the simplest way.

As we always say, this is a community effort, we are trying to provide the most features we can, but we don't have a dedicated team for the SDKs. We help when we have less workload, so please, if any day you want to do a pair programming session with me or one of my colleagues or open a PR with the features you need we will be so happy to see it happening!

joezimjs commented 1 year ago

I got something working in my own repository by creating a custom RichText component: https://github.com/joezimjs/nuxt-storyblok-poc/tree/main/components/rich-text Basically converted everything into Vue components rather than using functions that return HTML. And the RTText component (for text nodes) handles all the different mark types. I'm not sure how to integrate something like this into storyblok-nuxt, primary because I'm not sure which of the auto-import features are available inside a plugin.

joezimjs commented 1 year ago

Hmm... now that I'm thinking about it, there may be a better way that relies on the marks/nodes functionality that is defined for renderRichText from @storyblok/js, which would allow this to automatically stay up-to-date if new node/mark types are added.

Also, I looked more closely at @storyblok/astro's implementation and it's not adequate to take care of bloks that are embedded inside other nodes (e.g. inside a bullet point item) because it only looks for bloks in the first level of content items, then renders the rest with the provided renderRichText from @storyblok/js. So, I guess I can't get on your butts for taking this long to implement it if none of the other teams have implemented it quite right yet either. :)

joezimjs commented 1 year ago

There! I changed it so it's all packed in one component and it takes advantage of the provided RichTextSchema and even allows a user to pass in a different schema. https://github.com/joezimjs/nuxt-storyblok-poc/blob/main/components/RichText.ts

It's missing just a few things:

Youhan commented 6 months ago

@joezimjs Thank you for your efforts on this. Here is how I added <NuxtLink and <NuxtImg components to your solution at https://github.com/joezimjs/nuxt-storyblok-poc/blob/main/components/RichText.ts. Hope it helps a bit.

Just like we check the node.type for blok we can also check for node.type === 'image'

import { NuxtImg, NuxtLink } from '#components'

// use NuxtImg for images
if (node.type === 'image') {
    return h(NuxtImg, {
        provider: 'storyblok',
        format: 'webp',
        quality: 75,
        src: node.attrs.src,
        alt: node.attrs.alt,
        title: node.attrs.title,
        loading: 'lazy',
        width: 700,
        sizes: '90vw md:570px lg:700px',
    })
}

and since link is a mark on the RenderTag function we can add a check for a tags:

if (tagItem.tag === 'a')
    return h(NuxtLink, { ...tagItem.attrs }, () => [innerNode])
return h(tagItem.tag, tagItem.attrs, innerNode ? [innerNode] : undefined)
PP-Tom commented 5 months ago

I've done a very simple fix for this:

<script setup lang="ts">
type Props = { text: any };
defineProps<Props>();

const renderText = (text: any) => {
    const markup = { type: 'doc', content: [text] };
    return renderRichText(markup);
};
</script>

<template>
    <template v-if="text?.content" v-for="element in text?.content">
        <template v-if="element.type === 'blok'" v-for="blok in element?.attrs?.body" :key="blok.id">
            <component :is="blok.component" :blok />
        </template>
        <div v-else v-html="renderText(element)"></div>
    </template>
</template>

I haven't thoroughly texted it yet but seems to be working.

joezimjs commented 5 months ago

@PP-Tom Looks pretty good but I don't think this will catch bloks that are embedded in a lower level of structure. For example, if you put a blok into a bullet point, the bulleted list will hit the renderRichText call and the blok inside it will never be seen by this component. It's the same problem as the first example I linked in my original post.

To be fair, I was complaining that Astro had this implemented already while Nuxt still hadn't, but Astro implemented it in a very similar way to this, so it's like I'm the only person who cares about low-level embedded bloks... and I'm not even sure how much I care because I don't know if I have any use cases for it, but I see it as a blind spot for everyone who tries to implement this.

PP-Tom commented 5 months ago

@PP-Tom Looks pretty good but I don't think this will catch bloks that are embedded in a lower level of structure. For example, if you put a blok into a bullet point, the bulleted list will hit the renderRichText call and the blok inside it will never be seen by this component. It's the same problem as the first example I linked in my original post.

Good point. I'm really surprised that StoryBlok's UI is built in Vue but it's been almost a year for a 1st party solution for this. I know it's a DX thing, but just surprised.

joezimjs commented 5 months ago

Good point. I'm really surprised that StoryBlok's UI is built in Vue but it's been almost a year for a 1st party solution for this. I know it's a DX thing, but just surprised.

Right?!?

alvarosabu commented 5 months ago

Hi @joezimjs @PP-Tom @Youhan jumping here to give some good news on Richtext topic.

I'm currently working on a framework agnostic solution for the Richtext Renderer that is potentially extendable to each major framework (vue, react etc). Between all the features the use-case for rendering Blok components is covered and was successfully tested on the PoC. And yes, it includes as well overwriting resolves like adding the NuxtLink 😉

The community has been very patient about this topic so I want to be transparent that there IS a work-in-progress solution for this, we just need to wait a little bit more so it's rolled out since we are discussing internally the DX.

Hope this brings a little bit of light to this topic, will keep you posted.

joezimjs commented 5 months ago

Love to hear it!

narr07 commented 3 months ago

Hai melompat ke sini untuk memberikan kabar baik tentang topik.Richtext

Saat ini saya sedang mengerjakan solusi agnostik kerangka kerja untuk Richtext Renderer yang berpotensi dapat diperluas ke setiap kerangka kerja utama (vue, react, dll). Di antara semua fitur, kasus penggunaan untuk merender komponen Blok tercakup dan berhasil diuji pada PoC. Dan ya, itu termasuk juga menimpa resolusi seperti menambahkan 😉NuxtLink

Komunitas telah sangat sabar tentang topik ini jadi saya ingin transparan bahwa ada solusi yang sedang dalam proses untuk ini, kita hanya perlu menunggu sedikit lagi sehingga diluncurkan karena kita sedang mendiskusikan DX secara internal.

Semoga ini membawa sedikit cahaya ke topik ini, akan membuat Anda tetap diposting.

So glad to hear that 😇